如何正确缓冲Java输入/输出/文件流?

时间:2012-09-03 12:04:27

标签: java file-io stream buffering

我正在编写需要通过网络发送文件的应用程序。到目前为止,我只教过如何使用标准的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哈希测试失败。

所以我的问题是,为了获得合适的速度而使用正确相同的文件来缓冲的正确方法是什么?让它快一点也会很好但是我对现在的速度感到满意。我假设一个更大的缓冲区更好到一点,我只需要找到那个点。

2 个答案:

答案 0 :(得分:5)

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

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也很好。比这更大的东西不太可能有所帮助。

答案 1 :(得分:0)

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