Android从inputstream高效地读取

我正在向我的一个android应用程序的网站做HTTP请求。

我正在使用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(); } 

然而这是非常缓慢的。

这是低效的吗? 我没有加载一个大的网页 – www.cokezone.co.uk所以文件大小不大。 有没有更好的方法来做到这一点?

谢谢

安迪

代码中的问题在于,它会创build大量繁重的String对象,复制它们的内容并对它们执行操作。 相反,你应该使用StringBuilder来避免在每个append上创build新的String对象,并避免复制char数组。 你的情况的实现将是这样的:

 BufferedReader r = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder total = new StringBuilder(); String line; while ((line = r.readLine()) != null) { total.append(line).append('\n'); } 

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

String result = total.toString();

我会尽力解释它…

  • a += b (或a = a + b ),其中ab是string,将a b的内容复制到一个新的对象中(注意你也复制a包含累积 String ),而你在每次迭代中都要做这些副本。
  • a.append(b) ,其中a是一个StringBuilder ,将b内容直接附加到a ,所以在每次迭代时不要复制累加的string。

你有没有尝试内置的方法来将一个stream转换为string? 它是Apache Commons库(org.apache.commons.io.IOUtils)的一部分。

那么你的代码将是这一行:

 String total = IOUtils.toString(inputStream); 

它的文档可以在这里find: 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

番石榴的另一种可能性:

依赖关系: compile 'com.google.guava:guava:11.0.2'

 import com.google.common.io.ByteStreams; ... String total = new String(ByteStreams.toByteArray(inputStream )); 

那这个呢。 似乎给予更好的performance。

 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)); } 

编辑:其实这种包括钢铁和莫里斯·佩里的

我相信这是足够高效的…要从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(); } 

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

可能比Jaime Soriano的回答稍微快一点,也没有Adrian的答案的多字节编码问题,我build议:

 File file = new File("/tmp/myfile"); try { FileInputStream stream = new FileInputStream(file); int count; byte[] buffer = new byte[1024]; ByteArrayOutputStream byteStream = new ByteArrayOutputStream(stream.available()); while (true) { count = stream.read(buffer); if (count <= 0) break; byteStream.write(buffer, 0, count); } String string = byteStream.toString(); System.out.format("%d bytes: \"%s\"%n", string.length(), string); } catch (IOException e) { e.printStackTrace(); } 

也许宁可读“一次一行”并joinstring,尝试“读取所有可用的”,以避免扫描结束行,并避免string连接。

即InputStream.available()和InputStream.read(byte [] b,int offset,int length)

一次读取一行文本,并将所述行分别附加到一个string中,这对于提取每一行以及这么多方法调用的开销都是非常耗时的。

我能够通过分配一个相当大的字节数组来保存stream数据,并在需要时迭代地用一个更大的数组replace,并尝试读取与数组一样多的数据。

出于某种原因,当代码使用HTTPUrlConnection返回的InputStream时,Android一再无法下载整个文件,所以我不得不求助于使用BufferedReader和手动超时机制,以确保我得到整个文件或取消转移。

 private static final int kBufferExpansionSize = 32 * 1024; private static final int kBufferInitialSize = kBufferExpansionSize; private static final int kMillisecondsFactor = 1000; private static final int kNetworkActionPeriod = 12 * kMillisecondsFactor; private String loadContentsOfReader(Reader aReader) { BufferedReader br = null; char[] array = new char[kBufferInitialSize]; int bytesRead; int totalLength = 0; String resourceContent = ""; long stopTime; long nowTime; try { br = new BufferedReader(aReader); nowTime = System.nanoTime(); stopTime = nowTime + ((long)kNetworkActionPeriod * kMillisecondsFactor * kMillisecondsFactor); while(((bytesRead = br.read(array, totalLength, array.length - totalLength)) != -1) && (nowTime < stopTime)) { totalLength += bytesRead; if(totalLength == array.length) array = Arrays.copyOf(array, array.length + kBufferExpansionSize); nowTime = System.nanoTime(); } if(bytesRead == -1) resourceContent = new String(array, 0, totalLength); } catch(Exception e) { e.printStackTrace(); } try { if(br != null) br.close(); } catch(IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 

编辑:事实certificate,如果你不需要有内容重新编码(即,你想要的内容是原样 ),你不应该使用任何的读者子类。 只要使用适当的Stream子类即可。

将上述方法的开始replace为以下方法的相应行,以加快其速度2至3倍

 String loadContentsFromStream(Stream aStream) { BufferedInputStream br = null; byte[] array; int bytesRead; int totalLength = 0; String resourceContent; long stopTime; long nowTime; resourceContent = ""; try { br = new BufferedInputStream(aStream); array = new byte[kBufferInitialSize]; 

如果文件很长,可以通过附加到StringBuilder来优化代码,而不是使用每行的string连接。

  byte[] buffer = new byte[1024]; // buffer store for the stream int bytes; // bytes returned from read() // Keep listening to the InputStream until an exception occurs while (true) { try { // Read from the InputStream bytes = mmInStream.read(buffer); String TOKEN_ = new String(buffer, "UTF-8"); String xx = TOKEN_.substring(0, bytes); 

为了将InputStream转换为String,我们使用BufferedReader.readLine()方法。 我们迭代,直到BufferedReader返回null,这意味着没有更多的数据要读取。 每一行都会附加到一个StringBuilder中,并以String的forms返回。

  public static String convertStreamToString(InputStream is) { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return sb.toString(); } }` 

最后从任何你想转换的类中调用该函数

 String dataString = Utils.convertStreamToString(in); 

完成

我用来阅读完整的数据:

 // inputStream is one instance InputStream byte[] data = new byte[inputStream.available()]; inputStream.read(data); String dataString = new String(data);