Java文件打包程序

本文讨论了如何将文件夹中的文件打包成适当大小的文件块以优化上传和备份过程。针对不同文件大小,提出了两种可能的打包方案,并强调了在实际操作中需要考虑目录结构和文件归属。同时,提出了关于遍历目录、性能评估、算法逆向、用户场景以及代码正确性的一系列问题,旨在优化打包算法并适应不同需求。

师兄给的说明↓

现在想象一个场景,你要将文件夹上传到网盘备份。
但是,假如现在有个大文件几G,可能上传到99%网络断了,重来(下载也是)。还有一种情况,可能某个文件夹下有大量的小文件(几十万的量级) ,可能上传的过程中,网络都跑不满,全部卡在cpu解析和读取上了。

所以现在需要把文件大小居中,弄成适当的大小(比如10MB一个文件),现在的任务就是将一个文件夹下的文件打包成10MB的文件块。

  • 问题一:

比如有如下文件的大小: 3个12M,10个127k,100个7k的文件

预期分配结果是什么?是最优的吗?

思路和需要用到的知识

  1. 遍历文件夹信息,就是获取每个文件的大小,路径什么的
  2. 编写算法,输入所有文件的信息,进行打包算法,

我当时想的是:把12m的都拆成10m+2m,再把3个2m部分+剩下的……

  • 答案:

    一共 36M+1270k+700k =37M+746K

    方案一: 10 + (2+8)+(4+6) +(6+剩下的)

    方案二: 12 +12 +12 +剩下的

    实际情况得从目录结构分析,可能会有不同的结果,也就是可能100个7k里面有几个和一个12M是同一子目录下的,应当打包到一起吧?不然你还原该文件夹的时候要处理两个数据块

    考虑到实际,虽然说打包成10M 但是一个10M+1B的文件总不能打包成两个吧,所以应该是约10M 实际大小大概是 7M~14M波动(这样超过14M即可拆分成两个7M+的文件了,当然还有6~12 8~16 但是离平均的10M较远)

  • 问题二:

输出是怎么样的?

  1. 拿上一步的输出,执行打包作业
  • 问题三: 重点

找个大一点的文件夹,观察执行中cpu,磁盘的调度和使用情况,性能最优了吗?

体会什么是阻塞。

  • 问题四:

遍历目录树用来什么遍历方法,别的遍历顺序也可以吗?有什么区别,哪一种最好?

  • 问题五:

考虑过算法的逆向吗?即从打包后的文件还原之前的目录结构

  • 问题六:

考虑过用户场景吗?

比如一个场景:

将一个图片文件夹或者视频文件夹打包后,将数据包上传到百度网盘。现在需要拿到里面某个文件,需要下载多少数据包?

a)是所有数据包?还是先下载打包信息,然后找到含有这个所需文件的数据包再下载需要的就行?

b)你的打包算法有对这种情况进行调优吗?回头看看问题四

  • 问题七:

你的代码怎么保证是正确的?


我思路就是先遍历文件夹把大于10m就拆成最大为10的子文件 然后再遍历文件夹把<10m的文件组装为最大10m的文件块 就是只能实现要求的内容 但是不优……有一些想法但是不知道要怎么实现,还是不熟悉JAVA语法,不知道怎么实现&不知道能不能实现,TAT。

目前代码:

package FilePacker;

import java.io.*;
import java.util.Arrays;
import javax.security.auth.DestroyFailedException;

