# 用 Java 复制文件

原文：http://zetcode.com/java/copyfile/

在 Java 复制文件教程中，我们展示了如何使用 Java 复制文件。 我们复制具有内置类的文件，包括`File`，`FileInputStream`，`FileOutputStream`，`FileChannel`和`Files`。 我们还使用两个第三方库：Apache Commons IO 和 Google Guava。

文件复制是创建一个与现有文件具有相同内容的新文件。 文件移动正在将文件从一个位置传输到另一位置。

要复制的文件称为源文件，而新副本称为目标文件。

## bugs 文件

在示例中，我们使用`bugs.txt`文件。

`bugs.txt`

```java
Assasin bug, Avondale spider, Backswimmer,
Bamboo moth, Banana moth, Bed bug,
Black cocroach, Blue moon, Bumble Bee,
Carpenter Bee, Cattle tick, Cave Weta,
Cicada, Cinnibar, Click beetle, Clothes moth,
Codling moth, Centipede, Earwig, Eucalypt longhorn beetle,
Field Grasshopper, Garden slug, Garden soldier,
German cockroach, German wasp, Giant dragonfly,
Giraffe weevil, Grass grub, Grass looper,
Green planthopper, Green house spider, Gum emperor,
Gum leaf skeletoniser, Hornet, Mealybug,
Mites, Mole Cricket, Monarch butterfly,
Mosquito, Silverfish, Wasp,
Water boatman, Winged weta, Wolf spider,
Yellow Jacket, Yellow Admiral

```

这是一个包含错误名称的简单文件。

## 使用`FileInputStream`和`FileOutputStream`复制文件

使用`FileInputStream`和`FileOutputStream`，我们创建用于读取和写入`File`的流。 找不到文件时，将引发`FileNotFoundException`。 `File`是 Java 中文件或目录的表示。

`com/zetcode/CopyFileStream.java`

```java
package com.zetcode;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyFileStream {

    public static void main(String[] args) throws IOException {

        var source = new File("src/resources/bugs.txt");
        var dest = new File("src/resources/bugs2.txt");

        try (var fis = new FileInputStream(source);
             var fos = new FileOutputStream(dest)) {

            byte[] buffer = new byte[1024];
            int length;

            while ((length = fis.read(buffer)) > 0) {

                fos.write(buffer, 0, length);
            }
        }
    }
}

```

本示例使用`FileInputStream`，`FileOutputStream`和`File`复制文件。

```java
try (var fis = new FileInputStream(source);
     var fos = new FileOutputStream(dest)) {

```

我们创建`FileInputStream`和`FileOutputStream`的实例。 `try-with-resources`语句将自动关闭流。

```java
byte[] buffer = new byte[1024];

```

我们将复制 1024 个字节的文本块。 这样做是为了获得更好的性能。

```java
while ((length = is.read(buffer)) > 0) {

```

`FileInputStream`的`read()`方法从输入流中读取指定数量的字节，并将其存储到缓冲区数组中。 它返回读入缓冲区的字节总数，如果由于到达流的末尾而没有更多数据，则返回 -1。

```java
os.write(buffer, 0, length);

```

`FileOutputStream`的`write()`方法将存储在缓冲区中的字节写入输出流。 第一个参数是数据，第二个参数是数据中的起始偏移量，最后一个参数是要写入的字节数。

## 使用`Paths`和`Files`复制文件

下一个示例与上一个示例相似。 它使用了更现代的 API。

`com/zetcode/CopyFileStream2.java`

```java
package com.zetcode;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CopyFileStream2 {

    public static void main(String[] args) throws IOException {

        var source = Paths.get("src/resources/bugs.txt");
        var dest = Paths.get("src/resources/bugs2.txt");

        try (var fis = Files.newInputStream(source);
             var fos = Files.newOutputStream(dest)) {

            byte[] buffer = new byte[1024];
            int length;

            while ((length = fis.read(buffer)) > 0) {

                fos.write(buffer, 0, length);
            }
        }
    }
}

```

我们使用`Paths`和`Files`类复制文件。

```java
var source = Paths.get("src/resources/bugs.txt");
var dest = Paths.get("src/resources/bugs2.txt");

```

从文件中，我们创建`Path`对象。

```java
try (var fis = Files.newInputStream(source);
     var fos = Files.newOutputStream(dest)) {

```

流是在`Files`类的帮助下创建的。

## 使用`FileChannel`的复制文件

`FileChannel`是用于读取，写入，映射和操作文件的通道。 `FileChannel`是经典 Java IO 流 API 的替代方法。 它位于`java.nio`程序包中。

`RandomAccessFile`支持读取和写入随机访问文件。 随机访问意味着我们可以在文件中的任何位置读取或写入信息。

