Android有效地从输入流中读取

Ren*_*ndy 147 java android input stream bufferedreader

我正在为我正在制作的Android应用程序的网站发出HTTP get请求.

我正在使用DefaultHttpClient并使用HttpGet发出请求.我得到实体响应,从中获取一个InputStream对象来获取页面的html.

然后我循环完成回复,如下所示:

BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
String x = "";
x = r.readLine();
String total = "";

while(x!= null){
total += x;
x = r.readLine();
}
Run Code Online (Sandbox Code Playgroud)

然而,这非常缓慢.

这效率低吗?我没有加载一个大的网页 - www.cokezone.co.uk所以文件大小不大.有一个更好的方法吗?

谢谢

安迪

Jai*_*ano 344

代码中的问题是它创建了大量繁重的String对象,复制其内容并对其执行操作.相反,您应该StringBuilder避免String在每个追加上创建新对象,并避免复制char数组.您的案例的实现将是这样的:

BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder total = new StringBuilder();
for (String line; (line = r.readLine()) != null; ) {
    total.append(line).append('\n');
}
Run Code Online (Sandbox Code Playgroud)

您现在可以使用total而无需将其转换为String,但如果您需要将结果作为a String,则只需添加:

字符串结果= total.toString();

我会试着更好地解释一下......

  • a += b(或a = a + b),在哪里ab是字符串,复制两者 的内容a b一个新的对象(请注意,您也在复制a,其中包含累积的 String),并且您在每次迭代时都要复制这些副本.
  • a.append(b),其中a是a StringBuilder,直接将b内容附加到a,因此您不会在每次迭代时复制累积的字符串.

  • 令人惊讶的是,Android没有内置的流到字符串转换.让网络上的每个代码片段和地球上的应用程序重新实现`readline`循环是荒谬的.这种模式应该在70年代与豌豆绿一起消失. (47认同)
  • 对于奖励积分,提供初始容量以避免在StringBuilder填满时重新分配:`StringBuilder total = new StringBuilder(inputStream.available());` (23认同)
  • 这不会删除换行符吗? (10认同)
  • 不要忘记在try/catch中包装while:try {while((line = r.readLine())!= null){total.append(line); catch(IOException e){Log.i(tag,"inputStreamToString function中readline的问题"); } (5认同)
  • @botbot:记录并忽略异常并不比忽略异常好多了...... (4认同)
  • @dokkaebi我引自[`InputStream.available()`](https://developer.android.com/reference/java/io/InputStream.html#available()):注意,虽然InputStream的一些实现将返回流中的总字节数,很多都不会.使用此方法的返回值来分配用于保存此流中所有数据的缓冲区绝对不正确. (3认同)
  • 我不认为readLine有效,取决于数据,这可能导致OutOfMemory异常 (2认同)

Mak*_*san 33

您是否尝试过内置方法将流转换为字符串?它是Apache Commons库(org.apache.commons.io.IOUtils)的一部分.

然后你的代码就是这一行:

String total = IOUtils.toString(inputStream);
Run Code Online (Sandbox Code Playgroud)

它的文档可以在这里找到:http: //commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toString%28java.io.InputStream%29

可以从这里下载Apache Commons IO库:http: //commons.apache.org/io/download_io.cgi

  • android API不包含IOUtils (60认同)
  • 如果你必须下载它,我不会称之为"内置"; 尽管如此,我只是下载了它,并且会试一试. (3认同)
  • 是的,这就是我提到拥有它的外部库的原因.我将库添加到我的Android项目中,它使得从流中读取变得容易. (2认同)

And*_*rey 15

番石榴的另一种可能性:

依赖性: compile 'com.google.guava:guava:11.0.2'

import com.google.common.io.ByteStreams;
...

String total = new String(ByteStreams.toByteArray(inputStream ));
Run Code Online (Sandbox Code Playgroud)


小智 8

我相信这很有效......要从InputStream获取String,我会调用以下方法:

public static String getStringFromInputStream(InputStream stream) throws IOException
{
    int n = 0;
    char[] buffer = new char[1024 * 4];
    InputStreamReader reader = new InputStreamReader(stream, "UTF8");
    StringWriter writer = new StringWriter();
    while (-1 != (n = reader.read(buffer))) writer.write(buffer, 0, n);
    return writer.toString();
}
Run Code Online (Sandbox Code Playgroud)

我总是使用UTF-8.当然,除了InputStream之外,您还可以将charset设置为参数.


Adr*_*ian 6

那这个呢.似乎可以提供更好的性能.

byte[] bytes = new byte[1000];

StringBuilder x = new StringBuilder();

int numRead = 0;
while ((numRead = is.read(bytes)) >= 0) {
    x.append(new String(bytes, 0, numRead));
}
Run Code Online (Sandbox Code Playgroud)

编辑:实际上这种情况包括钢铁和莫里斯佩里的

  • 您可能最终得到一个Unicode实体,该实体被切割成两个后续读取.最好阅读直到某种边界字符,比如\n,这正是BufferedReader所做的. (4认同)