public class FilePacker {
    private static void splitFile(File f, int eachSize) {
        if(f.length()>10 * 1024 * 1024) {//该文件大于10m
            int count = (int)(Math.ceil(f.length() / eachSize))+1;//块数
            try {
                /**创建输入输出流对象*/
                InputStream inf = new FileInputStream(f);
                OutputStream[] outf = new FileOutputStream[count];
                /**创建文件夹,存储各小块文件*/
                int no = f.getName().lastIndexOf(".");
                String str = f.getParent()+"\\"+f.getName().substring(0, no );/**目录路径*/
                File dirfile = new File(str);
                if(!dirfile.exists()) {
                    dirfile.mkdirs();
                }
                /**创建各小块文件并命名*/
                File[] dir_f = new File[count];
                /**获取文件类型*/
                String fName = f.getName();
                String fPattern = fName.substring(fName.lastIndexOf("."), fName.length());
                for(int j=0; j<count; j++) {
                    String newPath = str+"\\"+f.getName().substring(0, no)+"-"+j+fPattern;
                    dir_f[j] = new File(newPath);
                    outf[j] = new FileOutputStream(dir_f[j]);
                }
                /**写入各块内容*/
                int s,m=0,  n=10*1024;
                byte[] buffer = new byte[n];
                s = inf.read(buffer, 0, n);
                while(s != -1&& m<count) {
                    if(dir_f[m].length() < 10*1024) {
                        outf[m].write(buffer, 0, n);
                        s = inf.read(buffer, 0, n);
                    }
                    if(dir_f[m].length() == 10*1024){
                        outf[m].close();
                        m = m+1;
                        int off = (int)(f.length()-m*10*1024);
                        if(off<10*1024) {
                            outf[m].write(buffer, 0, off);
                            outf[m].close();
                            break;
                        }
                    }
                }
                inf.close();
                f.delete();
            }
            catch(IOException ioe) {
                System.out.println("IO 异常");
            }
            catch(IndexOutOfBoundsException ine) {
                System.out.println("数组越界 异常");
            }
            catch(Exception e) {
                System.out.println("异常");
            }
        }
    }

    public static void divide( String fPath ) {
        File f = new File(fPath);
        /**文件存在*/
        if(f.exists()){
            /**是单个文件*/
            if(f.isFile() && f.length() > 10*1024*1024) {
                /**调用单文件分割方法*/
                splitFile(f, 10*1024*1024);
            }
            /**是目录*/
            else if(f.isDirectory() && f.length() > 10*1024*1024) {
                /**目录文件数组化*/
                File[] dir = f.listFiles();

                for(int i=0; i<dir.length; i++) {
                    if(dir[i].exists() && dir[i].length() > 10*1024*1024){
                        if(dir[i].isFile()) {
                            splitFile(dir[i], 10*1024*1024);
                        }
                        else if(dir[i].isDirectory() && dir[i].length() > 10*1024*1024) {
                            divide(dir[i].getAbsolutePath());
                        }
                    }
                }
            }
        }
        else {
            System.out.println(fPath + "  不存在文件!");
        }
    }

    private static void murgeFile(File dir, File dst) throws IOException {

        String[] children = dir.list();
        FilenameFilter filter = new FilenameFilter(){
            public boolean accept(File dir, String name) {
                return true;
            }
        };
        File filePath = new File("c:\\Users\\73426\\Desktop\\PPT\\test\\作业要求");//需要拼装的目录
        String fileIndex="0";
        File FileBig = new File(filePath + "/" + "Files"+"_"+fileIndex);
        BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(FileBig));

        children = dir.list(filter);
        for (int i = 0; i < children.length; i++) {
            String inhalt = children[i];
            FileInputStream in = new FileInputStream(dir + "/" + inhalt);
            byte[] buffer = new byte[1024];
            int len=0;
            if (FileBig.length() /1024 / 1024 < 10) {
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                out.flush();// out.close();
            } else {
                int fileIndexInt = Integer.parseInt(fileIndex) + 1;
                FileBig = new File(filePath + "/" + "Files" + "_"
                        + fileIndexInt);
                out = new BufferedOutputStream(
                        new FileOutputStream(FileBig));

                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                out.flush();
//out.close();
                fileIndex = String.valueOf(fileIndexInt);
            }
        }
        out.close();
    }

    public static void start()
    {
        String path = "c:\\Users\\73426\\Desktop\\PPT\\test";//要切割的文件/目录路径
        divide(path);//切割
        File dir = new File("c:\\Users\\73426\\Desktop\\PPT\\test\\作业要求");
        File out=new File("c:\\Users\\73426\\Desktop\\PPT\\test\\作业要求");
        try {
            murgeFile(dir,out);
            //由于是在网上找的方法,东拼西凑改的,合并这个地方还不够灵活,应该要再创建一个方法遍历原目录所有文件进行合并处理,遇到子文件夹再将子文件也拼接(待完成)
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)throws IOException {
        start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值