Java-通过通道传输大文件-NIO

Java-通过通道传输大文件-NIO,java,nio,Java,Nio,我必须使用NIO通过ServerSocket传输大约100MB的数据,但我不知道如何在任何地方都不中断传输/保持传输状态 我的第一个想法是发送文件的大小,显然我不能发送那个大文件的大小,因为它甚至不能一次装入RAM。然后我想,为什么不直接转移,直到什么都没有收到,但问题就出现了 即使我一直在写服务器端数据 FileChannel fc = new FileInputStream(f).getChannel(); ByteBuffer buffer = ByteBu

我必须使用NIO通过ServerSocket传输大约100MB的数据,但我不知道如何在任何地方都不中断传输/保持传输状态

我的第一个想法是发送文件的大小,显然我不能发送那个大文件的大小,因为它甚至不能一次装入RAM。然后我想,为什么不直接转移,直到什么都没有收到,但问题就出现了

即使我一直在写服务器端数据

        FileChannel fc = new FileInputStream(f).getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while(fc.read(buffer) > 0) {
            buffer.flip();
            while(channel.write(buffer) > 0);
            buffer.clear();
        }
但是,因为在文件传输过程中必须有中断,所以在一段时间内不断读取数据,在没有可用数据时中断数据是个坏主意

我不知道如何才能告诉客户端是否还有可用的数据,而不必将每个数据片作为带有操作码等的新数据包发送,或者甚至是可能的

我还想知道是否有比下面更好的方法发送整个缓冲区

while(channel.write(buffer) > 0);

也许你正在寻找这个:

channel.transferFrom(0, fc.size(), fc);

如果您不能依赖套接字保持打开状态,则无法在协议中构建恢复并继续机制。至于告诉客户端预期的字节数,您可以在不将文件读入内存的情况下找到文件的大小。

通过缓冲区复制通道的正确方法如下:

while (in.read(buffer) >= 0 || buffer.position() > 0)
{
  buffer.flip();
  out.write(buffer);
  buffer.compact();
}
这将处理所有角落案例,包括读取长度!=写入长度,并在输入端保留数据


NB,用于阻塞模式。如果您处于非阻塞模式,如果read()或write()返回零,您应该返回到
select()
循环。

哇,我怎么会错过这个?我明天会试试,如果你的答案行得通,我希望能接受。@ruhkis请注意,你需要在循环中调用这个方法,因为它不能保证在一次调用中传输整个长度。另请参阅我的答案。我已经回答了部分问题,但我必须说我不明白你所说的“文件传输中必须有中断”和“不断读取数据,在没有可用数据时中断是个坏主意”是什么意思。请解释。希望我能接受多个答案,因为我根本不确定这个答案属于谁。维齐尔给了我一个完美的解决方案,但你做到了。我目前使用的代码与您的代码几乎完全相同,而且工作非常完美。非常感谢你们俩。然而,我不确定紧凑型操作能做什么,但我想它肯定比清算更好。再次感谢@Ruuhkis
compact()
删除已写入的内容,但保留未写入的内容。如果改为使用
clear()
,则如果读取长度!=书写长度,可以随时发生。谢谢,这是一些很好的建议。