• Java文件操作之复制、压缩、解压


    Java文件操作之复制、压缩、解压

    一、文件复制

    1、通过文件流Stream对文件进行复制

    这种方式的文件复制主要是通过InputStream读取文件流,再将读取的文件流数据写入到新创建的文件中。

    /**
      * @Description 文件复制(使用Stream流操作)
      * @Return void
      * @Author Mr.Walloce
      * @Date 2019/8/24 15:15
      */
    public static void copyFileByStream(File srcFile, File tarFile) {
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(srcFile);
            output = new FileOutputStream(tarFile);
            byte[] bytes = new byte[byteLen];
            //字节长度
            int byteLen = 0;
            while (true) {
                //字节为空时,跳出循环
                if (!((byteLen = input.read(bytes)) > 0)) {
                    break;
                }
                //向目标文件写入流数据
                output.write(bytes, 0, byteLen);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } finally {
            if (output != null) {
                IOUtils.closeQuietly(output);
            }
            if (input != null) {
                IOUtils.closeQuietly(input);
            }
        }
    }
    

    2、通过FileChannel对文件进行复制

    FileChannel操作文件流时使用的是ByteBuffer缓存区,而InputStream/OutputStream文件操作使用的是byte[]数组,由于FileChannel使用的是ByteBuffer缓存区,所以性能上应该是优于InputStream/OutputStream的。

    /**
      * @Description 使用FileChannel对文件进行复制,其实质还是通过
      *              FileInputStream和FileOutStream对文件流进行操作
      * @param srcFile
      * @param targetFile
      * @Return void
      * @Author Mr.Walloce
      * @Date 2019/8/24 14:43
      */
    public static void copyFileByChannel(File srcFile, File targetFile) {
        FileChannel inputFileChannel = null;
        FileChannel outputFileChannel = null;
        try {
            inputFileChannel = new FileInputStream(srcFile).getChannel();
            outputFileChannel = new FileOutputStream(targetFile).getChannel();
            outputFileChannel.transferFrom(inputFileChannel, 0, inputFileChannel.size());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } finally {
            if (outputFileChannel != null) {
                IOUtils.closeQuietly(outputFileChannel);
            }
            if (inputFileChannel != null) {
                IOUtils.closeQuietly(inputFileChannel);
            }
        }
    }
    

    3、通过commons-io工具包提供的copy方法拷贝

    使用方法如下:

    • 引入jar包
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.2</version>
    </dependency>
    
    • 调用方法
    FileUtils.copyFile(srcFile, targetFile);
    
    • copy方法的源码
    /**
     * Internal copy file method.
     * 
     * @param srcFile  the validated source file, must not be <code>null</code>
     * @param destFile  the validated destination file, must not be <code>null</code>
     * @param preserveFileDate  whether to preserve the file date
     * @throws IOException if an error occurs
     */
    private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
        if (destFile.exists() && destFile.isDirectory()) {
            throw new IOException("Destination '" + destFile + "' exists but is a directory");
        }
    
        FileInputStream fis = null;
        FileOutputStream fos = null;
        FileChannel input = null;
        FileChannel output = null;
        try {
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);
            input  = fis.getChannel();
            output = fos.getChannel();
            long size = input.size();
            long pos = 0;
            long count = 0;
            while (pos < size) {
                count = size - pos > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : size - pos;
                pos += output.transferFrom(input, pos, count);
            }
        } finally {
            IOUtils.closeQuietly(output);
            IOUtils.closeQuietly(fos);
            IOUtils.closeQuietly(input);
            IOUtils.closeQuietly(fis);
        }
    
        if (srcFile.length() != destFile.length()) {
            throw new IOException("Failed to copy full contents from '" +
                    srcFile + "' to '" + destFile + "'");
        }
        if (preserveFileDate) {
            destFile.setLastModified(srcFile.lastModified());
        }
    }
    

    由以上源码可以看出FileUtils.copy(srcFile, targetFile)实际上使用的是FileChannel的方式进行文件拷贝。

    二、文件压缩

    文件压缩的方法有两种情况:

    • 压缩的对象是文件夹
    • 压缩的对象是文件
    1. 压缩对象是文件时,不需要考虑是否存在子项
     /**
      * @Description 压缩文件,将文件压缩在源文件所在的目录下
      * @param srcFilePath 要压缩的文件
      * @Return void
      * @Author Mr.Walloce
      * @Date 2019/8/11 15:16
      */
    public static void zipFile(String srcFilePath) {
        File srcFile = new File(srcFilePath);
        if (!srcFile.exists()){
            return;
        }
    
        FileOutputStream fos = null;
        ZipOutputStream zos = null;
        //获取到文件路径
        String zipFilePath = srcFile.getPath();
        //压缩文件的路径
        String destFilePath = zipFilePath.substring(0, zipFilePath.indexOf(".") + 1) + "zip";
        File dstFile = new File(destFilePath);
        try {
            //输出的文件
            fos = new FileOutputStream(dstFile);
            CheckedOutputStream cos = new CheckedOutputStream(fos, new CRC32());
            zos = new ZipOutputStream(cos);
            //数据写入
            writeDataToZip(srcFile, zos, "");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (zos != null) {
                IOUtils.closeQuietly(zos);
            }
            if (fos != null) {
                IOUtils.closeQuietly(fos);
            }
        }
    }
    
    /**
      * @Description 数据写入压缩文件
      * @param srcFile
      * @param zos
      * @param baseDir
      * @Return void
      * @Author Mr.Walloce
      * @Date 2019/8/28 17:18
      */
    private static void writeDataToZip(File srcFile, ZipOutputStream  zos, String baseDir) {
        BufferedInputStream bis = null;
        try {
            //源文件流
            bis = new BufferedInputStream(new FileInputStream(srcFile));
            //创建压缩文件实体
            String name = baseDir + srcFile.getName();
            ZipEntry entry = new ZipEntry(name);
            zos.putNextEntry(entry);
            int count;
            byte data[] = new byte[byteLen];
            //写入数据
            while ((count = bis.read(data, 0, byteLen)) != -1) {
                zos.write(data, 0, count);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                IOUtils.closeQuietly(bis);
            }
        }
    }
    

    2. 压缩对象是文件夹时,需要考虑文件夹层级和文件夹下的文件项

     /**
      * @Description 压缩一个文件夹下的所有文件
      * @param srcFilePath 
      * @Return void
      * @Author Mr.Walloce
      * @Date 2019/8/24 15:59
      */
    public static void zipFilePath(String srcFilePath) {
        System.out.println(srcFilePath);
        File srcFile = new File(srcFilePath);
        if (!srcFile.exists()) {
            System.out.println("文件路径错误!");
            return;
        }
        FileOutputStream fos = null;
        ZipOutputStream zos = null;
        //获取到文件路径
        String zipFilePath = srcFile.getPath();
        //压缩文件的路径
        String destFilePath = srcFile.getParent() +"\"+ zipFilePath.substring(zipFilePath.lastIndexOf("\") + 1) + ".zip";
        File dstFile = new File(destFilePath);
        try {
            fos = new FileOutputStream(dstFile);
            CheckedOutputStream cos = new CheckedOutputStream(fos,new CRC32());
            zos = new ZipOutputStream(cos);
            File[] files = srcFile.listFiles();
            //遍历文件压缩
            for (int i = 0; i < files.length; i++) {
                if (files[i].isDirectory()) {
                    zipDirectory(files[i], zos, files[i].getName() + "/");
                } else {
                    writeDataToZip(files[i], zos, "");
                }
            }
        }  catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (zos != null) {
                IOUtils.closeQuietly(zos);
            }
            if (fos != null) {
                IOUtils.closeQuietly(fos);
            }
        }
    }
    
    /**
      * @Description 遍历文件夹下的文件
      * @param directoryFile
      * @param zos
      * @param baseDir
      * @Return void
      * @Author Mr.Walloce
      * @Date 2019/8/28 18:05
      */
    private static void zipDirectory(File directoryFile, ZipOutputStream zos, String baseDir) {
        File[] files = directoryFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            if (files[i].isDirectory()) {
                zipDirectory(files[i], zos, baseDir + files[i].getName() + "/");
            } else {
                if (files[i].exists()) {
                    writeDataToZip(files[i], zos, baseDir);
                }
            }
        }
    }
    

    三、文件解压

    将需要解压的.zip文件解压到目标文件夹下。

     /**
      * @Description 解压文件
      * @param zipFile  需要解压的文件
      * @param unZipPath 文件解压后存放的路径
      * @Return void
      * @Author Mr.Walloce
      * @Date 2019/8/25 15:17
      */
    public static void unZipFile(File zipFile, String unZipPath) {
        File pathFile = new File(unZipPath);
        if(!pathFile.exists()){
            pathFile.mkdirs();
        }
        ZipFile zip = null;
        InputStream is = null;
        OutputStream os = null;
        try {
            zip = new ZipFile(zipFile);
            //遍历解压文件
            for(Enumeration entries = zip.entries();entries.hasMoreElements();){
                ZipEntry entry = (ZipEntry)entries.nextElement();
                String zipEntryName = entry.getName();
                is =  zip.getInputStream(entry);
                String outPath = (unZipPath+"/"+zipEntryName).replaceAll("\*", "/");;
                //判断路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
                if(!file.exists()){
                    file.mkdirs();
                }
                //判断文件全路径是否为文件夹
                if(new File(outPath).isDirectory()){
                    continue;
                }
                //解压后输出文件
                os = new FileOutputStream(outPath);
                byte[] buf1 = new byte[byteLen];
                int len;
                while((len = is.read(buf1)) > 0){
                    os.write(buf1,0,len);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                IOUtils.closeQuietly(is);
            }
            if (os != null) {
                IOUtils.closeQuietly(os);
            }
        }
    }
    

    **
    以上是我整理的一些对文件操作工具,仅供学习参考,如有错误希望能指出,大家共同学习进步!
    **

    初心回归,时光已逝!
  • 相关阅读:
    Qt中的 Size Hints 和 Size Policies
    __declspec,__cdecl,__stdcall区别和作用
    深入理解DLL文件
    TCP/IP TIME_WAIT状态原理
    Linux 网络编程 高级套接字
    OpenCV 图像处理学习笔记(一)
    C++运算符重载的规则
    WinSock异步IO模型之Select
    ASSER、VERIFY、TRACE详解
    VC++ 网络编程总结(二)
  • 原文地址:https://www.cnblogs.com/yin1361866686/p/11426902.html
Copyright © 2020-2023  润新知