Java 1.7以降のファイルコピーのおさらいメモ

# 概要

Java 1.7以降の標準APIのみで行えるファイルコピーのおさらいです。

**環境**

* Windows 10 Professional
* OpenJDK 10.0.1

**参考**

* [Oracle JDK 9ドキュメント] (https://docs.oracle.com/javase/jp/9/index.html)
* [Oracle JDK 10ドキュメント] (https://docs.oracle.com/javase/jp/10/index.html)


# Files#copy() (Java 1.7+)

* [Files (Java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/java/nio/file/Files.html)

Java 1.7で追加されたFilesクラスのcopyメソッドを使う方法です。

```text:signature
public static long copy​(InputStream in, Path target, CopyOption... options) throws IOException

public static long copy​(Path source, OutputStream out) throws IOException

public static Path copy​(Path source, Path target, CopyOption... options) throws IOException
```

**コード例1**

```java:example
Path source = Paths.get("path/to/in.txt");
Path target = Paths.get("path/to/out.txt");
Files.copy(source, target);
```

コピー先のファイルを上書きしたい場合はコピーオプションにREPLACE_EXISTINGを指定します。

```java:example
Path source = Paths.get("path/to/in.txt");
Path target = Paths.get("path/to/out.txt");
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
```

任意のディレクトリへコピーしたい場合。
この例では"path/to/in.txt"を"path/to/newDir/in.txt"へコピーします。

```java:example
Path source = Paths.get("path/to/in.txt");
Path targetDir = Paths.get("path/to/newDir");
Files.copy(source, targetDir.resolve(source.getFileName()));
```

**コード例2**

```java:example
InputStream source = Files.newInputStream(Paths.get("path/to/in.txt"));
Path target = Paths.get("path/to/out.txt");
try (source) {
  Files.copy(source, target);
}
```


# InputStream.transferTo (Java 9+)

* [InputStream (Java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/java/io/InputStream.html)

InputStreamクラスにJava 9で追加されたtransferToメソッドを使う方法です。

```text:signature
public long transferTo​(OutputStream out) throws IOException
```

transferToは、JavaDoc(機械翻訳)に記載されている通りreader/writerのストリームを閉じません。

> この入力ストリームからすべてのバイトを読み込んで、指定された出力ストリームに読み込まれた順序でバイトを書き込みます。 戻り時に、この入力ストリームはストリームの終わりにあります。 このメソッドはいずれのストリームも閉じません。

**既知のサブクラス**

()の値はそのクラス、インターフェースが導入されたJavaのバージョン。

```text
InputStream (1.0)
 |
 +--- javax.sound.sampled.AudioInputStream (1.3)
 |
 +--- ByteArrayInputStream (1.0)
 |
 +--- FileInputStream (1.0)
 |
 +--- FilterInputStream (1.0)
 |     |
 |     +--- BufferedInputStream (1.0)
 |     +--- java.util.zip.CheckedInputStream (1.1)
 |     +--- javax.crypto.CipherInputStream (1.4)
 |     +--- DataInputStream (1.0)
 |     +--- java.util.zip.DeflaterInputStream (1.6)
 |     +--- java.security.DigestInputStream (1.2)
 |     +--- java.util.zip.InflaterInputStream (1.1)
 |     |    @Deprecated
 |     +--- LineNumberInputStream (1.0)
 |     +--- javax.swing.ProgressMonitorInputStream (1.2)
 |     +--- PushbackInputStream (1.0)
 |
 +--- org.omg.CORBA.portable.InputStream
 |
 +--- ObjectInputStream (1.1)
 |
 +--- PipedInputStream (1.0)
 |
 +--- SequenceInputStream (1.0)
 |
 |    @Deprecated
 +--- StringBufferInputStream (1.0)
```

## FileInputStream.transferTo

* [FileInputStream (Java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/java/io/FileInputStream.html)

**コード例1**

```java:example
Path source = Paths.get("path/to/in.txt");
Path target = Paths.get("path/to/out.txt");
try (InputStream in = new FileInputStream(source.toFile());
     OutputStream out = new FileOutputStream(target.toFile())) {
  in.transferTo(out);
}
```

**コード例1 (Java 9+)**

Java 9からはリソースをtry句の外側で宣言できるようになっています。

```java:example
Path source = Paths.get("path/to/in.txt");
Path target = Paths.get("path/to/out.txt");
InputStream in = new FileInputStream(source.toFile());
OutputStream out = new FileOutputStream(target.toFile());
try (in; out) {
  in.transferTo(out);
}
```

**コード例2**

```java:example
Path source = Paths.get("path/to/in.txt");
Path target = Paths.get("path/to/out.txt");
try (InputStream in = Files.newInputStream(source);
     OutputStream out = Files.newOutputStream(target)) {
    in.transferTo(out);
}
```

**コード例2 (Java 9+)**

```java:example
Path source = Paths.get("path/to/in.txt");
Path target = Paths.get("path/to/out.txt");
InputStream in = Files.newInputStream(source);
OutputStream out = Files.newOutputStream(target);
try (in; out) {
    in.transferTo(out);
}
```

# Reader.transferTo (Java 10+)

* [Reader (Java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/java/io/Reader.html)

ReaderクラスにJava 10で追加されたtransferToメソッドを使う方法です。

```text:signature
public long transferTo​(Writer out) throws IOException
```

transferToは、JavaDoc(機械翻訳)に記載されている通りreader/writerのストリームを閉じません。

> このリーダーからすべての文字を読み込み、指定されたライターに読み込まれた順番で書き込みます。 戻ってくると、このリーダーはストリームの最後にあります。 このメソッドは、リーダーまたはライターのいずれも閉じません。

**既知のサブクラス**

()の値はそのクラス、インターフェースが導入されたJavaのバージョン。

```text
Reader
 |
 +--- BufferedReader (1.1)
 |     |
 |     +--- LineNumberReader (1.1)
 |
 +--- CharArrayReader (1.1)
 |
 +--- FilterReader (1.1)
 |     |
 |     +--- PushbackReader (1.1)
 |
 +--- InputStreamReader (1.1)
 |     |
 |     +--- FileReader (1.1)
 |
 +--- PipedReader (1.1)
 |
 +--- StringReader (1.1)
 |
 +--- jdk.nashorn.api.scripting.URLReader (1.8u40)
```

## FileReader.transferTo

* [FileReader (Java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/java/io/FileReader.html)

**コード例**

```java:example
Path source = Paths.get("path/to/in.txt");
Path target = Paths.get("path/to/out.txt");
Reader in = new FileReader(source.toFile());
Writer out = new FileWriter(target.toFile());
try (in; out) {
  in.transferTo(out);
}
```

## BufferedReader.transferTo

* [BufferedReader (Java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/java/io/BufferedReader.html)

InputStreamReaderやFileReaderはBufferedReaderでラップすることが推奨されています。

> 一般的に、Readerに対して読込み要求が出されると、それに対応するベースとなる文字型ストリームまたはバイト・ストリームへの読込み要求が発行されます。 このため、FileReaderやInputStreamReaderのようにread()オペレーションの効率の良くないReaderでは、その周りをBufferedReaderでラップすることをお薦めします。

同様にOutputStreamWriterやFileWriterはBufferedWriterでラップすることが推奨されています。

> 一般的に、Writerは、その出力をただちにベースとなる文字型ストリームまたはバイト・ストリームに送信します。 プロンプト出力を必要とする場合以外では、FileWriterやOutputStreamWriterのようなWriterから直接write()オペレーションを呼び出すのは効率が悪いので、BufferedWriterでラップすることをお薦めします。

**コード例**

FileReaderのコード例を下記のように書き直すことができます。

```java:example
BufferedReader in = new BufferedReader(new FileReader(source.toFile()));
BufferedWriter out = new BufferedWriter(new FileWriter(target.toFile()));
try (in; out) {
  in.transferTo(out);
}
```

## StringReader.transferTo

* [StringReader (Java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/java/io/StringReader.html)

**コード例**

```java:example
String source = "あめんぼ\nあかいな\nあいうえお";
Path target = Paths.get("path/to/out.txt");
Reader in = new StringReader(source);
Writer out = new FileWriter(target.toFile());
try (in; out) {
  in.transferTo(out);
}
```

## URLReader.transferTo

* [URLReader (Java SE 10 & JDK 10)] (https://docs.oracle.com/javase/jp/10/docs/api/jdk/nashorn/api/scripting/URLReader.html)

URLReaderクラスはJava 1.8u40で追加されました。

**Java 11で廃止予定**です（[JEP 335: Deprecate the Nashorn JavaScript Engine] (http://openjdk.java.net/jeps/335)）。

**コード例**

```java:example
URI source = URI.create("http://www.oracle.com/technetwork/java/index.html");
Path target = Paths.get("path/to/out.txt");
Reader in = new URLReader(source.toURL(), StandardCharsets.UTF_8);
Writer out = new FileWriter(target.toFile());
try (in; out) {
  in.transferTo(out);
}
```

# (WIP) Files#writeString (Java 11+)

FilesクラスにJava 11で追加されたwriteStringメソッドを使う方法です。

```text
public static Path writeString​(Path path, CharSequence csq, OpenOption... options) throws IOException

public static Path writeString​(Path path, CharSequence csq, Charset cs, OpenOption... options) throws IOException
```