简体   繁体   English

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

[英]How can I buffer my Java input/output/file streams properly?

I'm writing an application that needs to send a file over the network. 我正在编写一个需要通过网络发送文件的应用程序。 I've only been taught how to use standard java.net and java.io classes so far (in my first year of college) so I have no experience with java.nio and netty and all those nice things. 到目前为止(在我大学的第一年),我仅被教过如何使用标准的java.net和java.io类,因此我对java.nio和netty以及所有这些不错的东西没有任何经验。 I've got a working server/client set up using Socket and ServerSocket classes along with BufferedInput/OutputStreams and BufferedFile streams, as follows: 我已经使用Socket和ServerSocket类以及BufferedInput / OutputStreams和BufferedFile流设置了工作的服务器/客户端,如下所示:

The server: 服务器:

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

And the client: 和客户:

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

At first I was using no buffering, and writing each int from in.read(). 最初,我没有使用缓冲,而是从in.read()中写入每个int。 That got me about 200kb/s transfer according to my network monitor gadget on windows 7. I then changed it as above but used 4096 byte buffers and got the same speed, but the file received was usually a couple kilobytes bigger than the source file, and that is what my problem is. 根据Windows 7上的网络监控器小工具,这使我获得了大约200kb / s的传输速度。然后我如上所述进行了更改,但是使用了4096字节的缓冲区,并获得了相同的速度,但是接收到的文件通常比源文件大几千字节,这就是我的问题。 I changed the buffer size to 8192 and I now get about 3.7-4.5mb/sec transfer over wireless to my laptop, which is plenty fast enough for now, but I still have the problem of the file getting slightly bigger (which would cause it to fail an md5/sha hash test) when it is received. 我将缓冲区大小更改为8192,现在通过无线传输到笔记本电脑的速度约为3.7-4.5mb / sec,这已经足够快了,但是我仍然遇到文件变大的问题(这将导致文件变大)使它无法通过md5 / sha哈希测试)。

So my question is what is the proper way of buffering to get decent speeds and end up with exactly the same file on the other side? 所以我的问题是,适当的缓冲方法是什么以获得适当的速度并最终获得另一端完全相同的文件? Getting it to go a bit faster would be nice too but I'm happy with the speed for now. 使它运行得更快也很好,但是我对目前的速度感到满意。 I'm assuming a bigger buffer is better up to a point, I just need to find what that point is. 我假设较大的缓冲区在某种程度上会更好,我只需要找到该点即可。

You are ignoring the size of data actually read. 您将忽略实际读取的数据大小。

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

will always write 8192 bytes even if only one byte is read. 即使只读取一个字节,也将始终写入8192字节。 Instead I suggest using 相反,我建议使用

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

Your buffers are the same size as your byte[] so they are not really doing anything at the moment. 缓冲区的大小与byte []的大小相同,因此目前它们实际上并没有做任何事情。

The MTU for most networks is around 1500 bytes and you get a performance improvement on slower networks (up to 1 GB) up to 2 KB. 大多数网络的MTU约为1500字节,在速度较慢的网络(最大1 GB)和最大2 KB上,您可以获得性能上的提高。 8 KB as fine as well. 以及8 KB。 Larger than that is unlikely to help. 大于此值不太可能会有所帮助。

如果您确实想使其“如此完美”,则应查看try-catch-with-resources语句java.nio包 (或任何nio派生的库)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM