Java操作文件的日常总结(文件压缩,文件解压,递归删除文件,文件的下载保存)

您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦
💪🏻 1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精通
❤️ 2. Python爬虫专栏,系统性的学习爬虫的知识点。9.9元买不了吃亏,买不了上当 。python爬虫入门进阶
❤️ 3. Ceph实战,从原理到实战应有尽有。 Ceph实战
❤️ 4. Java高并发编程入门,打卡学习Java高并发。 Java高并发编程入门
😁 5. 社区逛一逛,周周有福利,周周有惊喜。码农飞哥社区,飞跃计划
全网同名【码农飞哥】欢迎关注,个人VX: wei158556

简介

文件的读写是日常开发中经常碰到的需求,熟练掌握文件的读写是每个Java开发者的基本功。本文将主要介绍常见的文件读写操作。
之前写过一篇Java IO的文章 Java IO基础(同步阻塞IO)

1. 文件的下载

文件的下载是指通过文件的url在网络中得到文件的输入流。
这里直接通过java自带的HttpURLConnection来从网络中获取文件流。

    public static InputStream downloadByUrl(String urlPath) {

        try {
            URL url = new URL(urlPath);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestProperty("Charset", "UTF-8");
            httpURLConnection.connect();
            return httpURLConnection.getInputStream();
        } catch (Exception e) {
            return null;
        }
    }

在请求的时候需要设置文件的编码是UTF-8。

2. 将下载到文件保存到本地

   /**
     * 下载文件并保存
     *
     * @param fileUrl  文件的url
     * @param fileName 文件的原始文件名
     * TARGET_DIR 是文件的保存目录,可以自行指定
     * @return
     * @Author 码农飞哥
     */
    public static String downloadAndSaveFile(String fileUrl, String fileName) throws IOException {
        if (StringUtils.isAnyBlank(fileUrl, fileName)) {
            return null;
        }
        //2.保存文件
        File file = new File(TARGET_DIR);
        if (!file.exists()) {
            file.mkdirs();
        }
        String[] fileNameStr = fileName.split(FileUtil.DOU_SUFFIX);
        String newFileName = fileNameStr[0] + "." + fileNameStr[1];
        File targetFile = new File(TARGET_DIR + "/" + newFileName);
        InputStream is = null;
        FileOutputStream fos = null;
        //1.下载文件
        try {
            is = downloadByUrl(fileUrl);
            fos = new FileOutputStream(targetFile);
            byte[] bufferByte = new byte[1024];
            int len;
            while ((len = is.read(bufferByte)) > 0) {
                fos.write(bufferByte, 0, len);
            }
            fos.flush();
        } finally {
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(fos);
        }
        return targetFile.getAbsolutePath();
    }

这里就是将文件下载下来并保存到本地,通过downloadByUrl 方法得到文件流,然后,定义输出流FileOutputStream 来将数据写入到目标文件中,在操作文件时一定要注意在finally代码块中关闭输入流和输出流。

3. 文件压缩

