Java中的文件压缩与解压设计与实现

1 实验分析说明

一、文件压缩,是很有必要的,我们在进行文件,传输过程中,很多时候都是,都是单个文件单个文件发送接收,但是当数据量特别大,或者文件数量比较多的时候,这个时候就可以考虑文件压缩。
二、优势:文件压缩过后,只需要进行一次文件的传输就可以了。减少频繁发送的问题。缺点:文件大小会变大,如果传输过程中断了,风险较大。
三、开发工具为:JDK1.8, idea

2.基础知识

ZIP是一种较为常见的压缩形式,在Java中要想实现ZIP的压缩需要导入java.util.zip包,可以使用此包中的ZipFile、ZipOutputStream、ZipInputStream、ZipEntry几个类完成。
ZipOutputStream 实现文件的压缩
ZipOutputStream (OutputStream out) 创建新的zip输出流
void putNextEntry(ZipEntry e) 开始写入新的zip文件条目并将流定位到条目数据的开始处
条目指的是一个文件夹下的多个文件。
ZipEntry(String name) 使用指定名称创建新的zip条目
ZipIutputStream实现文件的解压
ZipIutputStream (IutputStream out) 创建新的zip输入流
ZipEntry getNextEntry()读取下一个zip条目并将流定位到该条目数据的开始处

3结构分析

实际上这个程序主要分为两个部分,分别是图形界面的部分和文件处理的部分。
图形界面:用JTextField类实现文本的输入,通过继承ActionListener接口实现反馈操作swing和awt是java中处理图形界面的类。Java的图形界面分为容器container和组件JComponent,容器上可以添加组建。JPanel一般作为容器装其他组件,再添加到窗口上。窗口一般从Jframe派生,对话框从Jdialog派生。具体的参数设定方法参见Java的类实现。
附一张图:
在这里插入图片描述

4.GUI界面展示

在这里插入图片描述

5.代码具体实现

5.1display类

此类为本项目的GUI界面具体代码如下:

import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
import java.awt.event.*;
import java.io.*;
public class display extends JFrame implements ActionListener {
    JTextField text1,text2;
    JButton bt1, bt2;
    String str[] = {null, null};//存储文本框信息
    File f[] = {null, null};// 文件名为空,然后进行对f操作,(比如赋值文件目录)
    public display()
    {
        f[0] = f[1] = null;
        JPanel p1 = new JPanel();
        p1.setLayout(new FlowLayout(FlowLayout.LEFT,10,10));
        p1.add(new JLabel("路径:    "));
        text1 = new JTextField(30);
        p1.add(text1);
        Font largeFont = new Font("宋体", Font.BOLD, 20);// 字体样式,字体格式(加粗),大小
        Border lineBorder = new LineBorder(Color.BLACK, 2);
        p1.add(new JLabel("文件名:"));
        text2 = new JTextField(30);
        p1.add(text2);
        JPanel p2 = new JPanel();
        p2.setLayout(new GridLayout(1,2,10,10));
        text1.addActionListener(this);
        text2.addActionListener(this);
        text1.setText("请输入正确的绝对路径,回车键结束!");
        text2.setText("请输入压缩文件的绝对路径,回车键结束!");
        bt1 = new JButton("打包");
        bt2 = new JButton("解包");
        bt1.setFont(largeFont);
        bt2.setFont(largeFont);
        bt1.setBorder(lineBorder);// 按钮的线边框
        bt2.setBorder(lineBorder);
        bt1.setBackground(Color.CYAN);
        bt2.setBackground(Color.CYAN);
        //bt1 是打包按钮,添加监视器调用压缩函数
        //处理鼠标事件的类要么实现此接口(及其包含的所有方法),要么扩展抽象类 MouseAdapter(仅重写所需的方法)。首先在主Panel中注册鼠标的点击和拖动事件,分别是mouseClicked和mouseDragged,事件中能够获得鼠标的坐标
        // 然后使用组件的 addMouseListener 方法将从该类所创建的侦听器对象向该组件注册。
        // 当按下、释放或单击(按下并释放)鼠标时会生成鼠标事件。
        // 鼠标光标进入或离开组件时也会生成鼠标事件。发生鼠标事件时,将调用该侦听器对象中的相应方法,
        // 并将 MouseEvent 传递给该方法。
        bt1.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                boolean flag = true;
                if(f[0] == null || !f[0].exists()) {
                    text1.setText("格式错误或路径不存在!请重新输入!");
                    flag = false;
                }
                if(f[1] == null) {
                    text2.setText("格式错误或路径不存在!请重新输入!");
                    flag = false;
                }
                if(flag == true) {
                    Zipfile.zip(f);
                }
            }
        });
        //bt2 是解包按钮,调用解压函数
        bt2.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                boolean flag = true;
                if(f[0] == null || !f[0].exists()) {
                    text1.setText("格式错误或路径不存在!请重新输入!");
                    flag = false;
                }

                if(f[1] == null || !f[0].exists()) {
                    text2.setText("待解压文件不存在!请重新输入!");
                    flag = false;
                }
                if(flag == true) {
                    try {
                        Zipfile.unZipFiles(f[1], str[0] + "/");

                    } catch (IOException e1) {
                    }
                }
            }
        });
        p2.add(bt1);
        p2.add(bt2);
        setLayout(new GridLayout(2,1,5,5));
        add(p1);
        add(p2);
    }
    //添加文本监视器,并判断输入是否合法
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == text1) {//获得目前这个事件的事件源
            str[0] = text1.getText();
            f[0] = new File(str[0]);
            if(f[0] == null || !f[0].exists()) {
                text1.setText("格式错误或路径不存在!请重新输入!");
            }
            else {
                text1.setText("路径已输入!");
            }
        }
        else {
            str[1] = text2.getText();
            f[1] = new File(str[1]);
            if(!str[1].endsWith(".zip")) {//endsWith() 方法用于测试字符串是否以指定的后缀zip结束。
                text2.setText("请输入zip格式的文件路径!");
            }
            else {
                text2.setText("路径已输入!");
            }
        }
    }
}

