ted*_*ddy 6 java asynchronous nio
我想从(Tomcat servlet)InputStream中读取并使用AsynchronousFileChannel异步地将(大)内容复制到文件中.我可以使用常规的FileChannel来完成它并阅读有关丢失的transferTo.但是,如果我使用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);
Run Code Online (Sandbox Code Playgroud)
那时跑步我得到
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]
Run Code Online (Sandbox Code Playgroud)
如何修复BufferOverflow?还有什么是在读取0字节时暂停循环和等待的正确方法?
对于原始海报来说为时已晚,但无论如何。
我尝试重现您的问题(但示例略有不同,我借助通道复制了大文件):
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();
}
Run Code Online (Sandbox Code Playgroud)
在循环的每次迭代中,我们从输入流中读取一块数据,然后将该块“推”到输出流中。当前线程不会等待写入完成,它会继续执行,因此我们可以做额外的工作。但在新的迭代之前我们应该等待写入完成。尝试注释掉
if (lastWrite != null) lastWrite.get();
你会得到
java.nio.BufferOverflowException。
你的代码给了我一个使用 Future 来处理最后一个写操作的提示。但你错过了等待最后一次手术。
另外,我还省略了代码片段中的一些额外调整(只是为了简单起见,在处理文件时不需要额外调整)。
| 归档时间: |
|
| 查看次数: |
1158 次 |
| 最近记录: |