/** * Obtain a {@link InputStream} from the given supplier, and read it into a {@code Flux} * of {@code DataBuffer}s. Closes the input stream when the flux is terminated. * @param inputStreamSupplier the supplier for the input stream 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> readInputStream( Callable<InputStream> inputStreamSupplier, DataBufferFactory dataBufferFactory, int bufferSize) { Assert.notNull(inputStreamSupplier, "'inputStreamSupplier' must not be null"); return readByteChannel(() -> Channels.newChannel(inputStreamSupplier.call()), dataBufferFactory, bufferSize); }
/** * Obtain a {@link InputStream} from the given supplier, and read it into a {@code Flux} * of {@code DataBuffer}s. Closes the input stream when the flux is terminated. * @param inputStreamSupplier the supplier for the input stream 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> readInputStream( Callable<InputStream> inputStreamSupplier, DataBufferFactory dataBufferFactory, int bufferSize) { Assert.notNull(inputStreamSupplier, "'inputStreamSupplier' must not be null"); return readByteChannel(() -> Channels.newChannel(inputStreamSupplier.call()), 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); }
@Test public void readByteChannel() throws Exception { URI uri = this.resource.getURI(); Flux<DataBuffer> result = DataBufferUtils.readByteChannel(() -> FileChannel.open(Paths.get(uri), StandardOpenOption.READ), this.bufferFactory, 3); verifyReadData(result); }
@Test public void readByteChannelError() throws Exception { ReadableByteChannel channel = mock(ReadableByteChannel.class); when(channel.read(any())) .thenAnswer(invocation -> { ByteBuffer buffer = invocation.getArgument(0); buffer.put("foo".getBytes(StandardCharsets.UTF_8)); buffer.flip(); return 3; }) .thenThrow(new IOException()); Flux<DataBuffer> result = DataBufferUtils.readByteChannel(() -> channel, this.bufferFactory, 3); StepVerifier.create(result) .consumeNextWith(stringConsumer("foo")) .expectError(IOException.class) .verify(Duration.ofSeconds(3)); }
/** * 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 readAndWriteByteChannel() throws Exception { Path source = Paths.get( DataBufferUtilsTests.class.getResource("DataBufferUtilsTests.txt").toURI()); Flux<DataBuffer> sourceFlux = DataBufferUtils .readByteChannel(() -> FileChannel.open(source, StandardOpenOption.READ), this.bufferFactory, 3); Path destination = Files.createTempFile("DataBufferUtilsTests", null); WritableByteChannel channel = Files.newByteChannel(destination, StandardOpenOption.WRITE); DataBufferUtils.write(sourceFlux, channel) .subscribe(DataBufferUtils.releaseConsumer(), throwable -> fail(throwable.getMessage()), () -> { try { String expected = String.join("", Files.readAllLines(source)); String result = String.join("", Files.readAllLines(destination)); assertEquals(expected, result); } catch (IOException e) { fail(e.getMessage()); } finally { DataBufferUtils.closeChannel(channel); } }); }
@Test public void SPR16070() throws Exception { ReadableByteChannel channel = mock(ReadableByteChannel.class); when(channel.read(any())) .thenAnswer(putByte('a')) .thenAnswer(putByte('b')) .thenAnswer(putByte('c')) .thenReturn(-1); Flux<DataBuffer> read = DataBufferUtils.readByteChannel(() -> channel, this.bufferFactory, 1); StepVerifier.create(read) .consumeNextWith(stringConsumer("a")) .consumeNextWith(stringConsumer("b")) .consumeNextWith(stringConsumer("c")) .expectComplete() .verify(Duration.ofSeconds(5)); }
@Test public void readByteChannelCancel() throws Exception { URI uri = this.resource.getURI(); Flux<DataBuffer> result = DataBufferUtils.readByteChannel(() -> FileChannel.open(Paths.get(uri), StandardOpenOption.READ), this.bufferFactory, 3); StepVerifier.create(result) .consumeNextWith(stringConsumer("foo")) .thenCancel() .verify(); }
/** * Obtain a {@link InputStream} from the given supplier, and read it into a {@code Flux} * of {@code DataBuffer}s. Closes the input stream when the flux is terminated. * @param inputStreamSupplier the supplier for the input stream 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> readInputStream( Callable<InputStream> inputStreamSupplier, DataBufferFactory dataBufferFactory, int bufferSize) { Assert.notNull(inputStreamSupplier, "'inputStreamSupplier' must not be null"); return readByteChannel(() -> Channels.newChannel(inputStreamSupplier.call()), dataBufferFactory, bufferSize); }
/** * Obtain a {@link InputStream} from the given supplier, and read it into a {@code Flux} * of {@code DataBuffer}s. Closes the input stream when the flux is terminated. * @param inputStreamSupplier the supplier for the input stream 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> readInputStream( Callable<InputStream> inputStreamSupplier, DataBufferFactory dataBufferFactory, int bufferSize) { Assert.notNull(inputStreamSupplier, "'inputStreamSupplier' must not be null"); return readByteChannel(() -> Channels.newChannel(inputStreamSupplier.call()), 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); }