Consistent use of NIO.2 for file read/write interactions
Issue: SPR-15748
This commit is contained in:
parent
d56fedc226
commit
12114a9d4c
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.core.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -25,7 +24,9 @@ import java.net.HttpURLConnection;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
|
@ -127,7 +128,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource {
|
|||
@Override
|
||||
public ReadableByteChannel readableChannel() throws IOException {
|
||||
if (isFile()) {
|
||||
return new FileInputStream(getFile()).getChannel();
|
||||
return FileChannel.open(getFile().toPath(), StandardOpenOption.READ);
|
||||
}
|
||||
else {
|
||||
return super.readableChannel();
|
||||
|
|
|
@ -17,15 +17,16 @@
|
|||
package org.springframework.core.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -35,9 +36,15 @@ import org.springframework.util.StringUtils;
|
|||
* Supports resolution as a {@code File} and also as a {@code URL}.
|
||||
* Implements the extended {@link WritableResource} interface.
|
||||
*
|
||||
* <p>Note: As of Spring Framework 5.0, this {@link Resource} implementation
|
||||
* uses NIO.2 API for read/write interactions. Nevertheless, in contrast to
|
||||
* {@link PathResource}, it primarily manages a {@code java.io.File} handle.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 28.12.2003
|
||||
* @see PathResource
|
||||
* @see java.io.File
|
||||
* @see java.nio.file.Files
|
||||
*/
|
||||
public class FileSystemResource extends AbstractResource implements WritableResource {
|
||||
|
||||
|
@ -113,7 +120,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
|||
*/
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new FileInputStream(this.file);
|
||||
return Files.newInputStream(this.file.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +140,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
|||
*/
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return new FileOutputStream(this.file);
|
||||
return Files.newOutputStream(this.file.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,7 +183,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
|||
*/
|
||||
@Override
|
||||
public ReadableByteChannel readableChannel() throws IOException {
|
||||
return new FileInputStream(this.file).getChannel();
|
||||
return FileChannel.open(getFile().toPath(), StandardOpenOption.READ);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,7 +192,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
|
|||
*/
|
||||
@Override
|
||||
public WritableByteChannel writableChannel() throws IOException {
|
||||
return new FileOutputStream(this.file).getChannel();
|
||||
return FileChannel.open(getFile().toPath(), StandardOpenOption.WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,7 +41,9 @@ import org.springframework.util.Assert;
|
|||
* @author Philippe Marschall
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @see FileSystemResource
|
||||
* @see java.nio.file.Path
|
||||
* @see java.nio.file.Files
|
||||
*/
|
||||
public class PathResource extends AbstractResource implements WritableResource {
|
||||
|
||||
|
@ -52,8 +54,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
|||
* Create a new PathResource from a Path handle.
|
||||
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
|
||||
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
|
||||
* the given root:
|
||||
* e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* @param path a Path handle
|
||||
*/
|
||||
public PathResource(Path path) {
|
||||
|
@ -65,8 +66,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
|||
* Create a new PathResource from a Path handle.
|
||||
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
|
||||
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
|
||||
* the given root:
|
||||
* e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* @param path a path
|
||||
* @see java.nio.file.Paths#get(String, String...)
|
||||
*/
|
||||
|
@ -79,8 +79,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
|||
* Create a new PathResource from a Path handle.
|
||||
* <p>Note: Unlike {@link FileSystemResource}, when building relative resources
|
||||
* via {@link #createRelative}, the relative path will be built <i>underneath</i>
|
||||
* the given root:
|
||||
* e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* the given root: e.g. Paths.get("C:/dir1/"), relative path "dir2" -> "C:/dir1/dir2"!
|
||||
* @see java.nio.file.Paths#get(URI)
|
||||
* @param uri a path URI
|
||||
*/
|
||||
|
@ -193,7 +192,7 @@ public class PathResource extends AbstractResource implements WritableResource {
|
|||
catch (UnsupportedOperationException ex) {
|
||||
// Only paths on the default file system can be converted to a File:
|
||||
// Do exception translation for cases where conversion is not possible.
|
||||
throw new FileNotFoundException(this.path + " cannot be resolved to " + "absolute file path");
|
||||
throw new FileNotFoundException(this.path + " cannot be resolved to absolute file path");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,11 +230,11 @@ public class PathResource extends AbstractResource implements WritableResource {
|
|||
public long lastModified() throws IOException {
|
||||
// We can not use the superclass method since it uses conversion to a File and
|
||||
// only a Path on the default file system can be converted to a File...
|
||||
return Files.getLastModifiedTime(path).toMillis();
|
||||
return Files.getLastModifiedTime(this.path).toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation creates a FileResource, applying the given path
|
||||
* This implementation creates a PathResource, applying the given path
|
||||
* relative to the path of the underlying file of this resource descriptor.
|
||||
* @see java.nio.file.Path#resolve(String)
|
||||
*/
|
||||
|
|
|
@ -16,19 +16,16 @@
|
|||
|
||||
package org.springframework.util;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
|
@ -42,6 +39,7 @@ import org.springframework.lang.Nullable;
|
|||
* @author Juergen Hoeller
|
||||
* @since 06.10.2003
|
||||
* @see StreamUtils
|
||||
* @see FileSystemUtils
|
||||
*/
|
||||
public abstract class FileCopyUtils {
|
||||
|
||||
|
@ -62,9 +60,7 @@ public abstract class FileCopyUtils {
|
|||
public static int copy(File in, File out) throws IOException {
|
||||
Assert.notNull(in, "No input File specified");
|
||||
Assert.notNull(out, "No output File specified");
|
||||
|
||||
return copy(new BufferedInputStream(new FileInputStream(in)),
|
||||
new BufferedOutputStream(new FileOutputStream(out)));
|
||||
return copy(Files.newInputStream(in.toPath()), Files.newOutputStream(out.toPath()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,10 +72,7 @@ public abstract class FileCopyUtils {
|
|||
public static void copy(byte[] in, File out) throws IOException {
|
||||
Assert.notNull(in, "No input byte array specified");
|
||||
Assert.notNull(out, "No output File specified");
|
||||
|
||||
ByteArrayInputStream inStream = new ByteArrayInputStream(in);
|
||||
OutputStream outStream = new BufferedOutputStream(new FileOutputStream(out));
|
||||
copy(inStream, outStream);
|
||||
copy(new ByteArrayInputStream(in), Files.newOutputStream(out.toPath()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,8 +83,7 @@ public abstract class FileCopyUtils {
|
|||
*/
|
||||
public static byte[] copyToByteArray(File in) throws IOException {
|
||||
Assert.notNull(in, "No input File specified");
|
||||
|
||||
return copyToByteArray(new BufferedInputStream(new FileInputStream(in)));
|
||||
return copyToByteArray(Files.newInputStream(in.toPath()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ package org.springframework.util;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
|
@ -27,29 +32,60 @@ import org.springframework.lang.Nullable;
|
|||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.3
|
||||
* @deprecated as of Spring Framework 5.0, in favor of native NIO API usage
|
||||
* @see java.io.File
|
||||
* @see java.nio.file.Path
|
||||
* @see java.nio.file.Files
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class FileSystemUtils {
|
||||
|
||||
/**
|
||||
* Delete the supplied {@link File} - for directories,
|
||||
* recursively delete any nested directories or files as well.
|
||||
* <p>Note: Like {@link File#delete()}, this method does not throw any
|
||||
* exception but rather silently returns {@code false} in case of I/O
|
||||
* errors. Consider using {@link #deleteRecursively(Path)} for NIO-style
|
||||
* handling of I/O errors, clearly differentiating between non-existence
|
||||
* and failure to delete an existing file.
|
||||
* @param root the root {@code File} to delete
|
||||
* @return {@code true} if the {@code File} was deleted,
|
||||
* @return {@code true} if the {@code File} was successfully deleted,
|
||||
* otherwise {@code false}
|
||||
*/
|
||||
public static boolean deleteRecursively(@Nullable File root) {
|
||||
if (root != null && root.exists()) {
|
||||
if (root.isDirectory()) {
|
||||
File[] children = root.listFiles();
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
deleteRecursively(child);
|
||||
}
|
||||
}
|
||||
if (root != null) {
|
||||
try {
|
||||
return deleteRecursively(root.toPath());
|
||||
}
|
||||
return root.delete();
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the supplied {@link File} - for directories,
|
||||
* recursively delete any nested directories or files as well.
|
||||
* @param root the root {@code File} to delete
|
||||
* @return {@code true} if the {@code File} existed and was deleted,
|
||||
* or {@code false} it it did not exist
|
||||
* @throws IOException in the case of I/O errors
|
||||
* @since 5.0
|
||||
*/
|
||||
public static boolean deleteRecursively(@Nullable Path root) throws IOException {
|
||||
if (root != null) {
|
||||
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
return Files.deleteIfExists(root);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -61,43 +97,44 @@ public abstract class FileSystemUtils {
|
|||
* @param dest the destination directory
|
||||
* @throws IOException in the case of I/O errors
|
||||
*/
|
||||
public static void copyRecursively(@Nullable File src, File dest) throws IOException {
|
||||
Assert.isTrue(src != null && (src.isDirectory() || src.isFile()),
|
||||
"Source File must denote a directory or file");
|
||||
public static void copyRecursively(File src, File dest) throws IOException {
|
||||
Assert.notNull(src, "Source File must not be null");
|
||||
Assert.notNull(dest, "Destination File must not be null");
|
||||
doCopyRecursively(src, dest);
|
||||
copyRecursively(src.toPath(), dest.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually copy the contents of the {@code src} file/directory
|
||||
* Recursively copy the contents of the {@code src} file/directory
|
||||
* to the {@code dest} file/directory.
|
||||
* @param src the source directory
|
||||
* @param dest the destination directory
|
||||
* @throws IOException in the case of I/O errors
|
||||
* @since 5.0
|
||||
*/
|
||||
private static void doCopyRecursively(File src, File dest) throws IOException {
|
||||
if (src.isDirectory()) {
|
||||
dest.mkdir();
|
||||
File[] entries = src.listFiles();
|
||||
if (entries == null) {
|
||||
throw new IOException("Could not list files in directory: " + src);
|
||||
}
|
||||
for (File entry : entries) {
|
||||
doCopyRecursively(entry, new File(dest, entry.getName()));
|
||||
}
|
||||
public static void copyRecursively(Path src, Path dest) throws IOException {
|
||||
Assert.notNull(src, "Source Path must not be null");
|
||||
Assert.notNull(dest, "Destination Path must not be null");
|
||||
BasicFileAttributes srcAttr = Files.readAttributes(src, BasicFileAttributes.class);
|
||||
|
||||
if (srcAttr.isDirectory()) {
|
||||
Files.walkFileTree(src, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
Files.createDirectories(dest.resolve(src.relativize(dir)));
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.copy(file, dest.resolve(src.relativize(file)));
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (src.isFile()) {
|
||||
try {
|
||||
dest.createNewFile();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IOException("Failed to create file: " + dest, ex);
|
||||
}
|
||||
FileCopyUtils.copy(src, dest);
|
||||
else if (srcAttr.isRegularFile()) {
|
||||
Files.copy(src, dest);
|
||||
}
|
||||
else {
|
||||
// Special File handle: neither a file not a directory.
|
||||
// Simply skip it when contained in nested directory...
|
||||
throw new IllegalArgumentException("Source File must denote a directory or file");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import static org.junit.Assert.*;
|
|||
/**
|
||||
* @author Rob Harrop
|
||||
*/
|
||||
@Deprecated
|
||||
public class FileSystemUtilsTests {
|
||||
|
||||
@Test
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
|
||||
package org.springframework.expression.spel.standard;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Map;
|
||||
|
@ -244,40 +241,6 @@ public class SpelCompiler implements Opcodes {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For debugging purposes, dump the specified byte code into a file on the disk.
|
||||
* Not yet hooked in, needs conditionally calling based on a sys prop.
|
||||
* @param expressionText the text of the expression compiled
|
||||
* @param name the name of the class being used for the compiled expression
|
||||
* @param bytecode the bytecode for the generated class
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static void dump(String expressionText, String name, byte[] bytecode) {
|
||||
String nameToUse = name.replace('.', '/');
|
||||
String dir = (nameToUse.indexOf('/') != -1 ? nameToUse.substring(0, nameToUse.lastIndexOf('/')) : "");
|
||||
String dumpLocation = null;
|
||||
try {
|
||||
File tempFile = File.createTempFile("tmp", null);
|
||||
dumpLocation = tempFile + File.separator + nameToUse + ".class";
|
||||
tempFile.delete();
|
||||
File f = new File(tempFile, dir);
|
||||
f.mkdirs();
|
||||
// System.out.println("Expression '" + expressionText + "' compiled code dumped to " + dumpLocation);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Expression '" + expressionText + "' compiled code dumped to " + dumpLocation);
|
||||
}
|
||||
f = new File(dumpLocation);
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
fos.write(bytecode);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(
|
||||
"Unexpected problem dumping class '" + nameToUse + "' into " + dumpLocation, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A ChildClassLoader will load the generated compiled expression classes.
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.http.codec.multipart;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.Channels;
|
||||
|
@ -25,6 +24,7 @@ import java.nio.channels.FileChannel;
|
|||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -187,9 +187,9 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
|||
}
|
||||
|
||||
private Part createPart(StreamStorage storage, HttpHeaders httpHeaders) {
|
||||
String fileName = MultipartUtils.getFileName(httpHeaders);
|
||||
if (fileName != null) {
|
||||
return new SynchronossFilePart(httpHeaders, storage, fileName, this.bufferFactory);
|
||||
String filename = MultipartUtils.getFileName(httpHeaders);
|
||||
if (filename != null) {
|
||||
return new SynchronossFilePart(httpHeaders, storage, this.bufferFactory, filename);
|
||||
}
|
||||
else if (MultipartUtils.isFormField(httpHeaders, this.context)) {
|
||||
String value = MultipartUtils.readFormParameterValue(storage, httpHeaders);
|
||||
|
@ -200,13 +200,6 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
|||
}
|
||||
}
|
||||
|
||||
private Part createPart(HttpHeaders httpHeaders, StreamStorage storage) {
|
||||
String fileName = MultipartUtils.getFileName(httpHeaders);
|
||||
return fileName != null ?
|
||||
new SynchronossFilePart(httpHeaders, storage, fileName, this.bufferFactory) :
|
||||
new DefaultSynchronossPart(httpHeaders, storage, this.bufferFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String message, Throwable cause) {
|
||||
if (this.terminated.getAndIncrement() == 0) {
|
||||
|
@ -284,15 +277,18 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
|||
|
||||
private static class SynchronossFilePart extends DefaultSynchronossPart implements FilePart {
|
||||
|
||||
public SynchronossFilePart(HttpHeaders headers, StreamStorage storage,
|
||||
String fileName, DataBufferFactory factory) {
|
||||
private final String filename;
|
||||
|
||||
public SynchronossFilePart(
|
||||
HttpHeaders headers, StreamStorage storage, DataBufferFactory factory, String filename) {
|
||||
|
||||
super(headers, storage, factory);
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String filename() {
|
||||
return MultipartUtils.getFileName(headers());
|
||||
return this.filename;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -301,8 +297,7 @@ public class SynchronossPartHttpMessageReader implements HttpMessageReader<Part>
|
|||
FileChannel output = null;
|
||||
try {
|
||||
input = Channels.newChannel(getStorage().getInputStream());
|
||||
output = new FileOutputStream(destination).getChannel();
|
||||
|
||||
output = FileChannel.open(destination.toPath(), StandardOpenOption.WRITE);
|
||||
long size = (input instanceof FileChannel ? ((FileChannel) input).size() : Long.MAX_VALUE);
|
||||
long totalWritten = 0;
|
||||
while (totalWritten < size) {
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
package org.springframework.http.server.reactive;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -85,7 +85,7 @@ public class UndertowServerHttpResponse extends AbstractListenerServerHttpRespon
|
|||
return doCommit(() -> {
|
||||
FileChannel source = null;
|
||||
try {
|
||||
source = new FileInputStream(file).getChannel();
|
||||
source = FileChannel.open(file.toPath(), StandardOpenOption.READ);
|
||||
StreamSinkChannel destination = getUndertowExchange().getResponseChannel();
|
||||
Channels.transferBlocking(destination, source, position, count);
|
||||
return Mono.empty();
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
package org.springframework.web.multipart.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -317,7 +317,7 @@ public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpSe
|
|||
// At least we offloaded the file from memory storage; it'll get deleted
|
||||
// from the temp dir eventually in any case. And for our user's purposes,
|
||||
// we can manually copy it to the requested location as a fallback.
|
||||
FileCopyUtils.copy(this.part.getInputStream(), new FileOutputStream(dest));
|
||||
FileCopyUtils.copy(this.part.getInputStream(), Files.newOutputStream(dest.toPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue