Java 如何将InputStream复制到AsynchronousFileChannel

Java 如何将InputStream复制到AsynchronousFileChannel,java,asynchronous,nio,Java,Asynchronous,Nio,我想从(TomcatServlet)输入流中读取内容,并使用AsynchronousFileChannel将(大)内容异步复制到文件中。我可以做这件事,也可以阅读有关它的文章。但是如果我使用Java 7 AsyncFileChannel,我总是会得到BufferOverflowException try (AsynchronousFileChannel output = AsynchronousFileChannel.open(path, StandardOpenOption.CREAT

我想从(TomcatServlet)输入流中读取内容,并使用AsynchronousFileChannel将(大)内容异步复制到文件中。我可以做这件事,也可以阅读有关它的文章。但是如果我使用Java 7 AsyncFileChannel,我总是会得到BufferOverflowException

    try (AsynchronousFileChannel output = AsynchronousFileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
         output.lock(); // need to lock, this is one key reason to use channel

        ReadableByteChannel input = Channels.newChannel(inputStream); // servlet InputStream
        ByteBuffer buf = ByteBuffer.allocate(4096);
        int position = 0;
        int count;
        Future<Integer> lastWrite = null;
        while ((count = input.read(buf)) >= 0 || buf.position() > 0) {
            logger.info("read {} bytes", count);
            buf.flip();
            output.write(buf, position);
            if (count > 0) position += count;
            buf.compact();
        }
        if (lastWrite != null) lastWrite.get(10, TimeUnit.SECONDS);

如何修复缓冲区溢出?还有,当读取0字节时,挂起循环并等待的正确方法是什么?

对于原始海报来说太晚了,但无论如何

我试图复制您的问题(但样本略有不同,我借助渠道复制了大文件):

publicstaticvoidmain(String[]args)抛出IOException、interruptedeexception、ExecutionException{
final InputStream InputStream=新文件InputStream(“/home/me/Store/largefile”);
最终可读性ByTechannel inputChannel=Channels.newChannel(inputStream);
最终AsynchronousFileChannel输出通道=AsynchronousFileChannel.open(
FileSystems.getDefault().getPath(
“/home/me/Store/output”),
StandardOpenOption.CREATE、StandardOpenOption.WRITE);
outputChannel.lock();
最终字节缓冲区=字节缓冲区分配(4096);
int位置=0;
int receivedBytes=0;
未来lastWrite=null;
而((ReceivedBytes=inputChannel.read(buffer))>=0
||buffer.position()!=0){
System.out.println(“接收字节:“+receivedbytes”);
System.out.println(“缓冲区位置:+Buffer.position());
flip();
lastWrite=outputChannel.write(缓冲区、位置);
//在异步通道将字节写入磁盘时执行额外工作,
//在完美的情况下,可以做更多的额外工作,而不仅仅是简单的计算
位置+=接收字节;
//额外的工作已经完成,我们应该等待,因为我们只使用一个缓冲区,它可能仍然很忙
如果(lastWrite!=null)lastWrite.get();
buffer.compact();
}
outputChannel.close();
inputChannel.close();
inputStream.close();
}
在循环的每次迭代中,我们从输入流中读取一个数据块,然后将该数据块“推”到输出流中。当前线程不会等待写入完成,它会继续,所以我们可以做额外的工作。但在新的迭代之前,我们应该等待编写完成。试着评论一下

if(lastWrite!=null)lastWrite.get()

你会得到

java.nio.BufferOverflowException

您的代码为我提供了使用Future处理上次写入操作的提示。但是你错过了等待最后一次手术


此外,我还省略了代码片段中的一些附加tunning(只是为了简单起见,在处理文件时不需要附加tunning)。

仍在寻找答案,还是您解决了它?您从哪里获得
inputStream
?该错误是由
HeapByteBuffer.put
调用的字节数组太大,无法容纳,但是
通道。ReadableByteChannel.read
似乎是正确的,除非
inputStream.read
返回的大小大于传递给它的最大值。(这将是
InputStream
的一个中断实现,但是
HeapByteBuffer
ReadableByteChannel
的源代码似乎是正确的。)
14:12:30.597 [http-bio-9090-exec-3] INFO  c.b.p.c.BlobUploadServlet - read 4096 bytes
14:12:30.597 [http-bio-9090-exec-3] INFO  c.b.p.c.BlobUploadServlet - read 0 bytes
... many more with 0 bytes read ...
14:12:30.597 [http-bio-9090-exec-3] INFO  c.b.p.c.BlobUploadServlet - read 3253 bytes
14:12:30.605 [http-bio-9090-exec-3] ERROR c.b.p.c.BlobUploadServlet - null
java.nio.BufferOverflowException: null
at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:183) ~[na:1.7.0_17]
at java.nio.channels.Channels$ReadableByteChannelImpl.read(Channels.java:393) ~[na:1.7.0_17]
public static void main(String[] args) throws IOException,  InterruptedException, ExecutionException {
    final InputStream inputStream = new FileInputStream("/home/me/Store/largefile");
    final ReadableByteChannel inputChannel = Channels.newChannel(inputStream);
    final AsynchronousFileChannel outputChannel = AsynchronousFileChannel.open(
                    FileSystems.getDefault().getPath(
                    "/home/me/Store/output"),
                    StandardOpenOption.CREATE, StandardOpenOption.WRITE);
    outputChannel.lock();

    final ByteBuffer buffer = ByteBuffer.allocate(4096);
    int position = 0;
    int recievedBytes = 0;
    Future<Integer> lastWrite = null;

    while ((recievedBytes = inputChannel.read(buffer)) >= 0
            || buffer.position() != 0) {
        System.out.println("Recieved bytes: " + recievedBytes);
        System.out.println("Buffer position: " + buffer.position());
        buffer.flip();
        lastWrite = outputChannel.write(buffer, position);
        // do extra work while asynchronous channel is writing bytes to disk,
        // in perfect case more extra work can be done, not just simple calculations
        position += recievedBytes;
        // extra work is done, we should wait, because we use only one buffer which can be still busy
        if (lastWrite != null)  lastWrite.get();
        buffer.compact();
    }

    outputChannel.close();
    inputChannel.close();
    inputStream.close();
}