学习Java小结-3

3 篇文章 0 订阅
1 篇文章 0 订阅

学习Java也有近一个月了,基础语法、常用类也有所了解。上周把文件相关操作进行了一个总结,制作了一个简单的文件常用操作的工具类。

此处详解文件的打包与解包

工具类包含了容下功能的实现:
1、 拷贝文件
2、 移动文件
3、 遍历文件夹
4、 获取文件夹内所有文件
5、 文件打包与解包

5-1 文件的打包

思路:要将文件进行打包,首先需要拿到文件当中的所有文件对象,然后将所有的文件安装一定的组织关系存入一个文件当中。
既然是打包,那么就应该有一个打包后的文件类型,在这里我将包文件类型定义为pakge类型的文件

public static String PACKAGE_TYPE = ".pakge";

在上面已经实现了获取文件中的所有文件,现在需要将所有的文件存入一个文件当中。这个就简单了,只需要遍历获取了所有的文件对象的List集合对象,将每一个文件依次写入一个文件当中即可。


    /**
     * 打包一个文件(夹)
     * @param srcDir 要打包的目标文件(夹)绝对路径字符串
     * @param dir 打包文件的存贮绝对路径字符串
     * @return boolean TRUE表示成功打包
     */
    public static boolean packageFile(String srcDir, String dir) {
        //创建文件对象
        File srcFile = new File(srcDir);
        File destFile = new File(dir + PACKAGE_TYPE);
        //通过文件对象获取源文件的绝对路径,避免参数字符差异
        String srcFilePath = srcFile.getAbsolutePath();
        //如果源文件存在,则进行打包操作
        if (srcFile.exists()) {
            //通过已有方法获取所有文件
            ArrayList<File> fileList = new ArrayList<File>();
            FileControls.getAllFiles(srcFilePath, fileList);
            try {
                //以追加方式创建文件输出流,绑定打包文件
                FileOutputStream fs = new FileOutputStream(destFile, true);
                for (Filef : fileList) {
                    if (!f.getFilePath().isDirectory()) {
                        FileInputStream fi = new FileInputStream(f.getFilePath());
                        //创建缓冲字节数组
                        byte[] buffer = new byte[4096];
                        //获取当前文件总长(字节数)
                        long size = f.length();
                        while (true) {
                            //如果未写入的字节数比缓冲数组长,则读取并写入4096字节                         if (size > 4096) {
                                fi.read(buffer);
                                fs.write(buffer);
                                //未写入字节数减少4096
                                size -= 4096;
                            } else {
                            //读取并写入剩余字节,关闭输入流
                                fi.read(buffer, 0, (int) size);
                                fs.write(buffer, 0, (int) size);
                                fi.close();
                                break;
                            }
                        }
                    }
                }
                //刷新输出流,关闭输出流
                fs.flush();
                fs.close();
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("源文件\"" + srcFile.getAbsolutePath() + "\"不存在");
        }
        return false;
    }

这里可以看到,打包功能已经完成。接下来看解包的实现。

5-2 文件的解包

思路:在这里突然发现,上面实现的打包功能无法解包。为啥呢?因为包中的文件名、文件大小信息均没有进行保留。因此需要对上面的打包功能进行优化。在打包的时候要将文件名、文件大小写入到打包文件中。这样在解包的时候才可以将包文件中的文件正常的完整的解包出来。
因此,增加了一个功能类Filesize

    public static class Filesize implements Serializable {
        private static final long serialVersionUID = -1035346214239079079L;
        private File filePath;
        private long fileSize;

        public File getFilePath() {
            return filePath;
        }
        public long getFileSize() {
            return fileSize;
        }
        public void setFilePath(String filePath) {
            this.filePath = new File(filePath);
            this.fileSize = this.filePath.length();
        }
    }

该功能类Filesize有两个属性:1、文件对象。2、文件对象的大小。另外可以看到该功能类实现了Serializable接口,这是为了能够该类对象能够序列化到文件中。以便于将文件的名称、大小的信息保存下来。
因为要将文件信息保存到该功能类中,因此重载获取所有文件对象的方法。重载时发现,目录文件不需要进行获取

    public static void getAllFiles(String srcPath, ArrayList<FileControls.Filesize> files) {
        File file = new File(srcPath);
        if (file.exists()) {
            File[] fileList = file.listFiles();
            if (fileList != null && fileList.length > 0) {
                for (File src : fileList) {
                    getAllFiles(src.getAbsolutePath(), files);
                }
            }
            if (!file.isDirectory()) {
                //构建功能类对象
                FileControls.Filesize fileSize = new FileControls.Filesize();
                fileSize.setFilePath(file.getAbsolutePath());
                files.add(fileSize);
            }
        }
    }

打包方法优化后的代码如下

    /**
     * 对打包文件进行解包,默认解包路径为打包文件同级路径,解包的后的文件对象的父目录为
     * 包文件父目录/包文件名
     *
     * @param packageFilePath 包文件绝对路径字符串
     * @return 成功解包则返回TRUE
     */
    public static boolean upPackges(String packageFilePath) {
        File packageFile = new File(packageFilePath);
        FileInputStream fin = null;
        ObjectInputStream oin = null;
        if (packageFile.exists()) {
            try {
                fin = new FileInputStream(packageFile);
                oin = new ObjectInputStream(fin);
                ArrayList<FileControls.Filesize> list = new ArrayList<FileControls.Filesize>();
                //反序列化出文件详细信息集合对象
                //如果强转失败,则会抛出ClassCastException异常,说明这不是一个大包文件
                list = (ArrayList<FileControls.Filesize>) oin.readObject();
                if (list.size() != 0) {
                    for (int i = 0; i < list.size(); i++) {
                        File file = list.get(i).getFilePath();
                        //如果该文件是目录,则直接创建目录
                        if (!file.isDirectory()) {
                            //构建包文件的绝对路径字符串
                            String dir = packageFile.getParent() + "\\" + file.getName();
                            //创建解包文件
                            File destfile = new File(dir);
                            //创建父级目录
                            destfile.getParentFile().mkdirs();
                            FileOutputStream fout = new FileOutputStream(destfile);
                            //获取文件大小
                            long filesize = list.get(i).getFileSize();
                            //通过缓冲法将文件类容读取并写入解包的对应文件中
                            byte[] buffer = new byte[4096];
                            while (true && filesize > 0) {
                                if (filesize > 4096) {
                                    fin.read(buffer);
                                    fout.write(buffer);
                                    filesize -= 4096;
                                } else {
                                    fin.read(buffer, 0, (int) filesize);
                                    fout.write(buffer, 0, (int) filesize);
                                    break;
                                }
                            }
                            fout.flush();
                            fout.close();
                        } else {
                            file.mkdirs();
                        }
                    }
                    //关闭输入流
                    oin.close();
                    return true;
                }
            } catch (ClassCastException ce) {
                System.out.println("这不是一个包文件");
                try {
                    oin.close();
                    fin.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return false;
    }

到这里,所以的功能已经完整的实现。代码已经上传到GitHub中,这是GitHub的链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值