java - 不完整的文件复制 Java NIO

标签 java asynchronous nio filechannel

我在读取文件时遇到问题。我对 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();
    }
}

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

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. 每次套接字 channel 变得可读时,您都会打开一个新文件。每个到达的 TCP 段,您都会重新创建目标文件,因此会丢弃之前收到的所有内容。

    解决这个问题的简单方法是在每个 OP_READ 上打开文件进行追加,但它的效率仍然很低。您应该在知道目标文件是什么后立即打开它,并在从发送者处读取流结束时关闭它,或者在读取整个内容(如果流结束未发出信号)时关闭它。您尚未透露您的应用程序协议(protocol),因此我无法提供更具体的信息。

  2. 当没有数据可在不阻塞的情况下读取时,
  3. read() 返回零。您将其视为文件结尾。事实并非如此。
  4. 在 channel 之间写入的规范方法如下:

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

    但是,如果目标是非阻塞套接字 channel ,则情况会变得更加复杂:您必须根据最后一个 write() 是否选择您来操作是否选择 OP_WRITE 。返回零。您会发现这里有大量帖子解释了这一点,其中很多是我自己写的。

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

注意,您不需要同时关闭 RandomAccessFile 和从中派生的 FileChannel。两者都可以。

关于java - 不完整的文件复制 Java NIO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36888298/

相关文章:

java - 从 android 发送 json 数组作为 post 参数

java - 如何使用 Java NIO 套接字重新组装数据包

java - 如何在JAVA中正确关闭java SocketChannel?

java - 使用绘制位置与平移变换时,Graphics2D 文本绘制在不同的位置

java - 方法 setLatestEventInfo(GcmMessageHandler, String, String, PendingIntent) 未定义类型通知

java - JDBC模板: getting the inserted data's autogenerated key

c# - 如何在 ASP.NET MVC Web 应用程序中使用 log4net 异步登录而不用尽所有可用线程?

javascript - 如果我们需要等待,为什么回调被认为是异步的

mongodb - Redis vs MongoDB 存储异步结果过期

Java 7 NIO2 Files.walk NotDirectoryException