【问题标题】:How can I buffer my Java input/output/file streams properly?如何正确缓冲我的 Java 输入/输出/文件流?
【发布时间】:2012-09-03 12:04:26
【问题描述】:

我正在编写一个需要通过网络发送文件的应用程序。到目前为止(在我大学的第一年)我只被教过如何使用标准的 java.net 和 java.io 类,所以我没有使用 java.nio 和 netty 以及所有这些好东西的经验。我已经使用 Socket 和 ServerSocket 类以及 BufferedInput/OutputStreams 和 BufferedFile 流设置了一个工作服务器/客户端,如下所示:

服务器:

    public class FiletestServer {

    static ServerSocket server;
    static BufferedInputStream in;
    static BufferedOutputStream out;

    public static void main(String[] args) throws Exception {
    server = new ServerSocket(12354);
    System.out.println("Waiting for client...");
    Socket s = server.accept();
    in = new BufferedInputStream(s.getInputStream(), 8192);
    out = new BufferedOutputStream(s.getOutputStream(), 8192);
    File f = new File("test.avi");
    BufferedInputStream fin = new BufferedInputStream(new FileInputStream(f), 8192);

    System.out.println("Sending to client...");
    byte[] b = new byte[8192];
    while (fin.read(b) != -1) {
        out.write(b);
    }
    fin.close();
    out.close();
    in.close();
    s.close();
    server.close();
    System.out.println("done!");
    }
}

还有客户:

public class FiletestClient {

    public static void main(String[] args) throws Exception {
    System.out.println("Connecting to server...");
    Socket s;
    if (args.length < 1) {
        s = new Socket("", 12354);
    } else {
        s = new Socket(args[0], 12354);
    }
    System.out.println("Connected.");
    BufferedInputStream in = new BufferedInputStream(s.getInputStream(), 8192);
    BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream(), 8192);
    File f = new File("test.avi");
    System.out.println("Receiving...");
    FileOutputStream fout = new FileOutputStream(f);
    byte[] b = new byte[8192];
    while (in.read(b) != -1) {
        fout.write(b);
    }
    fout.close();
    in.close();
    out.close();
    s.close();
    System.out.println("Done!");
    }
}

起初我没有使用缓冲,而是从 in.read() 写入每个 int。根据我在 Windows 7 上的网络监视器小工具,这让我的传输速度大约为 200kb/s。然后我按照上面的方法进行了更改,但使用了 4096 字节的缓冲区并获得了相同的速度,但接收到的文件通常比源文件大几千字节,这就是我的问题所在。我将缓冲区大小更改为 8192,现在我通过无线传输到我的笔记本电脑的速度约为 3.7-4.5mb/秒,这对于现在来说已经足够快了,但我仍然遇到文件变大的问题(这会导致接收到 md5/sha 哈希测试失败)。

所以我的问题是,什么是正确的缓冲方法才能获得不错的速度并最终在另一端得到完全相同的文件?让它走得更快一点也会很好,但我对现在的速度很满意。我假设在某一点上更大的缓冲区更好,我只需要找到那个点是什么。

【问题讨论】:

    标签: java file-io stream buffering


    【解决方案1】:

    您忽略了实际读取的数据大小。

    while (in.read(b) != -1) {
        fout.write(b);
    }
    

    即使只读取一个字节,也将始终写入 8192 个字节。相反,我建议使用

    for(int len; ((len = in.read(b)) > 0;)
       fout.write(b, 0, len);
    

    您的缓冲区与您的 byte[] 大小相同,因此它们目前并没有真正做任何事情。

    大多数网络的 MTU 约为 1500 字节,而在速度较慢的网络(最大 1 GB)上,您可以获得高达 2 KB 的性能提升。 8 KB 也可以。大于这个值不太可能有帮助。

    【讨论】:

    • @martijno 我需要放慢速度的标志。 ;)
    • 我理解忽略导致问题的数据大小部分,但我不理解 for 循环。看起来它以某种方式提前读取,并且只将数据从缓冲区写入到实际内容结束的位置——对吗?编辑:你有一个太多的括号,“((len = ...”应该是“(len = ...”)
    • @biltong 它存储在len 中读取了多少,只写入了多少。
    • 这行得通,我的文件在另一边通过了 md5 测试,并且我的笔记本电脑超过了千兆位,我得到了 ~30mb/sec。杰出的!非常感谢!
    【解决方案2】:

    如果你真的想让它“如此完美”,你应该看看 the try-catch-with-resources statementthe java.nio package(或任何 nio 派生库)。

    【讨论】:

      猜你喜欢
      • 2013-02-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      • 2012-05-16
      • 2014-09-14
      • 1970-01-01
      相关资源
      最近更新 更多