Java压缩、复制文件及解压zip

本文介绍了一个基于Java8的文件操作工具类,包括文件压缩、解压、复制功能的实现,重点讲解了重载优化、内存占用控制以及后端压缩文件实时传给前端的示例。通过实例演示和性能测试,展示了如何提升运行效率和内存管理。


引言

该文件工具类基于java 8,实现了文件的压缩、解压以及复制等操作(无需引入其它的依赖即可使用);同时给出后端压缩文件传给前端的示例,以及重载、性能优化的思路,可以根据具体的业务需求自行重构和优化
 
如需浏览,请详见目录,即可快速定位到所需要的内容。之后将会持续修复Bug、并且更新、优化完善,如需及时收到最新内容,记得关注、收藏一下┗|`O′|┛ 嗷~~


一、完整代码

该工具类实现了文件的压缩、解压以及复制等操作,仅仅基于java 8,无需依赖其它Jar包!将以下内容直接复制,粘贴到项目中即可使用!

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * 文件工具
 *
 * @author JZY
 */
public class FileUtil {

    /**
     * 默认缓冲数组大小
     */
    private static final int DEFAULT_BUFFER_SIZE = 8192;

    /**
     * 保持结构
     */
    private static final boolean KEEP_STRUCTURE = true;

    /**
     * 保留空文件夹
     */
    private static final boolean KEEP_EMPTY_FOLDER = true;

    /**
     * 默认编码格式
     */
    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

    /**
     * 兼容性编码格式
     */
    private static final Charset COMPATIBLE_ENCODING = Charset.forName("GBK");

    /**
     * 获取不带后缀的文件名
     *
     * @param fileName 文件名
     * @return 不带后缀的文件名
     */
    public static String getFileNameWithoutSuffix(String fileName) {
        int endIndex = fileName.lastIndexOf(".");
        if (endIndex != -1) {
            return fileName.substring(0, endIndex);
        } else {
            return fileName;
        }
    }

    /**
     * 获取不带后缀的文件名
     *
     * @param file 文件
     * @return 不带后缀的文件名
     */
    public static String getFileNameWithoutSuffix(File file) {
        return getFileNameWithoutSuffix(file.getName());
    }

    /**
     * 获取文件后缀
     *
     * @param fileName 文件名
     * @return 文件后缀
     */
    public static String getFileSuffix(String fileName) {
        int endIndex = fileName.lastIndexOf(".");
        if (endIndex != -1) {
            return fileName.substring(endIndex + 1);
        } else {
            return null;
        }
    }

    /**
     * 获取文件后缀
     *
     * @param file 文件
     * @return 文件后缀
     */
    public static String getFileSuffix(File file) {
        return getFileSuffix(file.getName());
    }

    /**
     * 创建所有必须但不存在的父文件夹
     *
     * @param parentFolderPath 父文件夹路径
     * @throws IOException IO异常
     */
    public static void createParentFolder(String parentFolderPath) throws IOException {
        createParentFolder(new File(parentFolderPath));
    }

    /**
     * 创建所有必须但不存在的父文件夹
     *
     * @param parentFolder 父文件夹
     * @throws IOException IO异常:创建父文件夹(父目录)失败
     */
    public static void createParentFolder(File parentFolder) throws IOException {
        if (!parentFolder.exists()) {
            if (!parentFolder.mkdirs()) {
                throw new IOException("创建父文件夹(父目录)“" + parentFolder.getPath() + "”失败");
            }
        }
    }

    /**
     * 文件转字节数组
     *
     * @param file 文件
     * @return 字节数组
     * @throws IOException IO异常
     */
    public static byte[] fileToByte(File file) throws IOException {
        return fileToByte(file, new byte[DEFAULT_BUFFER_SIZE]);
    }

    /**
     * 文件转字节数组
     *
     * @param file 文件
     * @param bufferSize 缓冲区大小
     * @return 字节数组
     * @throws IOException IO异常
     */
    public static byte[] fileToByte(File file, int bufferSize) throws IOException {
        if (bufferSize <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        return fileToByte(file, new byte[bufferSize]);
    }

    /**
     * 文件转字节数组
     *
     * @param file 文件
     * @param buffer 缓冲区
     * @return 字节数组
     * @throws IOException IO异常
     */
    public static byte[] fileToByte(File file, byte[] buffer) throws IOException {
        try (
                FileInputStream fileInputStream = new FileInputStream(file);
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()
        ) {
            int length;
            while ((length = fileInputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, length);
            }
            byteArrayOutputStream.flush();
            return byteArrayOutputStream.toByteArray();
        }
    }

    /**
     * 复制文件
     *
     * @param sourceFile 源文件
     * @param targetFile 目标文件
     * @throws IOException IO异常
     */
    public static void copyFile(File sourceFile, File targetFile) throws IOException {
        copyFile(sourceFile, targetFile, new byte[DEFAULT_BUFFER_SIZE]);
    }

    /**
     * 复制文件
     *
     * @param sourceFile 源文件
     * @param targetFile 目标文件
     * @param bufferSize 缓冲区大小
     * @throws IOException IO异常
     */
    public static void copyFile(File sourceFile, File targetFile, int bufferSize) throws IOException {
        if (bufferSize <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        copyFile(sourceFile, targetFile, new byte[bufferSize]);
    }

    /**
     * 复制文件
     *
     * @param sourceFile 源文件
     * @param targetFile 目标文件
     * @param buffer 缓冲区
     * @throws IOException IO异常
     */
    public static void copyFile(File sourceFile, File targetFile, byte[] buffer) throws IOException {
        try (
                FileInputStream fileInputStream = new FileInputStream(sourceFile);
                FileOutputStream fileOutputStream = new FileOutputStream(targetFile)
        ) {
            int length;
            while ((length = fileInputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, length);
            }
            fileOutputStream.flush();
        }
    }

    /**
     * 复制文件夹
     *
     * @param sourceFolder 源文件夹
     * @param targetFolder 目标文件夹
     * @throws IOException IO异常
     */
    public static void copyFolder(File sourceFolder, File targetFolder) throws IOException {
        copyFolder(sourceFolder, targetFolder, new byte[DEFAULT_BUFFER_SIZE]);
    }

    /**
     * 复制文件夹
     *
     * @param sourceFolder 源文件夹
     * @param targetFolder 目标文件夹
     * @param bufferSize 缓冲区大小
     * @throws IOException IO异常
     */
    public static void copyFolder(File sourceFolder, File targetFolder, int bufferSize) throws IOException {
        if (bufferSize <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        copyFolder(sourceFolder, targetFolder, new byte[bufferSize]);
    }

    /**
     * 复制文件夹
     *
     * @param sourceFolder 源文件夹
     * @param targetFolder 目标文件夹
     * @param buffer 缓冲区
     * @throws IOException IO异常
     */
    public static void copyFolder(File sourceFolder, File targetFolder, byte[] buffer) throws IOException {
        copyFolderContent(sourceFolder, new File(targetFolder.getPath(), sourceFolder.getName()), buffer);
    }

    /**
     * 复制文件夹内容
     *
     * @param sourceFolder 源文件夹
     * @param targetFolder 目标文件夹
     * @throws IOException IO异常
     */
    public static void copyFolderContent(File sourceFolder, File targetFolder) throws IOException {
        copyFolderContent(sourceFolder, targetFolder, new byte[DEFAULT_BUFFER_SIZE]);
    }

    /**
     * 复制文件夹内容
     *
     * @param sourceFolder 源文件夹
     * @param targetFolder 目标文件夹
     * @param bufferSize 缓冲区大小
     * @throws IOException IO异常
     */
    public static void copyFolderContent(File sourceFolder, File targetFolder, int bufferSize) throws IOException {
        if (bufferSize <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        copyFolderContent(sourceFolder, targetFolder, new byte[bufferSize]);
    }

    /**
     * 复制文件夹内容
     *
     * @param sourceFolder 源文件夹
     * @param targetFolder 目标文件夹
     * @param buffer 缓冲区
     * @throws IOException IO异常
     */
    public static void copyFolderContent(File sourceFolder, File targetFolder, byte[] buffer) throws IOException {
        if (sourceFolder.isDirectory()) {
            createParentFolder(targetFolder);
            File[] files = sourceFolder.listFiles();
            if (files != null && files.length > 0) {
                String sourceFolderPath = sourceFolder.getPath();
                String targetFolderPath = targetFolder.getPath();
                String fileName;
                for (File file : files) {
                    fileName = file.getName();
                    copyFolderContent(new File(sourceFolderPath, fileName), new File(targetFolderPath, fileName), buffer);
                }
            }
        } else {
            copyFile(sourceFolder, targetFolder, buffer);
        }
    }

    /**
     * 压缩文件
     *
     * @param sourceFile 源文件
     * @param targetFile 目标文件
     * @throws IOException IO异常
     */
    public static void compressFile(File sourceFile, File targetFile) throws IOException {
        compressFile(sourceFile, targetFile, new byte[DEFAULT_BUFFER_SIZE]);
    }

    /**
     * 压缩文件
     *
     * @param sourceFile 源文件
     * @param targetFile 目标文件
     * @param bufferSize 缓冲区大小
     * @throws IOException IO异常
     */
    public static void compressFile(File sourceFile, File targetFile, int bufferSize) throws IOException {
        if (bufferSize <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        compressFile(sourceFile, targetFile, new byte[bufferSize]);
    }

    /**
     * 压缩文件
     *
     * @param sourceFile 源文件
     * @param targetFile 目标文件
     * @param buffer 缓冲区
     * @throws IOException IO异常
     */
    public static void compressFile(File sourceFile, File targetFile, byte[] buffer) throws IOException {
        try (
                FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
                ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream, DEFAULT_ENCODING)
        ) {
            compressFile(sourceFile, sourceFile.getName(), buffer, zipOutputStream);
        }
    }

    /**
     * 压缩文件
     *
     * @param sourceFile 源文件
     * @param fileName 文件名
     * @param zipOutputStream Zip输出流
     * @throws IOException IO异常
     */
    public static void compressFile(File sourceFile, String fileName, ZipOutputStream zipOutputStream) throws IOException {
        compressFile(sourceFile, fileName, new byte[DEFAULT_BUFFER_SIZE], zipOutputStream);
    }

    /**
     * 压缩文件
     *
     * @param sourceFile 源文件
     * @param fileName 文件名
     * @param buffer 缓冲区
     * @param zipOutputStream Zip输出流
     * @throws IOException IO异常
     */
    public static void compressFile(File sourceFile, String fileName, byte[] buffer, ZipOutputStream zipOutputStream) throws IOException {
        try (
                FileInputStream fileInputStream = new FileInputStream(sourceFile)
        ) {
            zipOutputStream.putNextEntry(new ZipEntry(fileName));
            int length;
            while ((length = fileInputStream.read(buffer)) != -1) {
                zipOutputStream.write(buffer, 0, length);
            }
            zipOutputStream.flush();
        }
    }

    /**
     * 压缩文件夹
     *
     * @param sourceFolder 源文件夹
     * @param targetFile 目标文件
     * @throws IOException IO异常
     */
    public static void compressFolder(File sourceFolder, File targetFile) throws IOException {
        compressFolder(sourceFolder, targetFile, new byte[DEFAULT_BUFFER_SIZE], KEEP_STRUCTURE, KEEP_EMPTY_FOLDER);
    }

    /**
     * 压缩文件夹
     *
     * @param sourceFolder 源文件夹
     * @param targetFile 目标文件夹
     * @param bufferSize 缓冲区大小
     * @param keepStructure 保持结构(如不保持结构,则所有文件、文件夹均在压缩包的根目录下)
     * @param keepEmptyFolder 保留空文件夹
     * @throws IOException IO异常
     */
    public static void compressFolder(File sourceFolder, File targetFile, int bufferSize, boolean keepStructure, boolean keepEmptyFolder) throws IOException {
        compressFolder(sourceFolder, targetFile, new byte[bufferSize], keepStructure, keepEmptyFolder);
    }

    /**
     * 压缩文件夹
     *
     * @param sourceFolder 源文件
     * @param targetFile 目标文件
     * @param buffer 缓冲区
     * @param keepStructure 保持结构(如不保持结构,则所有文件、文件夹均在压缩包的根目录下)
     * @param keepEmptyFolder 保留空文件夹
     * @throws IOException IO异常
     */
    public static void compressFolder(File sourceFolder, File targetFile, byte[] buffer, boolean keepStructure, boolean keepEmptyFolder) throws IOException {
        try (
                FileOutputStream fileOutputStream = new FileOutputStream(targetFile)
        ) {
            ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream);
            compressFolder(sourceFolder, "", buffer, zipOutputStream, keepStructure, keepEmptyFolder);
        }
    }

    /**
     * 压缩文件夹
     *
     * @param sourceFolder 源文件
     * @param fileName 文件名
     * @param zipOutputStream Zip输出流
     * @throws IOException IO异常
     */
    public static void compressFolder(File sourceFolder, String fileName, ZipOutputStream zipOutputStream) throws IOException {
        compressFolder(sourceFolder, fileName, new byte[DEFAULT_BUFFER_SIZE], zipOutputStream, KEEP_STRUCTURE, KEEP_EMPTY_FOLDER);
    }

    /**
     * 压缩文件夹
     *
     * @param sourceFolder 源文件
     * @param fileName 文件名
     * @param buffer 缓冲区
     * @param zipOutputStream Zip输出流
     * @throws IOException IO异常
     */
    public static void compressFolder(File sourceFolder, String fileName, byte[] buffer, ZipOutputStream zipOutputStream) throws IOException {
        compressFolder(sourceFolder, fileName, buffer, zipOutputStream, KEEP_STRUCTURE, KEEP_EMPTY_FOLDER);
    }

    /**
     * 压缩文件夹
     *
     * @param sourceFolder 源文件
     * @param fileName 文件名
     * @param buffer 缓冲区
     * @param zipOutputStream Zip输出流
     * @param keepStructure 保持结构(如不保持结构,则所有文件、文件夹均在压缩包的根目录下)
     * @param keepEmptyFolder 保留空文件夹
     * @throws IOException IO异常
     */
    public static void compressFolder(File sourceFolder, String fileName, byte[] buffer, ZipOutputStream zipOutputStream, boolean keepStructure, boolean keepEmptyFolder) throws IOException {
        if (sourceFolder.isDirectory()) {
            if (keepEmptyFolder) {
                zipOutputStream.putNextEntry(new ZipEntry(fileName + "/"));
            }
            File[] files = sourceFolder.listFiles();
            if (files != null && files.length > 0) {
                String currentFileName;
                String newFileName;
                for (File file : files) {
                    currentFileName = file.getName();
                    newFileName = fileName;
                    if (keepStructure) {
                        newFileName = newFileName + File.separator + currentFileName;
                    }
                    compressFolder(new File(sourceFolder.getPath(), currentFileName), newFileName, buffer, zipOutputStream, keepStructure, keepEmptyFolder);
                }
            }
        } else {
            compressFile(sourceFolder, fileName, buffer, zipOutputStream);
        }
    }

    /**
     * 解压
     *
     * @param sourceCompressFile 源压缩文件
     * @param targetFolder 目标文件夹
     * @throws IOException IO异常
     */
    public static void decompress(File sourceCompressFile, File targetFolder) throws IOException {
        decompress(sourceCompressFile, targetFolder, new byte[DEFAULT_BUFFER_SIZE]);
    }

    /**
     * 解压缩
     *
     * @param sourceCompressFile 源压缩文件
     * @param targetFolder 目标文件夹
     * @param bufferSize 缓冲区大小
     * @throws IOException IO异常
     */
    public static void decompress(File sourceCompressFile, File targetFolder, int bufferSize) throws IOException {
        if (bufferSize <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        decompress(sourceCompressFile, targetFolder, new byte[bufferSize]);
    }

    /**
     * 解压缩
     *
     * @param sourceCompressFile 源压缩文件
     * @param targetFolder 目标文件夹
     * @param buffer 缓冲区
     * @throws IOException IO异常
     */
    public static void decompress(File sourceCompressFile, File targetFolder, byte[] buffer) throws IOException {
        try (
                FileInputStream fileInputStream = new FileInputStream(sourceCompressFile);
                ZipInputStream zipInputStream = new ZipInputStream(fileInputStream, COMPATIBLE_ENCODING)
        ) {
            createParentFolder(targetFolder);
            ZipEntry zipEntry = zipInputStream.getNextEntry();
            while (zipEntry != null) {
                if (zipEntry.getName().endsWith("/") || zipEntry.getName().endsWith("\\")){
                    File newFolder = new File(targetFolder.getPath(), zipEntry.getName());
                    createParentFolder(newFolder);
                }else {
                    decompress(new File(targetFolder.getPath(), zipEntry.getName()), buffer, zipInputStream);
                }
                zipEntry = zipInputStream.getNextEntry();
            }
        }
    }

    /**
     * 解压缩
     *
     * @param targetFile 目标文件
     * @param buffer 缓冲区
     * @param zipInputStream Zip输入流
     * @throws IOException IO异常
     */
    public static void decompress(File targetFile, byte[] buffer, ZipInputStream zipInputStream) throws IOException {
        try (
                FileOutputStream fileOutputStream = new FileOutputStream(targetFile)
        ) {
            int length;
            while ((length = zipInputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, length);
            }
            fileOutputStream.flush();
        }
    }
}

二、优化

逻辑优化

方法重载、复用优化

该工具类针对可能存在的引用情况给出了不同的重载,具体使用方法可以根据每个方法前面的注释以及方法所要接收的参数类型了解(实际使用时可以根据情况自行重构)
 
其中,针对实际的使用需求:很多时候前端需要直接接收一个已经打包压缩好的文件/文件夹(譬如多个报表电子档的生成处理),但是后端这边仅仅只有源文件,还没有已经打包好的压缩包,如何操作?
 
通常的操作是先将文件/文件夹在服务器的磁盘上打包压缩好,再以压缩包文件的形式传给前端,最后再把压缩包删除;但是通过具体分析,可以看出这样的操作对于服务器的性能是不必要的损耗,并且会占用大量的磁盘I/O;反之,应当是边读取文件,边打包压缩,边发给前端,而且要注意的是不能一次性打包压缩完成后再发送,因为一次性打包压缩好的所有字节数据会全部暂存在内存中,这样的话占用大量的内存,而且倘若文件较大,将会频繁触发服务器的GC机制(如果是处理超大文件,则耗时较长,甚至会过多地触发Full GC,那么对于服务器而言是灾难性的,甚至有可能宕机)
 
为此在压缩文件方法中,特别给出了传入参数含有ZipOutputStream的重载方法(当然实际使用中,需要根据具体的业务需求分析,进而自行重构或优化)

后端压缩文件传给前端示例

这边以SSM的请求处理为例,使用其他框架,如SpringBoot等都是一样的,直接调用即可(前端可以在接受到数据流(即二进制数据)后将其转换为文件)

@PostMapping(path = "/file/download/compressFiles", produces = "application/json; charset=UTF-8")
public void downloadCompressFiles(HttpServletResponse response) throws IOException {
    String filesPath = "E:\\IntelliJ IDEA\\IdeaProjects\\Template\\Template_SSM\\SSM\\src\\main\\webapp\\static\\image";
    compress(filesPath, response);
}

public void compress(String compressPath, HttpServletResponse response) throws IOException {
    File file = new File(compressPath);
    if (file.exists()) {
        response.setContentType("application/octet-stream; charset=UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(FileUtil.getFileNameWithoutSuffix(file).concat(".zip"), "UTF-8"));
        try (
            	OutputStream outputStream = response.getOutputStream();
            	ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)
        ) {
            if (file.isFile()) {
                FileUtil.compressFile(file, file.getName(), zipOutputStream);
            } else {
                FileUtil.compressFolder(file, "", zipOutputStream);
            }
            outputStream.flush();
        }
    } else {
        response.sendError(404, "缺少资源,无法下载");
    }
}

资源关闭优化

因为该工具类是基于Java 8编写的,为此使用了早在JDK 1.7中就已经引入的try-with-resource语法糖,使得整体代码编写较为简洁,尤其在多个资源流的使用中(要注意的是,想要通过try-with-resource语法糖自动管理,其资源流必须实现了AutoCloseable)
 
例如:

public static void copyFile(File sourceFile, File targetFile, byte[] buffer) throws IOException {
    try (
        	FileInputStream fileInputStream = new FileInputStream(sourceFile);
        	FileOutputStream fileOutputStream = new FileOutputStream(targetFile)
    ) {
        int length;
        while ((length = fileInputStream.read(buffer)) != -1) {
            fileOutputStream.write(buffer, 0, length);
        }
        fileOutputStream.flush();
    }
}

性能优化

运行效率优化

为避免一个字节一个字节的读取或写入,频繁地访问文件,从而导致严重影响性能,此工具类的所有操作均使用了缓冲数组;在Java 8中,查看源码可知:private static int DEFAULT_BUFFER_SIZE = 8192; 即默认的缓冲数组大小是8192B = 8KB
 
为此在本工具类中使用的缓冲数组大小默认也为8KB(当然实际使用中,可以根据具体的业务需求自行优化,决定使用的缓冲数组大小——理论上对于一个100M以上的文件,缓冲数组越大,执行操作的耗时也就越低;但是当缓冲数组大小提高到一定阈值后,缓冲数组对于内存的开销也就不容忽视了,甚至会带来负面影响;根据实际情况选择缓冲数组大小才是明智的)

内存占用优化

在多文件、文件夹的循环复制、压缩以及解压的测试下,发现了一个问题:如果每次都去调用单个文件的处理方法,如public static void copyFile(File sourceFile, File targetFile),那么就会多次创建缓冲数组,然而操作每个文件时创建的缓冲数组在此文件操作完毕后,无法再度利用,只能等待被回收(较长时间、大量文件/文件夹处理,可能会多次触发服务器的GC机制),那么对于性能的消耗也是不容小觑的!

复制4096个文件/文件夹(每个文件/文件夹大小在1MB - 10MB不等)
在这里插入图片描述
可以看出整体内存使用量在100 - 110MB左右(中途JVM执行了一次内存回收)


当采用优化后的方法:public static void copyFile(File sourceFile, File targetFile, byte[] buffer)只申请一次缓冲数组,对于后面所有的递归调用都将缓冲数组当做参数传入,循环利用缓冲数组进行相关的文件/文件夹操作)
在这里插入图片描述
可以看出整体内存使用量降低到60-70MB左右(中途JVM执行了一次内存回收),少去的部分正好是(4096 - 1) * 8KB = 32760KB,约为32MB,并且还省去了频繁申请内存的操作,可以提高运行速度5% - 10%左右,而且当复制、压缩、解压的文件/文件夹越多的时候,所带来的内存占用影响越小、提升运行效率越明显

三、验证测试

先定义一些测试数据和记录运行时间的方法

String fileName = "10M.zip";

String sourceFilePath = "D:\\测试\\复制\\文件\\源文件存放位置\\" + fileName;

String targetFilePath = "D:\\测试\\复制\\文件\\目标文件存放位置\\" + fileName;

String sourceFolderPath = "D:\\测试\\复制\\文件夹\\源文件夹";

String targetFolderPath = "D:\\测试\\复制\\文件夹\\目标文件夹";

String targetFolderContentPath = "D:\\测试\\复制\\文件夹\\文件夹内容存放位置";

String sourceCompressFilePath = "D:\\测试\\压缩\\文件\\电影.mp4";

String targetCompressFilePath = "D:\\测试\\压缩\\文件\\电影.zip";

String sourceCompressFolderPath = "D:\\测试\\压缩\\文件夹\\压缩文件夹";

String targetCompressFolderPath = "D:\\测试\\压缩\\文件夹\\压缩文件夹.zip";

String sourceDecompressFilePath = "D:\\测试\\解压\\待解压.zip";

String targetDecompressFolderPath = "D:\\测试\\解压\\已解压";

File sourceFile = new File(sourceFilePath);

File targetFile = new File(targetFilePath);

File sourceFolder = new File(sourceFolderPath);

File targetFolder = new File(targetFolderPath);

File targetFolderContent = new File(targetFolderContentPath);

File sourceCompressFile = new File(sourceCompressFilePath);

File targetCompressFile = new File(targetCompressFilePath);

File sourceCompressFolder = new File(sourceCompressFolderPath);

File targetCompressFolder = new File(targetCompressFolderPath);

File sourceDecompressFile = new File(sourceDecompressFilePath);

File targetDecompressFolder = new File(targetDecompressFolderPath);

long startTime = 0;

long endTime = 0;

@BeforeEach
void setUp() {
    startTime = System.currentTimeMillis();
}

@AfterEach
void tearDown() {
    endTime = System.currentTimeMillis();
    System.out.println("本次操作用时:" + (endTime - startTime));
}

操作用时的单位为ms
物理磁盘中实际存储的内容(测试的磁盘为普通机械磁盘,转速5400r/s)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试 getFileNameWithoutSuffix()

@Test
void getFileNameWithoutSuffix() {
    System.out.println(FileUtil.getFileNameWithoutSuffix(sourceFile));
}

测试结果符合预期
在这里插入图片描述

测试 getFileSuffix()

@Test
void getFileSuffix() {
    System.out.println(FileUtil.getFileSuffix(sourceFile));
}

测试结果符合预期
在这里插入图片描述

测试 fileToByte()

@Test
void fileToByte() {
    try {
        System.out.println(FileUtil.fileToByte(sourceFile).length + "B");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

测试结果符合预期
在这里插入图片描述

测试 copyFile()

@Test
void copyFile() {
    try {
        FileUtil.copyFile(sourceFile, targetFile);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

测试结果符合预期

在这里插入图片描述
在这里插入图片描述

测试 copyFolder()

@Test
void copyFolder() {
    try {
        FileUtil.copyFolder(sourceFolder, targetFolder);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

测试结果符合预期

在这里插入图片描述
在这里插入图片描述

测试 copyFolderContent()

@Test
void copyFolderContent() {
    try {
        FileUtil.copyFolderContent(sourceFolder, targetFolderContent);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

测试结果符合预期

这里是引用
在这里插入图片描述

测试 compressFile()

@Test
void compressFile() {
    try {
        FileUtil.compressFile(sourceCompressFile, targetCompressFile);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

测试结果符合预期

这里是引用
在这里插入图片描述

测试 compressFolder()

@Test
void compressFolder() {
    try {
        FileUtil.compressFolder(sourceCompressFolder, targetCompressFolder);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

测试结果符合预期

这里是引用
在这里插入图片描述

测试 decompress()

@Test
void decompress() {
    try {
        FileUtil.decompress(sourceDecompressFile, targetDecompressFolder);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

测试结果符合预期

在这里插入图片描述
这里是引用

四、温馨提示

文件剪切操作

实现文件剪切操作,乍看之下,很简单嘛:先把文件复制过去,在把源文件删除…只能说,没错,也能实现需要的功能,但是这不是一个高效的处理办法!
 
可以自行去操作系统中,手动复制和剪切一个文件/文件夹到另一个目录下(前提是在同一个磁盘分区),可以发现执行时间明显不同(文件越大越明显),剪切操作似乎不管文件多大都一下子就处理完毕了(可以打开任务管理器查看对应磁盘在复制、剪切过程中传输速率的改变)
 
那是因为在操作系统中,不管文件/文件夹都是以文件的形式管理的,都是由索引进行维护的,那么移动文件/文件夹,仅仅需要更改其索引即可,无需实现在物理层面上的文件复制移动,在Java 8中提供了public boolean renameTo(File dest)来实现文件移动(处于同一磁盘分区的剪切操作则修改索引即可,跨磁盘分区的剪切操作则正常复制源文件/文件夹到目的地后,再删除源文件/文件夹)


免责申明:相关文章及资料仅供学习交流使用,禁止一切不正当行为,如由此产生相关责任,自行承担
 
Tip:如需转发或引用相关内容,请务必附带原链接


如果对你有帮助的话,麻烦关注一波,并且点赞、收藏、转发一下哦o( ̄︶ ̄)o!如果有问题或者发现Bug欢迎提出反馈!

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

6铭记6

打赏一下吧!^-^

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值