Add Resource.readableChannel()

Added readableChannel() to Resource, which returns a
java.nio.ReadableByteChannel. The default implementation uses
Channels.newChannel() to create a channel based on what is returned from
getInputStream(). Subclasses have more effecient, file-based
implementations.

Issue: SPR-14698
This commit is contained in:
Arjen Poutsma
2016-09-12 19:18:10 +02:00
committed by Rossen Stoyanchev
parent 06395f41cb
commit c6a61e0d85
8 changed files with 126 additions and 4 deletions

View File

@@ -17,7 +17,7 @@
package org.springframework.core.codec;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.ReadableByteChannel;
import java.util.Map;
import reactor.core.publisher.Flux;
@@ -66,8 +66,8 @@ public class ResourceEncoder extends AbstractSingleValueEncoder<Resource> {
protected Flux<DataBuffer> encode(Resource resource, DataBufferFactory dataBufferFactory,
ResolvableType type, MimeType mimeType, Map<String, Object> hints) throws IOException {
InputStream is = resource.getInputStream();
return DataBufferUtils.read(is, dataBufferFactory, bufferSize);
ReadableByteChannel channel = resource.readableChannel();
return DataBufferUtils.read(channel, dataBufferFactory, bufferSize);
}
}

View File

@@ -17,12 +17,14 @@
package org.springframework.core.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.ReadableByteChannel;
import org.springframework.util.ResourceUtils;
@@ -115,6 +117,22 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
return ResourceUtils.getFile(uri, getDescription());
}
/**
* This implementation returns a FileChannel for the given URI-identified
* resource, provided that it refers to a file in the file system.
* @since 5.0
* @see #getFile(URI)
*/
@Override
public ReadableByteChannel readableChannel() throws IOException {
if (isFile()) {
return new FileInputStream(getFile()).getChannel();
}
else {
return super.readableChannel();
}
}
@Override
public boolean exists() {

View File

@@ -23,6 +23,8 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import org.springframework.core.NestedIOException;
import org.springframework.util.Assert;
@@ -122,6 +124,15 @@ public abstract class AbstractResource implements Resource {
throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
}
/**
* This implementation returns {@link Channels#newChannel(InputStream)} with the result of
* {@link #getInputStream()}.
*/
@Override
public ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
/**
* This implementation reads the entire InputStream to calculate the
* content length. Subclasses will almost always be able to provide

View File

@@ -24,6 +24,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.nio.channels.ReadableByteChannel;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -168,6 +169,15 @@ public class FileSystemResource extends AbstractResource implements WritableReso
return this.file;
}
/**
* This implementation opens a FileChannel for the underlying file.
* @see java.nio.channels.FileChannel
*/
@Override
public ReadableByteChannel readableChannel() throws IOException {
return new FileInputStream(this.file).getChannel();
}
/**
* This implementation returns the underlying File's length.
*/

View File

@@ -23,10 +23,12 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.springframework.util.Assert;
@@ -194,6 +196,15 @@ public class PathResource extends AbstractResource implements WritableResource {
}
}
/**
* This implementation opens a InputStream for the underlying file.
* @see java.nio.file.spi.FileSystemProvider#newInputStream(Path, OpenOption...)
*/
@Override
public ReadableByteChannel readableChannel() throws IOException {
return Files.newByteChannel(this.path, StandardOpenOption.READ);
}
/**
* This implementation returns the underlying File's length.
*/

View File

@@ -18,8 +18,11 @@ package org.springframework.core.io;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
/**
* Interface for a resource descriptor that abstracts from the actual
@@ -111,6 +114,19 @@ public interface Resource extends InputStreamSource {
*/
File getFile() throws IOException;
/**
* Return a {@link ReadableByteChannel}.
* <p>It is expected that each call creates a <i>fresh</i> channel.
* <p>The default implementation returns {@link Channels#newChannel(InputStream)} with the
* result of {@link #getInputStream()}.
* @return the byte channel for the underlying resource (must not be {@code null})
* @throws IOException if the channel could not be opened
* @since 5.0
*/
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
/**
* Determine the content length for this resource.
* @throws IOException if the resource cannot be resolved