Java文件拷贝工具类

系统的路径分隔符

1
String separator = FileSystems.getDefault().getSeparator();

耗时计算

1
2
3
long startTime=System.currentTimeMillis();
long endTime=System.currentTimeMillis();
long costTime=endTime-startTime;

按字节写文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//读取配置文件,获取文件上传路径
Path path = Paths.get("/text.txt");
if (!Files.exists(path)) {
Files.createDirectories(path);
}
//1.按字节一次写入,如果文件过大在实际项目中会造成内存溢出
byte[] bytes = file.getBytes();
Files.write(path, bytes);

//2.限制字节长度写入
File file = new File(path.toUri());
InputStream ins = file.getInputStream();
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();

文件夹拷贝

Files工具类中有个walkFileTree用来遍历文件

1
2
3
4
5
6
7
8
9

public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)
throws IOException
{
return walkFileTree(start,
EnumSet.noneOf(FileVisitOption.class),
Integer.MAX_VALUE,
visitor);
}

看上面注释得出start参数是要遍历文件的位置,visitor则是一个接口规定了遍历文件将要做的事情
而visitor有4个方法:

  • 访问文件前preVisitDirectory
  • 访问文件visitFile时
  • 访问文件失败时
  • 访问文件后visitFileFailed

因此在visitor考虑实现文件的拷贝,在构造visitor类时将拷贝输出的路径传入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class CopyFileTree extends SimpleFileVisitor<Path>{

private Path targetPath;
private Path sourcePath;

public CopyFileTree(Path targetPath, Path sourcePath){
this.targetPath=targetPath;
this.sourcePath=sourcePath;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path target=getTargetPath(file);
if (Files.exists(target)){
Files.delete(target);
}
Files.createDirectories(target.getParent());
Files.copy(file,target);
return FileVisitResult.CONTINUE;
}

...
}

文件夹压缩

FileOutputStream 将数据写入文件的输出流,用于写入原始字节流如图像数据。 要编写字符流,请考虑使用。

ZipOutputStream 压缩文件并生成压缩文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static void doZipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
//如果文件隐藏则跳过
if (fileToZip.isHidden()) {
return;
}
if (fileToZip.isDirectory()) {
//如果文件是
if (!fileName.endsWith(File.separator)) {
//Creates a new zip entry with the specified name.
fileName += File.separator;
}
//放入下一个队列
zipOut.putNextEntry(new ZipEntry(fileName));
zipOut.closeEntry();
File[] children = fileToZip.listFiles();
for (File childFile : children) {
doZipFile(childFile, fileName + File.separator + childFile.getName(), zipOut);
}
return;
}
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileName);
zipOut.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}

文件压缩目前只能通过递归来压缩了,这里要注意的就是递归的结束条件不要陷入死循环了

遇见的错误

Input length = 1
编码不是UTF-8却按UTF-8读取了
Files.readAllLines(filePath, StandardCharsets.UTF_8)

如果要继续深入了解的文件的操作可以继续研究NIO。