我在阅读文件时遇到问题。我对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();
}
}
答案 0 :(得分:3)
每次套接字通道可读时,您都会打开一个新文件。到达的每个TCP段,您都会重新创建目标文件,因此丢弃以前收到的任何内容。
对此的简单修复是打开文件以便在每个OP_READ
上追加,但它仍然会非常低效。您应该在知道目标文件后立即打开目标文件,并在读取发件人的流末尾时关闭目标文件,或者如果您没有在结束时发出信号,则将其关闭。流。您尚未披露您的申请协议,因此我无法更具体。
read()
返回零。您将其视为文件的结尾。它不是。在频道之间写的规范方法如下:
while ((in.read(buffer) > 0 || buffer.position() > 0)
{
buffer.flip();
out.write(buffer);
buffer.compact();
}
但是,如果目标是非阻塞套接字通道,则会变得相当复杂:您必须操纵是否为OP_WRITE选择,具体取决于最后write()
是否返回零。你会发现这里有很多帖子解释过,很多都是我。
我从未见过客户端非阻塞I / O的任何令人信服的理由,除非它连接到多个服务器(例如网络爬虫)。我会在客户端使用阻塞模式或java.net.Socket
,这将消除上面提到的写入复杂性。
注意,您不需要关闭从中获取的RandomAccessFile
和FileChannel
。要么会这样做。