文件压缩的整体思路是:

  1. 指定待压缩的目录以及压缩文件名,定义zip文件的输出流zos。
  2. 如果文件是一个文件则向zos中添加一个zipEntry实体
  3. 将源目录下的文件数据写入zos中。
  4. 如果是空文件夹需要特殊处理
  5. 如果是非空文件夹,需要循环其子目录,递归压缩。
   /**
     * @param srcFile   需要压缩的文件目录
     * @param targetDir 压缩文件的目标路径
     * @return
     */
    public static void zipFile(File srcFile, String targetDir) {
        long start = System.currentTimeMillis();

        FileOutputStream out = null;
        ZipOutputStream zos = null;

        try {
            out = new FileOutputStream(new File(targetDir));
            zos = new ZipOutputStream(out);
            compress(srcFile, zos, srcFile.getName(), true);
            long end = System.currentTimeMillis();
            System.out.println("压缩完成,耗时:" + (end - start) + " ms");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (zos != null) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            IOUtils.closeQuietly(out);
        }
    }

    /**
     * 递归压缩方法
     *
     * @param sourceFile       源文件
     * @param zos              zip输出流
     * @param name             压缩后的名称
     * @param keepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean keepDirStructure) throws IOException {
        byte[] buf = new byte[1024];
        if (sourceFile.isFile()) {
            //向zip输出流中添加一个zip实体,构造器name为zip实体文件的名字
            zos.putNextEntry(new ZipEntry(name));
            //copy文件到zip输出流中
            int len;
            FileInputStream in = null;
            try {
                in = new FileInputStream(sourceFile);
                while ((len = in.read(buf)) > 0) {
                    zos.write(buf, 0, len);
                }
                zos.flush();
            } finally {
                zos.closeEntry();
                IOUtils.closeQuietly(in);
            }
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 判断是否需要保留原来的文件结构时,需要对空文件夹进行处理
                if (keepDirStructure) {
                    //空文件夹的处理
                    zos.putNextEntry(new ZipEntry(name + "/"));
                    // 没有文件,不需要文件的copy
                    zos.closeEntry();
                }
            } else {
                for (File file : listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (keepDirStructure) {
                        // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
                        // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
                        compress(file, zos, name + "/" + file.getName(), keepDirStructure);
                    } else {
                        compress(file, zos, file.getName(), keepDirStructure);
                    }
                }
            }

        }
    }

4. 文件解压

通过ZipFile来读取压缩包,整体思路就是:

  1. 首先定义好解压之后的目录,一般就是跟zip文件的同名目录。
  2. 定义ZipFile对象,不过需要指定编码gbk,不然可能会出现中文乱码的情况
  3. 通过 zfile.entries() 获取zipFile对象下的所有元素,通过 zList.hasMoreElements() 是否为true不断循环读取
  4. 通过 zList.nextElement() 获取压缩包里zipEntry实体,这个实体可能是文件也可能是目录
  5. 通过 newFile(destDir, zipEntry) 方法来创建zipEntry实体的父目录。
  6. 如果zipEntry对象是目录的话,则直接返回
  7. 如果zipEntry对象是文件的话,则需要将该文件的数据写入到本地。需要注意的是输入流和输出流用完之后需要立马在finally代码块中关闭掉。
//zipFileDir: zip文件的绝对路径
  public static String unzipFile(String zipFileDir) throws IOException {
        //接收解压后的存放路径, 兼容文件名带多个点的情况
        String targetDir = zipFileDir.substring(0, zipFileDir.indexOf(".zip"));
        File destDir = new File(targetDir);
        if (!destDir.exists()) {
            destDir.mkdirs();
        }
        ZipFile zfile = null;
        byte[] buffer = new byte[1024];
        InputStream fis = null;
        ZipEntry zipEntry;
        FileOutputStream fos = null;
        try {
            //指定编码,防止由于中文导致的MALFORMED问题
            zfile = new ZipFile(zipFileDir, Charset.forName("gbk"));
            Enumeration zList = zfile.entries();
            // 遍历压缩包中的所有元素
            while (zList.hasMoreElements()) {
                zipEntry = (ZipEntry) zList.nextElement();
                //创建子目录
                File newFile = newFile(destDir, zipEntry);
                //文件夹的话就继续
                if (zipEntry.isDirectory()) {
                    continue;
                }
                try {
                    fis = new BufferedInputStream(zfile.getInputStream(zipEntry));
                    fos = new FileOutputStream(newFile);
                    int len;
                    while ((len = fis.read(buffer)) > 0) {
                        fos.write(buffer, 0, len);
                    }
                    //放在循环外效率更高
                    fos.flush();
                } finally {
                    IOUtils.closeQuietly(fos);
                    IOUtils.closeQuietly(fis);
                }
            }
        } finally {
            if (zfile != null) {
                try {
                    zfile.close();
                } catch (IOException e) {
                }
            }
        }
        return targetDir;
    }
    //创建子目录
   private static File newFile(File destinationDir, ZipEntry zipEntry) {
        File destFile = new File(destinationDir, zipEntry.getName());
        String destFilePath = destFile.getParent();
        File file = new File(destFilePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        return destFile;
    }

5. 递归删除文件

本地文件或者文件夹使用完成之后,如果不需要的话,则需要删除掉,java不能直接删除一个非空的目录,只能通过递归的方式循环删除目录下的所有文件才能删除外层的目录。

//targetFile 需要递归删除的目录
  public static void deleteFile(File targetFile) {
        if (!targetFile.exists()) {
            return;
        }
        //如果是文件直接删除
        if (targetFile.exists() && targetFile.isFile()) {
            targetFile.delete();
            return;
        }
        File[] filesArray = targetFile.listFiles();
        if (filesArray == null || filesArray.length <= 0) {
            return;
        }
        for (File file : filesArray) {
            //如果是文件或者该目录没有子目录,就删除
            if (file.isFile() || file.listFiles().length <= 0) {
                file.delete();
            } else if (file.isDirectory()) {
                //递归删除
                deleteFile(file);
            }
        }
        //清空目录
        targetFile.delete();
    }

或者直接使用 org.apache.commons.io.FileUtils 类,调用其deleteDirectory 方法删除目录。调用方式是: FileUtils.deleteDirectory(new File(targetDir));

6. 最终的测试

    public static void main(String[] args) throws IOException {
        /** 测试压缩方法1  */
        zipFile(new File("D:\\测试"), "D:/test.zip");
        
        String fileName = "D:/test.zip";
       unzipFile(fileName);

        String targetDir = "D:\\测试";
        File file = new File(targetDir);
        FileUtil.deleteFile(file);
    }

总结

本文详细介绍了文件的下载保存,压缩以及解压,希望对读者朋友们有所帮助。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
解压失败可能有多种原因,以下是一些可能的原因和解决方法: 1. 压缩包损坏:首先,检查下载压缩包是否完整且没有损坏。可以尝试重新下载压缩包,并确保下载过程中没有中断或出错。 2. 压缩包格式不受支持:确保使用的解压工具支持压缩包的格式。常见的压缩格式包括ZIP、RAR、7z等。如果使用的解压工具不支持该格式,可以尝试使用其他支持该格式的工具。 3. 解压路径权限问题:检查解压路径是否具有足够的权限来解压文件。如果解压路径是受限制的目录,可能需要以管理员身份运行解压工具或将解压路径更改为具有适当权限的目录。 4. 解压工具版本问题:有时,解压工具的版本可能不兼容压缩包。尝试更新解压工具到最新版本,并再次尝试解压文件。 5. 文件名或路径包含非法字符:检查压缩包中的文件名和路径是否包含非法字符,例如特殊字符或空格。尝试将压缩解压到一个简单的路径,例如根目录或没有特殊字符的文件夹。 如果以上方法都无法解决问题,可能需要进一步调查压缩包的来源和内容,以确定是否存在其他问题。 #### 引用[.reference_title] - *1* *2* *3* [Java操作文件日常总结文件压缩文件解压递归删除文件文件下载保存)](https://blog.csdn.net/u014534808/article/details/125111422)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

码农飞哥

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值