/** * Obtain a {@code AsynchronousFileChannel} from the given supplier, and read it into a * {@code Flux} of {@code DataBuffer}s. Closes the channel when the flux is terminated. * @param channelSupplier the supplier for the channel to read from * @param dataBufferFactory the factory to create data buffers with * @param bufferSize the maximum size of the data buffers * @return a flux of data buffers read from the given channel */ public static Flux<DataBuffer> readAsynchronousFileChannel( Callable<AsynchronousFileChannel> channelSupplier, DataBufferFactory dataBufferFactory, int bufferSize) { return readAsynchronousFileChannel(channelSupplier, 0, dataBufferFactory, bufferSize); }
/** * Obtain a {@code AsynchronousFileChannel} from the given supplier, and read it into a * {@code Flux} of {@code DataBuffer}s. Closes the channel when the flux is terminated. * @param channelSupplier the supplier for the channel to read from * @param dataBufferFactory the factory to create data buffers with * @param bufferSize the maximum size of the data buffers * @return a flux of data buffers read from the given channel */ public static Flux<DataBuffer> readAsynchronousFileChannel( Callable<AsynchronousFileChannel> channelSupplier, DataBufferFactory dataBufferFactory, int bufferSize) { return readAsynchronousFileChannel(channelSupplier, 0, dataBufferFactory, bufferSize); }
/** * Read the given {@code Resource} into a {@code Flux} of {@code DataBuffer}s * starting at the given position. * <p>If the resource is a file, it is read into an * {@code AsynchronousFileChannel} and turned to {@code Flux} via * {@link #readAsynchronousFileChannel(Callable, DataBufferFactory, int)} or else * fall back on {@link #readByteChannel(Callable, DataBufferFactory, int)}. * Closes the channel when the flux is terminated. * @param resource the resource to read from * @param position the position to start reading from * @param dataBufferFactory the factory to create data buffers with * @param bufferSize the maximum size of the data buffers * @return a flux of data buffers read from the given channel */ public static Flux<DataBuffer> read( Resource resource, long position, DataBufferFactory dataBufferFactory, int bufferSize) { try { if (resource.isFile()) { File file = resource.getFile(); return readAsynchronousFileChannel( () -> AsynchronousFileChannel.open(file.toPath(), StandardOpenOption.READ), position, dataBufferFactory, bufferSize); } } catch (IOException ignore) { // fallback to resource.readableChannel(), below } Flux<DataBuffer> result = readByteChannel(resource::readableChannel, dataBufferFactory, bufferSize); return position == 0 ? result : skipUntilByteCount(result, position); }
/** * Read the given {@code Resource} into a {@code Flux} of {@code DataBuffer}s * starting at the given position. * <p>If the resource is a file, it is read into an * {@code AsynchronousFileChannel} and turned to {@code Flux} via * {@link #readAsynchronousFileChannel(Callable, DataBufferFactory, int)} or else * fall back on {@link #readByteChannel(Callable, DataBufferFactory, int)}. * Closes the channel when the flux is terminated. * @param resource the resource to read from * @param position the position to start reading from * @param dataBufferFactory the factory to create data buffers with * @param bufferSize the maximum size of the data buffers * @return a flux of data buffers read from the given channel */ public static Flux<DataBuffer> read( Resource resource, long position, DataBufferFactory dataBufferFactory, int bufferSize) { try { if (resource.isFile()) { File file = resource.getFile(); return readAsynchronousFileChannel( () -> AsynchronousFileChannel.open(file.toPath(), StandardOpenOption.READ), position, dataBufferFactory, bufferSize); } } catch (IOException ignore) { // fallback to resource.readableChannel(), below } Flux<DataBuffer> result = readByteChannel(resource::readableChannel, dataBufferFactory, bufferSize); return position == 0 ? result : skipUntilByteCount(result, position); }
@Test public void readAsynchronousFileChannel() throws Exception { URI uri = this.resource.getURI(); Flux<DataBuffer> flux = DataBufferUtils.readAsynchronousFileChannel( () -> AsynchronousFileChannel.open(Paths.get(uri), StandardOpenOption.READ), this.bufferFactory, 3); verifyReadData(flux); }
@Test public void readAsynchronousFileChannelError() throws Exception { AsynchronousFileChannel channel = mock(AsynchronousFileChannel.class); doAnswer(invocation -> { ByteBuffer byteBuffer = invocation.getArgument(0); byteBuffer.put("foo".getBytes(StandardCharsets.UTF_8)); byteBuffer.flip(); long pos = invocation.getArgument(1); assertEquals(0, pos); DataBuffer dataBuffer = invocation.getArgument(2); CompletionHandler<Integer, DataBuffer> completionHandler = invocation.getArgument(3); completionHandler.completed(3, dataBuffer); return null; }).doAnswer(invocation -> { DataBuffer dataBuffer = invocation.getArgument(2); CompletionHandler<Integer, DataBuffer> completionHandler = invocation.getArgument(3); completionHandler.failed(new IOException(), dataBuffer); return null; }) .when(channel).read(any(), anyLong(), any(), any()); Flux<DataBuffer> result = DataBufferUtils.readAsynchronousFileChannel(() -> channel, this.bufferFactory, 3); StepVerifier.create(result) .consumeNextWith(stringConsumer("foo")) .expectError(IOException.class) .verify(Duration.ofSeconds(3)); }
@Test public void readAndWriteAsynchronousFileChannel() throws Exception { Path source = Paths.get( DataBufferUtilsTests.class.getResource("DataBufferUtilsTests.txt").toURI()); Flux<DataBuffer> sourceFlux = DataBufferUtils.readAsynchronousFileChannel( () -> AsynchronousFileChannel.open(source, StandardOpenOption.READ), this.bufferFactory, 3); Path destination = Files.createTempFile("DataBufferUtilsTests", null); AsynchronousFileChannel channel = AsynchronousFileChannel.open(destination, StandardOpenOption.WRITE); CountDownLatch latch = new CountDownLatch(1); DataBufferUtils.write(sourceFlux, channel) .subscribe(DataBufferUtils::release, throwable -> fail(throwable.getMessage()), () -> { try { String expected = String.join("", Files.readAllLines(source)); String result = String.join("", Files.readAllLines(destination)); assertEquals(expected, result); latch.countDown(); } catch (IOException e) { fail(e.getMessage()); } finally { DataBufferUtils.closeChannel(channel); } }); latch.await(); }
@Test public void readAsynchronousFileChannelPosition() throws Exception { URI uri = this.resource.getURI(); Flux<DataBuffer> flux = DataBufferUtils.readAsynchronousFileChannel( () -> AsynchronousFileChannel.open(Paths.get(uri), StandardOpenOption.READ), 9, this.bufferFactory, 3); StepVerifier.create(flux) .consumeNextWith(stringConsumer("qux")) .expectComplete() .verify(Duration.ofSeconds(5)); }
@Test public void readAsynchronousFileChannelCancel() throws Exception { URI uri = this.resource.getURI(); Flux<DataBuffer> flux = DataBufferUtils.readAsynchronousFileChannel( () -> AsynchronousFileChannel.open(Paths.get(uri), StandardOpenOption.READ), this.bufferFactory, 3); StepVerifier.create(flux) .consumeNextWith(stringConsumer("foo")) .thenCancel() .verify(); }
/** * Obtain a {@code AsynchronousFileChannel} from the given supplier, and read it into a * {@code Flux} of {@code DataBuffer}s. Closes the channel when the flux is terminated. * @param channelSupplier the supplier for the channel to read from * @param dataBufferFactory the factory to create data buffers with * @param bufferSize the maximum size of the data buffers * @return a flux of data buffers read from the given channel */ public static Flux<DataBuffer> readAsynchronousFileChannel( Callable<AsynchronousFileChannel> channelSupplier, DataBufferFactory dataBufferFactory, int bufferSize) { return readAsynchronousFileChannel(channelSupplier, 0, dataBufferFactory, bufferSize); }
/** * Obtain a {@code AsynchronousFileChannel} from the given supplier, and read it into a * {@code Flux} of {@code DataBuffer}s. Closes the channel when the flux is terminated. * @param channelSupplier the supplier for the channel to read from * @param dataBufferFactory the factory to create data buffers with * @param bufferSize the maximum size of the data buffers * @return a flux of data buffers read from the given channel */ public static Flux<DataBuffer> readAsynchronousFileChannel( Callable<AsynchronousFileChannel> channelSupplier, DataBufferFactory dataBufferFactory, int bufferSize) { return readAsynchronousFileChannel(channelSupplier, 0, dataBufferFactory, bufferSize); }
/** * Read the given {@code Resource} into a {@code Flux} of {@code DataBuffer}s * starting at the given position. * <p>If the resource is a file, it is read into an * {@code AsynchronousFileChannel} and turned to {@code Flux} via * {@link #readAsynchronousFileChannel(Callable, DataBufferFactory, int)} or else * fall back on {@link #readByteChannel(Callable, DataBufferFactory, int)}. * Closes the channel when the flux is terminated. * @param resource the resource to read from * @param position the position to start reading from * @param dataBufferFactory the factory to create data buffers with * @param bufferSize the maximum size of the data buffers * @return a flux of data buffers read from the given channel */ public static Flux<DataBuffer> read( Resource resource, long position, DataBufferFactory dataBufferFactory, int bufferSize) { try { if (resource.isFile()) { File file = resource.getFile(); return readAsynchronousFileChannel( () -> AsynchronousFileChannel.open(file.toPath(), StandardOpenOption.READ), position, dataBufferFactory, bufferSize); } } catch (IOException ignore) { // fallback to resource.readableChannel(), below } Flux<DataBuffer> result = readByteChannel(resource::readableChannel, dataBufferFactory, bufferSize); return position == 0 ? result : skipUntilByteCount(result, position); }
/** * Read the given {@code Resource} into a {@code Flux} of {@code DataBuffer}s * starting at the given position. * <p>If the resource is a file, it is read into an * {@code AsynchronousFileChannel} and turned to {@code Flux} via * {@link #readAsynchronousFileChannel(Callable, DataBufferFactory, int)} or else * fall back on {@link #readByteChannel(Callable, DataBufferFactory, int)}. * Closes the channel when the flux is terminated. * @param resource the resource to read from * @param position the position to start reading from * @param dataBufferFactory the factory to create data buffers with * @param bufferSize the maximum size of the data buffers * @return a flux of data buffers read from the given channel */ public static Flux<DataBuffer> read( Resource resource, long position, DataBufferFactory dataBufferFactory, int bufferSize) { try { if (resource.isFile()) { File file = resource.getFile(); return readAsynchronousFileChannel( () -> AsynchronousFileChannel.open(file.toPath(), StandardOpenOption.READ), position, dataBufferFactory, bufferSize); } } catch (IOException ignore) { // fallback to resource.readableChannel(), below } Flux<DataBuffer> result = readByteChannel(resource::readableChannel, dataBufferFactory, bufferSize); return position == 0 ? result : skipUntilByteCount(result, position); }