压缩流&解压缩流

解压缩流

Java中只能识别格式为zip的压缩包。

其实压缩包中的每一个文件或者文件夹都是一个ZipEntry对象,解压其实就是把每一个ZipEntry对象读取出来并放到对应的目录下。

我知道了,要是压缩的文件里有中文,记得创建ZipInputStream的时候设置解码规则为GBK。

下面是ZipEntry对象的转换为字符串后的样子,经过观察可以发现,在遍历时一定是先遍历文件夹,然后再是文件夹下的内容,所以不会出现某个文件的父级目录不存在的情况。

下面是解压某个压缩包的代码: 

关于解压缩流中如何读取某个文件中数据?只需要调用流中的read方法就可以了。

public class ZIO1 {
    public static void main(String[] args) throws IOException {
        File src = new File("D:\\Java学习资料\\day29-IO(其他流)\\资料.zip");
        File dest = new File("bbb");
        unzip(src, dest);

    }
    public static void unzip(File src, File dest) throws IOException {
        // 首先获取解压缩流
        ZipInputStream zis = new ZipInputStream(new FileInputStream(src), Charset.forName("GBK"));
        ZipEntry zipEntry;
        // 依次读取解压缩包下的每一个文件或者文件夹
        while ((zipEntry = zis.getNextEntry()) != null) {
            // 文件夹
            if (zipEntry.isDirectory()) {
                File file = new File(dest, zipEntry.toString());
                file.mkdirs();
            } else { // 文件
                FileOutputStream fos = new FileOutputStream(new File(dest, zipEntry.toString()));
                int b;
                while ((b = zis.read()) != -1) {
                    fos.write(b);
                }
                fos.close();
                zis.closeEntry();
            }
        zis.close();
        }
    }
}

压缩流

压缩流属于输出流。

关于压缩流主要就是创建ZipEntry对象时new ZipEntry(path2);的参数,搞不明白了也就知道怎么回事了。

1、压缩单个文件
  1. 首先创建压缩包的路径;
  2. 然后把文件变成ZipEntry对象;
  3. 再调用putZipEntry()方法放到压缩包里面,这一步其实只是创建了一个空的文件或者文件夹;
  4. 接着创建输入流读取文件中的内容;
  5. 最后利用压缩流写入文件或者文件夹的内容。

代码实现:

public class ZIO2 {
    public static void main(String[] args) throws IOException {
        File src = new File("bbb//123.txt");
        File dest = new File("bbb");
        zip(src, dest);
    }

    private static void zip(File src, File dest) throws IOException {
        String path1 = dest + "/" + src.getName().split("\\.")[0] + ".zip";
        // 压缩流的路径
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(path1)));
        String path2 = src.getName().split("\\.")[0] + "/" + src.getName();
        // 转换为ZipEntry对象
        ZipEntry zip = new ZipEntry(path2);
        zos.putNextEntry(zip);
        // 读取的文件路径
        FileInputStream fis = new FileInputStream(src);
        // 要写入的文件路径,不需要再创建,直接写入压缩流就可以
        int b;
        while ((b = fis.read()) != -1) {
            zos.write(b);
        }
        fis.close();
        zos.closeEntry();
        zos.close();
    }
}
2、压缩文件夹

假设拿到a.txt就创建a.txt的ZipEntry对象放到压缩包中,再读a.txt的数据写进去啊,这个过程结束了,循环才结束去读下一个b.txt啊。

问题1:刚开始访问的是当前模块下的com/liu/PIO包,但是使用listFiles方法获取这个包下的所有内容时值总是为null,截图如下,也不知道为什么,后面干脆就换了其他的包进行压缩。

问题2:在 Java 中,推荐使用 File.separator 或者直接使用正斜杠 / 作为路径分隔符,以避免跨平台问题和转义字符的困扰。修改为:

String path2 = dest.getPath() + File.separator + file.getName();

或者更简单地使用正斜杠:

String path2 = dest.getPath() + "/" + file.getName();

问题3:压缩文件夹需要递归,所以要把创建压缩包的代码放到递归外面进行实现。 

所以刚开始我只是把压缩包所表示的路径放到主函数中了,然后压缩流还是放到递归中去,想着每次递归都创建一个新的压缩流,但实际并不是这样,因为压缩流并不是这样使用的。

        // 目的文件夹
        String path = "bbb";
        // 压缩包的路径
        File dest = new File(path, src.getName() + ".zip");

所以后面在运行时会报错。比如ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("bbb\\bbb\\123"));就会出错,格式不正确,因为压缩流在创建时构造方法的参数需为.zip格式的字符串。

所以正确的其实应该放到递归方法的外面。

问题4:压缩方法的3个参数,刚开始我是这样写的,传递的是目标文件夹的路径,但是在实际运行过程中发现总是出现名字为aaa.zip这样的普通文件夹,一直也找不到问题所在,最终发现是对压缩流的new ZipEntry(path2)方法不熟悉,这个方法会在压缩路径的基础上创建文件夹的。

private static void zip(ZipOutputStream zos, File src, File dest) throws IOException {

        ...
        String path2 = dest.getPath() + "\\" + file.getName();
        // 转换为ZipEntry对象
        ZipEntry zip = new ZipEntry(path2);
}

或者2个参数也行吧。 答案是不行,因为在使用new ZipEntry这个方法时要给出相对压缩包里面的完整路径路径,所以要用一个name变量进行存储。

问题5:文件夹是什么时候创建的?

答案是创建ZipEntry对象时new ZipEntry(path2);的参数,比如给定的path2的值为bbb/ccc/123.txt,那么就会在压缩包下的路径创建bbb/ccc/123.txt这么些个文化夹和文件,因为空的文件夹并不会被压缩。

下面是完整的代码实现:

public class ZIO3 {
    public static void main(String[] args) throws IOException {
        // 需求:把文件压缩到指定文件夹下
        // 源文件夹
        File src = new File("bbb//test");
        // 目的文件夹
        String path = "bbb";
        // 压缩包的路径
        File dest = new File(path, src.getName() + ".zip");

        // 压缩流的路径
        ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
        zip(zos, src, src.getName());
        zos.close();
    }

    private static void zip(ZipOutputStream zos, File src, String name) throws IOException {
        File[] files = src.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isFile()) {
                    String path2 = name + "\\" + file.getName();
                    // 转换为ZipEntry对象
                    ZipEntry zip = new ZipEntry(path2);
                    zos.putNextEntry(zip);
                    FileInputStream fis = new FileInputStream(file);
                    int b;
                    while ((b = fis.read()) != -1) {
                        zos.write(b);
                    }
                    fis.close();
                    zos.closeEntry();
                } else {
                    zip(zos, file, name + "\\" + file.getName());
                }
            }
        }
    }
}

平常压缩和解压都有软件了,这个还能干嘛,可能这个需要做页面下载文件用途。

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值