文件复制不完整 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();
}
}
每次套接字通道变得可读时,您都会打开一个新文件。每个到达的 TCP 段,您都在重新创建目标文件,因此会丢弃之前收到的任何内容。
解决这个问题的简单方法是在每个 OP_READ
上打开文件进行追加,但它仍然效率低得离谱。您应该在知道目标文件是什么后立即打开它,并在您从发送方读取流结束时关闭它,或者当您阅读了全部内容(如果流结束未发出信号)时关闭它。你还没有公开你的申请协议,所以我不能更具体。
read()
returns 零,当没有数据可以无阻塞地读取时。您将其视为文件结尾。不是。
通道间写入的规范方式如下:
while ((in.read(buffer) > 0 || buffer.position() > 0)
{
buffer.flip();
out.write(buffer);
buffer.compact();
}
但是,如果目标是非阻塞套接字通道,这将变得更加复杂:您必须根据最后一个 write()
返回零。你会在这里的大量帖子中找到这个解释,其中很多是我的。
我从未在客户端看到非阻塞 I/O 的任何令人信服的理由,除非它连接到多个服务器(例如网络爬虫)。我会在客户端使用阻塞模式或 java.net.Socket
,这将避免上面提到的写入复杂性。
注意,您不需要同时关闭从它派生的 RandomAccessFile
和 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();
}
}
这是我的客户端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();
}
}
每次套接字通道变得可读时,您都会打开一个新文件。每个到达的 TCP 段,您都在重新创建目标文件,因此会丢弃之前收到的任何内容。
解决这个问题的简单方法是在每个
OP_READ
上打开文件进行追加,但它仍然效率低得离谱。您应该在知道目标文件是什么后立即打开它,并在您从发送方读取流结束时关闭它,或者当您阅读了全部内容(如果流结束未发出信号)时关闭它。你还没有公开你的申请协议,所以我不能更具体。read()
returns 零,当没有数据可以无阻塞地读取时。您将其视为文件结尾。不是。通道间写入的规范方式如下:
while ((in.read(buffer) > 0 || buffer.position() > 0) { buffer.flip(); out.write(buffer); buffer.compact(); }
但是,如果目标是非阻塞套接字通道,这将变得更加复杂:您必须根据最后一个
write()
返回零。你会在这里的大量帖子中找到这个解释,其中很多是我的。我从未在客户端看到非阻塞 I/O 的任何令人信服的理由,除非它连接到多个服务器(例如网络爬虫)。我会在客户端使用阻塞模式或
java.net.Socket
,这将避免上面提到的写入复杂性。
注意,您不需要同时关闭从它派生的 RandomAccessFile
和 FileChannel
。两者都行。