IO流——(15)File类——文件的切割与合并

     生活中我们经常遇到这样一类问题,就是对于文件上传有大小的限制,尤其是对某个论坛上传附件时,由于论坛的服务器容量比较小,所以在用户上传文件时,进行限制。

      比如论坛限制上传大小为2M,我需要上传5M的文件,那么就可以进行将5M文件切割为3个2M大小的碎片文件,上传以后进行合并。接下来就演示文件的切割与合并。

一、切割文件:

1、首先实现需要明确需要切割文件的位置。

2、切割的大小容量

3、切割后碎片文件的存放位置。

4、碎片文件的格式一般是.part。

二、示例代码

public static  void splitFile(File file) throws IOException {

        //用读取流关联一个源文件
        FileInputStream fis =new FileInputStream(file);

        //定义一个1M缓冲区,用于存放碎片文件
        byte[] bty =new byte[SIZE];

        //定义输出流
        FileOutputStream fos =null;

        //创建目的地
        File dir =new File("C:\\Users\\Administrator\\Pictures\\partFiles");
        if (!dir.exists()){
            dir.mkdirs();
        }
        //定义一个缓冲区长度变量
        int len=0;
        int count=0;

        while ((len=fis.read(bty))!=-1){
            //碎片文件存放位置与格式
          fos =new FileOutputStream(new File(dir,(count++)+".part"));
          fos.write(bty,0,len);
        }

        fos.close();
        fis.close();
        
    }

调用:

 public static void main(String[] args) throws IOException {

        File file =new File("C:\\Users\\Administrator\\Pictures\\Screenshots\\0.bmp");
        splitFile(file);

    }

源文件:

 

切割后的碎片文件:

三、合并文件

将碎片化的文件合并成切割前的源文件

代码:

private static void mergeFile(File dir) throws IOException {
        //存放多个读取源
        ArrayList<FileInputStream>  al =new ArrayList<FileInputStream>();
        for (int i=0; i<=4;i++){
            //为list添加多个读取流对象
            al.add(new FileInputStream(new File(dir,i+".part")));
        }
        //将ArrayList转换为枚举
        Enumeration<FileInputStream> enumeration = Collections.enumeration(al);
        //序列流
        SequenceInputStream sis =new SequenceInputStream(enumeration);
        //定义合并后的输出位置位于碎片文件文件夹
        FileOutputStream fos =new FileOutputStream(new File(dir,"0.bmp"));
        //缓冲区
        byte[] buf =new byte[1024];
        int len=0;
        while ((len=sis.read(buf))!=-1){
           fos.write(buf,0,len);
        }
        fos.close();
        sis.close();
    }

调用:

 public static void main(String[] args) throws IOException {

        File file =new File("C:\\Users\\Administrator\\Pictures\\partFiles");
        mergeFile(file);

    }

但是以上代码中却有两个问题:

不知道有多少碎片?

不知道源文件的名字?

上面代码都是写死的。

解决方法就是在切割源文件为碎片文件时,获取原文件名和碎片文件个数,存入到一个properties文件中。

四、完善版切割文件

带有文件名和碎片文件次数的配置文件:

话不多说 ,看代码

 private static void splitFile_2(File file) throws IOException {
        /*
         * 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数。 以方便于合并。
         * 这个信息为了进行描述,使用键值对的方式。用到了properties对象
         *
         */

        //用读取流关联一个源文件
        FileInputStream fis =new FileInputStream(file);

        //定义一个1M缓冲区,用于存放碎片文件
        byte[] bty =new byte[SIZE];

        //定义输出流
        FileOutputStream fos =null;

        //创建目的地
        File dir =new File("C:\\Users\\Administrator\\Pictures\\partFiles");
        if (!dir.exists()){
            dir.mkdirs();
        }
        //定义一个缓冲区长度变量
        int len=0;
        //记录切割文件的个数
        int count=1;

       
        /**
         * Properties用于记录文件信息
         */
        Properties prop =new Properties();
        while ((len=fis.read(bty))!=-1){
            //碎片文件存放位置与格式
            fos =new FileOutputStream(new File(dir,(count++)+".part"));
            fos.write(bty,0,len);
            fos.close();
        }

        prop.setProperty("partcount",count+"");
        prop.setProperty("filename",file.getName());

        //新建一个文件输出流 创建一个properties配置文件
        fos = new FileOutputStream(new File(dir,count+".properties"));
        //将properties文件写入到文件中
        prop.store(fos,"save file info");

        fos.close();
        fis.close();
}

、调用:

 public static void main(String[] args) throws IOException {

        File file =new File("C:\\Users\\Administrator\\Pictures\\Screenshots\\0.bmp");
       // splitFile(file);

        //自动获取文件名与碎片文件个数,生成配置文件。
        splitFile_2(file);

    }

切割后得到的文件: 

五、完善合并文件:

 private static void mergeFile_2(File file) throws IOException {

        /**
         *1、 获取指定目录下的配置文件对象
         * 使用过滤器
         */
        File[] dir =file.listFiles(new SuffixFilter(".properties"));
        if (dir.length !=1) {
            throw new RuntimeException(file+"该目录下没有properties扩展名的文件或者不唯一");
        }
        //获取配置文件对象
        File configFile = dir[0];

        /**
         * 2、获取该文件中的信息
         */
        Properties prop =new Properties();
        FileInputStream fis =new FileInputStream(configFile);
        //从输入流中读取键值属性信息
        prop.load(fis);

        //获取碎片个数和源文件的文件名
        int count = Integer.parseInt(prop.getProperty("partcount"));
        String filename = prop.getProperty("filename");

        /**
         * 3、 获取该目录下的所有碎片文件
         */
        File[] partFiles = file.listFiles(new SuffixFilter(".part"));
        if (partFiles.length!=(count-1)){
           throw new RuntimeException("碎片文件个数与源文件碎片文件个数不符,文件未上传完整");
        }
        /**
         * 4、将碎片文件和流对象关联 并存储到集合中。
         */
        ArrayList<FileInputStream> al =new ArrayList<FileInputStream>();
        for (int i=0;i<partFiles.length;i++){
            al.add(new FileInputStream(partFiles[i]));
        }



        /**
         * 5、将多个流合并成一个序列流 合并碎片文件
         */

        Enumeration<FileInputStream> enumeration = Collections.enumeration(al);
        SequenceInputStream sis =new SequenceInputStream(enumeration);

         //定义合并后的输出位置位于碎片文件文件夹
        FileOutputStream fos =new FileOutputStream(new File(file,filename));
        //缓冲区
        byte[] buf =new byte[1024];
        int len=0;
        while ((len=sis.read(buf))!=-1){
            fos.write(buf,0,len);
        }
        fos.close();
        sis.close();

    }

调用:

 public static void main(String[] args) throws IOException {

        File file =new File("C:\\Users\\Administrator\\Pictures\\partFiles");
        //mergeFile(file);
        mergeFile_2(file);

    }

合并后的文件:

当然其他视频等文件也是如此,就不一一演示了,只需要更改一下切割的源文件目录即可验证。

发布了186 篇原创文章 · 获赞 45 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/zhanshixiang/article/details/103906578