5.2zip压缩主函数

import javax.swing.*;
public class zip {
    public static void main(String[] args)
    {
        display frame = new display();
        frame.setTitle("文件压缩程序");
        frame.setSize(400,300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setResizable(true);//设置此窗体是否可由用户调整大小。
    }
}

5.3FileZip 实现.zip压缩与解压

import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.*;
//文件解压与压缩A
public final class Zipfile {
    //文件压缩函数,通过遍历子文件夹,递归的压缩文件
    public static void zip(File[] f) {
        File source = f[0];
        File target = f[1];
        FileOutputStream fout = null;// 写入文件,字节输出流
        ZipOutputStream zout = null;// 压缩流
        try {
            fout = new FileOutputStream(target);
            zout = new ZipOutputStream(new BufferedOutputStream(fout));
            //将文件目录中的文件放入输出流
            //用输入流读取压缩文件中制定目录中的文件
            // 一般来说BufferedOutputStream一般放在所有一层层OutputStream的最外面。
            // 但是 ZipOutputStream都是,zos.putNextEntry加一个zip内的文件路径,
            // 接下去写入的stream都表示是这个文件路径的数据了。
            // BufferedOutputStream如果裹在zos外面的话,必须得写入完后flush一下。
            // 不然会把上一个zipentry的数据写到下个zipentry里去了。
            // 所以这时最好把BufferedOutputStream放ZipOutputStream里面。
            addZip("../", source, zout);// ../ 父级目录,向source父级目录追加压缩文件zout
        }catch(IOException e) {
        }finally {
            try {
                if(fout != null) {
                    zout.close();
                }
                if(zout != null) {
                    fout.close();
                }
            }catch(IOException e) {
            }
        }
        //输出压缩信息
        System.out.println("******************压缩完毕********************");
        System.out.println("文件已从"+f[0].getAbsolutePath()+"压缩至"+f[1].getAbsolutePath());
        取得绝对路径
    }
    //使用递归函数对文件进行压缩
    public static void addZip(String base, File source, ZipOutputStream zout) throws IOException {
        String entry = base + source.getName();// 完整目录:父级目录+名称,解压出的文件路径
        if(source.isDirectory()) {// 取出文件夹中的文件(或子文件夹)
            for(File file : source.listFiles()) {// File对象类型的完整路径遍历文件夹中所有文件用listFiles()方法
                addZip(entry + "/", file, zout);// 写入此目录的进入点entry
            }
        }
        else {
            FileInputStream fin = null;// 文件字节输入流
            BufferedInputStream bin = null;// 缓冲的输入流
            try {
                byte[] buffer = new byte[1024 * 10];
                fin = new FileInputStream(source);
                bin = new BufferedInputStream(fin, buffer.length);
                int r = 0;
                //将源文件写入到zip文件中
                zout.putNextEntry(new ZipEntry(entry));//在压缩文件中建立进入点entry
                while(((r = bin.read(buffer, 0, buffer.length)) != -1)) {//如果没有到达流的尾部
                    zout.write(buffer, 0, r);//将字节写入当前zip条目
                }
                zout.closeEntry();//关闭当前的ZIP条目并定位流以读取下一个条目。
            }
            finally {
                try {
                    if(bin != null) {
                        bin.close();
                    }
                    if(fin != null) {
                        fin.close();
                    }
                }catch(IOException e) {
                }
            }
        }
    }
    //解压文件
    public static void unZipFiles(File zipFile,String descDir)throws IOException
    {
        File pathFile = new File(descDir);//获取当前压缩文件
        // 判断源文件是否存在
        if(!pathFile.exists())
        {
            pathFile.mkdirs();
            // 这个方法可以在不知道有没有父类文件夹的情况下,创建文件夹,而mkdir()必须在有父类的文件夹下创建文件
        }
        //保证中文可以被正确识别
        ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));
        //创建压缩文件对象
        //开始解压
        for(Enumeration entries = zip.entries(); entries.hasMoreElements();)
        //1返回zip文件的zip文件条目的枚举,2如果枚举包含更多元素,则它将返回true,否则返回false判断是不是还要下一个元素
            // 遍历文件
        {
            ZipEntry entry = (ZipEntry)entries.nextElement();// 如果是文件夹,就创建个文件夹
            String zipEntryName = entry.getName();
            InputStream in = zip.getInputStream(entry);//字节输入流,用来将文件中的数据读取到java程序中。
            String outPath = (descDir+zipEntryName).replaceAll("\\*", "/");
            //替换字符串所有匹配给定的正则表达式的子字符串。输出文件格式:路径+名称
            //regex -- 匹配此字符串的正则表达式。
            //replacement -- 用来替换每个匹配项的字符串。
            File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
            // 如果是文件,就先创建一个文件,然后用io流把内容copy过去
            if(!file.exists())
            {
                file.mkdirs();//创建此文件的上级目录
            }
            if(new File(outPath).isDirectory()) //判断输出路径是否为一个目录
            {
                continue;
            }
            System.out.println(outPath);
            OutputStream out = new FileOutputStream(outPath);// 文件输出流
            byte[] buf1 = new byte[1024];
            int len;
            while((len=in.read(buf1))>0)//如有输入流可以读取到数值
            {
                out.write(buf1,0,len);//输出流写入
            }
            in.close();
            out.close();
        }
        //输出解压信息
        System.out.println("******************解压完毕********************");
        System.out.println("文件已从"+zipFile.getAbsolutePath()+"解压至"+descDir.substring(0, descDir.length() - 1));
        zip.close();
    }
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
程序测试可用,直接解压导入到工程就可以,bat文件跟shell文件是用于在window跟linux上直接执行的脚本 我把开发的配置文档附上: 1.程序为定时任务,任务执行时间在bin目录下的配置文件mergeFilleUtil.properties配置,在配置文件,TASK_PERIOD表示任务执行时间间隔,单位为妙,如一天的时间间隔配置是86400,TASK_BEGIN_HOUR表示任务开始的小时时间,比如9点,TASK_BEGIN_MINUTE表任务开始的分钟,比如30分。 2. 程序用log4j记录日志,日志分正常信息跟错误信息两个级别,日志文件存放在log4j文件夹下。考虑到文件很多,日志解压、移动文件解压、移动1000个记录一次,合并、删除文件每合并、删除50000个记录一次, 3. 启动任务前需配置文件解压合并的路径,本程序需配置的路径如下: 1). PROVINCE_DIR:原始文件存放的路径,必须配置到省的上一级路径,比如存放安徽省的文件路径为E:\test\rootfile\anhui,那么文件的路径必须配置为E:\test\rootfile,否则不能正确显示合并结果; 2). UN_ZIP_PATH:存放解压后的文件的路径; 3). OUT_PATH:存放合并后的文件路径; 4). DONE_FILE_PATH:存放已经解压处理过的文件; 5). DELETE_PATH:配置程序运行结束后欲删除文件的路径,如想删除多个文件夹下的文件,路径之间用逗号隔开,勿加空格,比如:E:\test\rootfile,E:\test\unZip; 4. 注意事项: 本解压合并程序处理文件的逻辑如下: 程序每次解压都去PROVINCE_DIR文件下去解压,将解压后的文件存放到UN_ZIP_PATH下,之后程序启动合并程序合并UN_ZIP_PATH下文件,将合并后的文件按照省份名称存放到OUT_PATH,一个省一个文件。当解压合并结束后,程序将PROVINCE_DIR路径下的文件移动到DONE_FILE_PATH下,并且删除PROVINCE_DIR跟UN_ZIP_PATH下文件,这样保证程序每次运行PROVINCE_DIR文件夹下的文件跟UN_ZIP_PATH下的文件都是最处理过的,避免了不断判断文件历史记录所带来的大量时间消耗。 所以为了保证文件解压跟合并的正确性,必须配置好DELETE_PATH路径下的文件,否则合并后的结果是不准确的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cai-4

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

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

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

打赏作者

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

抵扣说明:

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

余额充值