`com/zetcode/CopyFileChannel.java`

```java
package com.zetcode;

import java.io.IOException;
import java.io.RandomAccessFile;

public class CopyFileChannel {

    public static void main(String[] args) throws IOException {

        var source = new RandomAccessFile("src/resources/bugs.txt", "r");
        var dest = new RandomAccessFile("src/resources/bugs2.txt", "rw");

        try (var sfc = source.getChannel();
             var dfc = dest.getChannel()) {

            dfc.transferFrom(sfc, 0, sfc.size());
        }
    }
}

```

该示例使用`FileChannel`复制文本文件。

```java
var source = new RandomAccessFile("src/resources/bugs.txt", "r");

```

创建读取模式下的随机访问文件。

```java
var dest = new RandomAccessFile("src/resources/bugs2.txt", "rw");

```

创建一个处于读/写模式的随机访问文件。

```java
try (var sfc = source.getChannel();
    var dfc = dest.getChannel()) {

```

我们使用`getChannel()`从文件中获取频道。

```java
dfc.transferFrom(sfc, 0, sfc.size());

```

`transferFrom()`方法将字节从源通道传输到目标通道。 第一个参数是源通道，第二个参数是文件中传输的开始位置，第三个参数是要传输的最大字节数。

## 用`Files.copy`复制文件

Java 7 引入了`Files.copy()`方法，该方法提供了一种复制文件的简便方法。 如果目标文件存在，则复制失败，除非指定了`REPLACE_EXISTING`选项。 `Files.copy()`采用可选的第三副本选项参数。

`options`参数可以包括以下任何一项：

*   `REPLACE_EXISTING` - 如果目标文件存在，则目标文件不是非空目录时，将替换目标文件。
*   `COPY_ATTRIBUTES` - 尝试将与此文件关联的文件属性复制到目标文件。
*   `ATOMIC_MOVE` - 移动文件。
*   `NOFOLLOW_LINKS` - 不遵循符号链接。

前三个选项在`StandarCopyOption`中可用； `LinkOption`中的最后一个。

`com/zetcode/CopyFileJava7.java`

```java
package com.zetcode;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

public class CopyFileJava7 {

    public static void main(String[] args) throws IOException {

        var source = new File("src/resources/bugs.txt");
        var dest = new File("src/resources/bugs2.txt");

        Files.copy(source.toPath(), dest.toPath(),
                StandardCopyOption.REPLACE_EXISTING);
    }
}

```

本示例使用`Files.copy()`复制文件。 如果目的地已经存在，它将替换目的地。

## 使用 Apache Commons IO 进行 Java 复制文件

Apache Commons IO 是一个工具库，可帮助开发 IO 功能。 它包含`FileUtils.copyFile()`方法来执行复制。 `FileUtils.copyFile()`将指定源文件的内容复制到指定目标文件中，并保留文件日期。 如果目标文件所在的目录不存在，则创建该目录。 如果目标文件存在，则此方法将覆盖它。

```java
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.5</version>
</dependency>

```

对于此示例，我们需要`commons-io`工件。

`com/zetcode/CopyFileApacheCommons.java`

```java
package com.zetcode;

import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;

public class CopyFileApacheCommons {

    public static void main(String[] args) throws IOException {

        var source = new File("src/main/resources/bugs.txt");
        var dest = new File("src/main/resources/bugs2.txt");

        FileUtils.copyFile(source, dest);
    }
}

```

该示例使用 Apache Commons 的`FileUtils.copyFile()`复制文件。

## 用 Guava Java 复制文件

Google Guava 是 Java 通用库的开源集。 它包括用于复制文件的`Files.copy()`。

```java
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.0-jre</version>
</dependency>

```

我们使用 Guava 依赖。

`com/zetcode/CopyFileGuava.java`

```java
package com.zetcode;

import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;

public class CopyFileGuava {

    public static void main(String[] args) throws IOException {

        var source = new File("src/main/resources/bugs.txt");
        var dest = new File("src/main/resources/bugs2.txt");

        Files.copy(source, dest);
    }
}

```

该示例使用 Guava 的`Files.copy()`复制文件。

在本教程中，我们展示了几种用 Java 复制文件的方法。 我们使用了内置工具和第三方库。 您可能也对相关教程感兴趣： [Java 文件教程](/java/file/)， [Java 创建目录](/java/createdirectory/)， [Java 文件大小](/java/filesize/)，[用 Java 创建文件](/java/createfile/) ，[用 Java 读取文本文件](/articles/javareadtext/)， [Apache `FileUtils`教程](/java/fileutils/)， [Java 教程](/lang/java/)。

列出[所有 Java 教程](/all/#java)。