小编典典

用Java复制和移动文件,不同方法的解释和比较

java

我实现了文件操作功能,并且我注意到Java提供了多种复制和移动文件的技术。在下面可以找到代码片段,简要描述了这些方法:

方法1:

File from = new File(src.getPath());
File to = new File(dst.getPath());

from.renameTo(to);

方法2:

FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();

inChannel.transferTo(0, inChannel.size(), outChannel);

方法3:

InputStream in = getContentResolver().openInputStream(selectedImageUri);
OutputStream out = new FileOutputStream("/sdcard/wallpapers/" + wall);

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

while ((read = in.read(buffer)) != -1) {
    out.write(buffer, 0, read);
}

方法4:

import static java.nio.file.StandardCopyOption.*;

Files.copy(source, target, REPLACE_EXISTING);

所有这些方法都有效,但是我不知道何时应使用它们?从性能和可靠性的角度来看,每种方法的优缺点分别是什么?当我不得不优先使用一种技术而不是另一种技术时,是否有任何特定情况?


阅读 325

收藏
2020-11-26

共1个答案

小编典典

我们可以将您的四种方法分为两种类型:

  1. 使用内置的标准库方法(例如File.renameTo()Files.move())。
  2. 自己完成工作-通过将字节从源复制到目标。

首先,请注意,File它没有复制方法,因此在谈论复制时,对于内置的标准库方法只有一个选项。

另请注意,重命名时“自行完成工作”非常不好-
您将复制整个文件,然后删除旧文件。这不是一个好的或有效的方法。在大多数情况下,在同一个文件系统中重命名/移动只需要更改文件元数据而不实际接触内容,因此使用标准库确实要好得多。

因此,您有两种情况:

重命名

这些选项实际上使用File.renameTo()Files.move()。使用流和复制数据毫无意义。

File是过时的课程。它实际上不应该再使用了。为什么有一个很好的解释,可以概括为以下事实:File当任何标准方法都失败时,它不会为您提供任何信息,而Files当这种情况发生时,它会为您提供非常准确的异常。

复制中

您有两种选择-使用Files.copy()或“自己动手”方法之一。

到目前为止,如果要复制的是实际文件,则选择应为Files.copy()。无需重新发明轮子。它完全符合您的要求,并且有据可查,因此您不太可能偶然引入错误。是的,它非常有效。

Files.copy()依靠底层的“提供者”来进行操作。这意味着有专门的供应商(或操作系统)特定的类来执行对该文件系统最有效的操作。无论是Linux文件系统还是Windows文件系统,副本都将为此进行优化。甚至还有针对特殊情况的提供程序,例如zip文件,因此您可以使用Files.copy()-
复制zip,jar或war文件中的文件-如果尝试“自己动手”方法,则要复杂得多。

此外,Files.copy()检查许多在编写“自己的”副本时可能会忘记的事情。例如,您还记得检查过要读取的文件和要写入的文件是否不是同一文件吗?可能会造成严重的麻烦。Files.copy()可以。它检查权限,检查副本的目标是否是目录,依此类推。因此非常可靠。

那么,为什么您可以选择“自己做”呢?因为好,Java是一种通用语言。您可以选择读取文件,也 可以 选择写入文件,因此 可以
编写自己的“复制”方法。那并不意味着你应该。

请注意,在“方法3”中,“源”文件实际上不是文件!它是由Image
URI产生的,这意味着它可能是网络来源。当您的源文件不是文件,而是基于套接字,数据库BLOB,Web服务器请求等的流或通道时,您将无法真正使用Files.copy()。这是您需要编写自己的代码的地方。

实际上,Files还有从文件复制到OutputStream或从复制到文件的选项InputStream,因此,如果副本的一侧是流,另一侧是文件,则可以使用该选项。这将是可读,安全的,并抛出有意义的异常。

因此,编写您自己的副本:

  • 当您需要将数据从源移动到非文件的目标时,
  • 当您需要以某种方式过滤或处理数据,而不是将原样从源复制到目标时,
  • 当您使用Java 1.7之前的旧版本时。在这种情况下,频道可能比流更好。
2020-11-26