diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java index 9b192fd4dd..29aec14530 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java @@ -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(); diff --git a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java index a3b216864a..80f86d85ea 100644 --- a/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/FileSystemResource.java @@ -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. * + *
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); } /** diff --git a/spring-core/src/main/java/org/springframework/core/io/PathResource.java b/spring-core/src/main/java/org/springframework/core/io/PathResource.java index 571479dcb2..a63c22fb97 100644 --- a/spring-core/src/main/java/org/springframework/core/io/PathResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/PathResource.java @@ -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. *
Note: Unlike {@link FileSystemResource}, when building relative resources * via {@link #createRelative}, the relative path will be built underneath - * 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. *
Note: Unlike {@link FileSystemResource}, when building relative resources * via {@link #createRelative}, the relative path will be built underneath - * 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. *
Note: Unlike {@link FileSystemResource}, when building relative resources * via {@link #createRelative}, the relative path will be built underneath - * 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) */ diff --git a/spring-core/src/main/java/org/springframework/util/FileCopyUtils.java b/spring-core/src/main/java/org/springframework/util/FileCopyUtils.java index 3c933b23b5..ed596a173b 100644 --- a/spring-core/src/main/java/org/springframework/util/FileCopyUtils.java +++ b/spring-core/src/main/java/org/springframework/util/FileCopyUtils.java @@ -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())); } diff --git a/spring-core/src/main/java/org/springframework/util/FileSystemUtils.java b/spring-core/src/main/java/org/springframework/util/FileSystemUtils.java index 5445f006f1..96c5424d3f 100644 --- a/spring-core/src/main/java/org/springframework/util/FileSystemUtils.java +++ b/spring-core/src/main/java/org/springframework/util/FileSystemUtils.java @@ -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. + *
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