从InputStream中读取最快的方法是什么?

3

我正在尝试从HttpURLConnection的输入流中读取:

InputStream input = conn.getInputStream();
InputStreamReader isr = new InputStreamReader((input));
BufferedReader br = new BufferedReader(isr);

StringBuilder out = new StringBuilder("");
String output;
while ((output = br.readLine()) != null) {
    out.append(output);
}

当输入流包含大量数据时,这确实需要很长时间。有没有可能进行优化呢?


10
你认为瓶颈在你的代码中,而不是数据通过网络传输所需的时间吗? - Jon Skeet
你可以尝试使用更大/更小的缓冲区大小来测试你的 BufferedReader。否则,你会受到网络的限制。 - Sotirios Delimanolis
将其存储在 StringBuilder 中是可以的,但您应该根据您的预期提供初始分配。否则,当大小超过每个 2 的幂时,扩展/复制就会发生。 - laune
1
@laune:我认为它不太可能比网络慢... - Jon Skeet
1
@biziclop,我确实见过双重/复制会减慢事情进程的情况。这只是一个检查的问题-因此只是一个评论,而不是答案;-) - laune
显示剩余9条评论
3个回答

3
也许这会更快,因为Java 8中的新Stream API内部使用并行机制:
package testing;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.stream.Stream;

public class StreamTest {

  /**
   * @param args the command line arguments
   * @throws java.io.IOException
   */
  public static void main(String[] args) throws IOException {
    URL url = new URL("http://www.google.com");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setUseCaches(false);
    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
      BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

      Stream<String> s = br.lines();
      s.parallel().forEach(System.out::println);      
    }
  }

}

那么您可能已经完成了最快的实现。也许并发读取将是一种替代方案:https://dev59.com/u3HYa4cB1Zd3GeqPJkUe,如果您决定切换到Java 8,则可能会有所帮助:https://dev59.com/ZXI-5IYBdhLWcg3w8NSB - aw-think
谢谢你的建议。在我的代码中,bufferedReader.readLine() 是占用最多执行时间的部分。 - yo_haha
实际上并不更快。对于20kb的字符串,仍然需要大约10秒的时间。 - Slim_user71169

0
在Java的InputStream中,我们有一个名为read(byte b[], off, len)的方法,它将从输入流中读取数据到给定的字节数组中。 这里off是数组的起始索引,len是要读取的最大字节数,b[]是字节数组。 read方法将尝试读取最多len个字节,但是由于某些原因可能无法读取所需的字节数,因此该方法返回实际读取的字节数。 以下是示例:
FileInputStream i=new FileInputStream("file path");
FIleOutputStream o=new FileOutputStream("file path");
byte a[]=new byte[1024];
for(int j;(j=i.read(a,0,1024))!=-1;){
    o.write(a,0,j);
}                             

0

这段代码速度非常快。如果输入足够快,您可以每秒读取数百万行代码。您的时间可能根本不是用来读取输入流的,而是要么阻塞等待输入,要么附加到 StringBuilder 中。

但您根本不应该这样做。大多数文件可以逐行或逐个记录进行处理。编译器按令牌一次处理它们,除了编译之外,几乎没有更复杂的文件处理任务。这是可能的。


1
如果你说“时间...花费在向 StringBuilder 添加内容上”:难道你不是在反驳你的声明“这段代码没有任何缓慢之处”吗? - laune
我进行了一些测量:等待输入需要12-13秒,而读取流和构建StringBuilder需要40-55秒。 - yo_haha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接