文件复制不完整 Java NIO

Incomplete File Copy Java NIO

我在读取文件时遇到问题。我对 NIO 也很陌生。我要发送到服务器的文件实际大小差不多900MB,只收到了3MB

服务端读取代码:

private void read(SelectionKey key) throws IOException{
    SocketChannel socket = (SocketChannel)key.channel();
    RandomAccessFile aFile = null;
    ByteBuffer buffer = ByteBuffer.allocate(300000000);
    try{
        aFile = new RandomAccessFile("D:/test2/test.rar","rw");

        FileChannel inChannel = aFile.getChannel();

        while(socket.read(buffer) > 0){
            buffer.flip();
            inChannel.write(buffer);
            buffer.compact();
        }
        System.out.println("End of file reached..");
    }catch(Exception e){
        e.printStackTrace();
    }
}

这是我的客户端write方法的代码:

private void write(SelectionKey key) throws IOException {
    SocketChannel socket = (SocketChannel) key.channel();
    RandomAccessFile aFile = null;
    try {
        File f = new File("D:/test.rar");
        aFile = new RandomAccessFile(f, "r");
        ByteBuffer buffer = ByteBuffer.allocate(300000000);

        FileChannel inChannel = aFile.getChannel();
        while (inChannel.read(buffer) > 0) {
            buffer.flip();
            socket.write(buffer);
            buffer.compact();
        }
        aFile.close();
        inChannel.close();

        key.interestOps(SelectionKey.OP_READ);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 每次套接字通道变得可读时,您都会打开一个新文件。每个到达的 TCP 段,您都在重新创建目标文件,因此会丢弃之前收到的任何内容。

    解决这个问题的简单方法是在每个 OP_READ 上打开文件进行追加,但它仍然效率低得离谱。您应该在知道目标文件是什么后立即打开它,并在您从发送方读取流结束时关闭它,或者当您阅读了全部内容(如果流结束未发出信号)时关闭它。你还没有公开你的申请协议,所以我不能更具体。

  2. read() returns 零,当没有数据可以无阻塞地读取时。您将其视为文件结尾。不是。
  3. 通道间写入的规范方式如下:

    while ((in.read(buffer) > 0 || buffer.position() > 0)
    {
        buffer.flip();
        out.write(buffer);
        buffer.compact();
    }
    

    但是,如果目标是非阻塞套接字通道,这将变得更加复杂:您必须根据最后一个 write() 返回零。你会在这里的大量帖子中找到这个解释,其中很多是我的。

  4. 我从未在客户端看到非阻塞 I/O 的任何令人信服的理由,除非它连接到多个服务器(例如网络爬虫)。我会在客户端使用阻塞模式或 java.net.Socket,这将避免上面提到的写入复杂性。

注意,您不需要同时关闭从它派生的 RandomAccessFileFileChannel。两者都行。