简体   繁体   English

不完整的文件复制Java NIO

[英]Incomplete File Copy Java NIO

I'm having problem with reading my file. 我在读取文件时遇到问题。 Im quite new to NIO too. 我对NIO也很陌生。 The actual size of the file I want to send to the server is almost 900MB and only received 3MB . 我要发送到服务器的文件的实际大小几乎为900MB ,只有3MB

The server's side code for reading: 服务器的辅助代码用于读取:

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();
    }
}

This is my code for the write method of the client side: 这是我的客户端写方法的代码:

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. You're opening a new file every time the socket channel becomes readable. 每当套接字通道变得可读时,您都在打开一个新文件。 Every TCP segment that arrives, you're recreating the target file, and therefore throwing away whatever was received before. 每个到达的TCP段都在重新创建目标文件,因此丢弃了之前收到的所有内容。

    The simple fix to that would be to open the file for append on every OP_READ , but it would remain ridicously inefficient. 对此的简单解决方法是打开文件,以便在每个OP_READ上追加内容,但效率极低。 You should open the target file as soon as you know what it is, and close it when you read end of stream from the sender, or when you've read the entire contents if that isn't signalled by end of stream. 您应该在知道目标文件后立即打开它,并在从发送方读取流的末尾时或在未从流的末尾发出信号的情况下读取全部内容时将其关闭。 You haven't disclosed your application protocol so I can't be more specific. 您尚未公开您的应用协议,因此我无法更具体地说明。

  2. read() returns zero when there is no data available to be read without blocking. 如果没有可读取的无阻塞数据,则read()返回零。 You're treating that as an end of file. 您将其视为文件结尾。 It isn't. 不是。
  3. The canonical way to write between channels is as follows: 通道间的规范方法如下:

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

    However if the target is a non-blocking socket channel this gets considerably more complex: you have to manipulate whether you're selected for OP_WRITE or not depending on whether or not the last write() returned zero. 但是,如果目标是非阻塞套接字通道,则情况会变得更加复杂:您必须根据最后一个write()返回零来操纵是否选择OP_WRITE。 You will find this explained in a large number of posts here, many by me. 您会在这里的许多帖子中找到解释的内容,其中很多是我写的。

  4. I have never seen any cogent reason for non-blocking I/O in the client side, unless it connects to multiple servers (a web crawler for example). 我从未见过在客户端进行非阻塞I / O的任何有力理由,除非它连接到多个服务器(例如Web爬网程序)。 I would use blocking mode or java.net.Socket at the client, which will obviate the write complexity referred to above. 我将在客户端使用阻塞模式或java.net.Socket ,这将避免上述写入复杂性。

NB you don't need to close both the RandomAccessFile and the FileChannel that was derived from it. 注意,您不需要同时关闭RandomAccessFile和从其派生的FileChannel Either will do. 都可以。

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

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