From ed4bd43cacebf2d001a1d0b66b67ad5141499be1 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 3 May 2017 11:19:55 +0200 Subject: [PATCH] Add writableChannel to WritableResource This commit introduces a `writableChannel()` method to `WritableResource`, defaulting to `Channels.newChannel`, but with overrides for file-based resources. --- .../core/io/FileSystemResource.java | 12 +++++++++- .../springframework/core/io/PathResource.java | 16 ++++++++++--- .../core/io/WritableResource.java | 19 ++++++++++++++- .../core/io/PathResourceTests.java | 23 +++++++++++++++++-- 4 files changed, 63 insertions(+), 7 deletions(-) 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 b9fc1310ce3..a3b216864a0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.io.OutputStream; import java.net.URI; import java.net.URL; import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -178,6 +179,15 @@ public class FileSystemResource extends AbstractResource implements WritableReso return new FileInputStream(this.file).getChannel(); } + /** + * This implementation opens a FileChannel for the underlying file. + * @see java.nio.channels.FileChannel + */ + @Override + public WritableByteChannel writableChannel() throws IOException { + return new FileOutputStream(this.file).getChannel(); + } + /** * This implementation returns the underlying File's length. */ 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 3fd2a2bc179..571479dcb22 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import java.io.OutputStream; import java.net.URI; import java.net.URL; import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; import java.nio.file.Files; import java.nio.file.OpenOption; import java.nio.file.Path; @@ -197,14 +198,23 @@ 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...) + * This implementation opens a Channel for the underlying file. + * @see Files#newByteChannel(Path, OpenOption...) */ @Override public ReadableByteChannel readableChannel() throws IOException { return Files.newByteChannel(this.path, StandardOpenOption.READ); } + /** + * This implementation opens a Channel for the underlying file. + * @see Files#newByteChannel(Path, OpenOption...) + */ + @Override + public WritableByteChannel writableChannel() throws IOException { + return Files.newByteChannel(this.path, StandardOpenOption.WRITE); + } + /** * This implementation returns the underlying File's length. */ diff --git a/spring-core/src/main/java/org/springframework/core/io/WritableResource.java b/spring-core/src/main/java/org/springframework/core/io/WritableResource.java index 780a419d0a2..8924e57e60d 100644 --- a/spring-core/src/main/java/org/springframework/core/io/WritableResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/WritableResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,8 @@ package org.springframework.core.io; import java.io.IOException; import java.io.OutputStream; +import java.nio.channels.Channels; +import java.nio.channels.WritableByteChannel; /** * Extended interface for a resource that supports writing to it. @@ -51,4 +53,19 @@ public interface WritableResource extends Resource { */ OutputStream getOutputStream() throws IOException; + /** + * Return a {@link WritableByteChannel}. + *

It is expected that each call creates a fresh channel. + *

The default implementation returns {@link Channels#newChannel(OutputStream)} + * with the result of {@link #getOutputStream()}. + * @return the byte channel for the underlying resource (must not be {@code null}) + * @throws java.io.FileNotFoundException if the underlying resource doesn't exist + * @throws IOException if the content channel could not be opened + * @since 5.0 + * @see #getOutputStream() + */ + default WritableByteChannel writableChannel() throws IOException { + return Channels.newChannel(getOutputStream()); + } + } diff --git a/spring-core/src/test/java/org/springframework/core/io/PathResourceTests.java b/spring-core/src/test/java/org/springframework/core/io/PathResourceTests.java index d6fbc68fb5e..12717200fa7 100644 --- a/spring-core/src/test/java/org/springframework/core/io/PathResourceTests.java +++ b/spring-core/src/test/java/org/springframework/core/io/PathResourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ import java.io.FileNotFoundException; import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.StandardCharsets; import java.nio.file.AccessDeniedException; import java.nio.file.NoSuchFileException; import java.nio.file.Path; @@ -272,7 +274,7 @@ public class PathResourceTests { @Test public void outputStream() throws Exception { PathResource resource = new PathResource(temporaryFolder.newFile("test").toPath()); - FileCopyUtils.copy("test".getBytes(), resource.getOutputStream()); + FileCopyUtils.copy("test".getBytes(StandardCharsets.UTF_8), resource.getOutputStream()); assertThat(resource.contentLength(), equalTo(4L)); } @@ -328,4 +330,21 @@ public class PathResourceTests { resource.readableChannel(); } + @Test + public void getWritableChannel() throws Exception { + PathResource resource = new PathResource(temporaryFolder.newFile("test").toPath()); + ByteBuffer buffer = ByteBuffer.wrap("test".getBytes(StandardCharsets.UTF_8)); + WritableByteChannel channel = null; + try { + channel = resource.writableChannel(); + channel.write(buffer); + } + finally { + if (channel != null) { + channel.close(); + } + } + assertThat(resource.contentLength(), equalTo(4L)); + } + }