zoukankan      html  css  js  c++  java
  • 70. SequenceInputStream(文件合并)

    缓冲输入字节流:
    ----------------------| InputStream 输入字节流的基类
    ----------------| FileInputStream  读取文件的输入字节流
    ----------------| BufferedInputStream  缓冲输入字节流   作用:提高读取文件的效率

    缓冲输出字节流:
    ----------------------| OutputStream 输出字节流的基类
    ----------------| FileOutputStream 写入文件的输入字节流
    ----------------| BufferedOutputStream 缓冲输出字节流 作用:提高我们写入数据的效率

    输入字符流:
    --------------| Reader 输入字符流的基类。 抽象类
    ----------| FileReader 读取文件的输入字符流
    ----------| BufferedReader 缓存输入字符流(提高效率和扩展了FileReader的功能)。内部其实也维护了一个字符数组

    扩展功能:
    readLine()     一次读取文本的一行数据,如果读取到了文件末尾返回null

    输出字符流:
    --------------| Write  输出字符流的基类。 抽象类
    ----------| FileWrite  向文件输入数据
    ----------| BufferedWrite 缓存输出字符流。 内部维护了一个字符数组,当我们使用write的时候是把数据存储到了字符数组中,并不是写入了文件中
    当我们使用flush,close方法或者数组满了的时候,才会写入文件中

    扩展功能:
    newLine()     添加一个回车符,实际上就是输出(/r/n)

    //需求:把a.txt 和 b.txt的文本合并成一个文本

    public class Demo1 {
        public static void main(String[] args) throws IOException {
            //找到目标文件
            File inputfile1 = new File("D:\新建文件夹\a.txt");
            File inputfile2 = new File("D:\新建文件夹\b.txt");
            File outputfile = new File("D:\新建文件夹\c.txt");
            //建立数据通道
            FileInputStream fileInputStream1 = new FileInputStream(inputfile1);
            FileInputStream fileInputStream2 = new FileInputStream(inputfile2);
            FileOutputStream fileOutputStream = new FileOutputStream(outputfile);
            //我们建立一个集合来存储被合并文本的数据通道对象
            ArrayList<FileInputStream> arrayList = new ArrayList<FileInputStream>();
            arrayList.add(fileInputStream1);
            arrayList.add(fileInputStream2);
            //创建缓存字节数组
            byte[] buf = new byte[1024];
            //定义变量用来存储每次读取到数组中的字符长度
            int length = 0;
            for (FileInputStream fileInputStream : arrayList) {
                while((length = fileInputStream.read(buf))!= -1) {
                    //把读取的数据写入c.txt文本中,
                    fileOutputStream.write(buf,0,length);
                }
            }
            //先开后关原则
            fileOutputStream.close();
            fileInputStream2.close();
            fileInputStream1.close();
        }
    }

    我们可以发现,用上面的方式很不方便,书写很麻烦很繁琐

    sun公司给我们提供了一个SequenceInputStream类:
    表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,
    接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止

    其实我们可以发现,它的底层也是存在一个有序集合,原理一样都是遍历有序集合

    SequenceInputStream的构造方法:

    SequenceInputStream(InputStream s1, InputStream s2)
        通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节
    SequenceInputStream(Enumeration<? extends InputStream> e)
        通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。


    SequenceInputStream的常用方法:
    close()   关闭此输入流并释放与此流关联的所有系统资源。
    read()    从此输入流中读取下一个数据字节。
    read(byte[] b, int off, int len)    将最多 len 个数据字节从此输入流读入 byte 数组。

    //使用第一个构造方法实现2个文件合并SequenceInputStream(InputStream s1, InputStream s2)

    public class Demo2 {
        public static void main(String[] args) throws IOException {
            //找到目标文件的父路径
            File inputfile1 = new File("D:\新建文件夹\a.txt");
            File inputfile2 = new File("D:\新建文件夹\b.txt");
            File outputfile = new File("D:\新建文件夹\c.txt");
            //建立数据通道
            FileInputStream fileInputStream1 = new FileInputStream(inputfile1);
            FileInputStream fileInputStream2 = new FileInputStream(inputfile2);
            FileOutputStream fileOutputStream = new FileOutputStream(outputfile);
    
            SequenceInputStream sequenceInputStream = new SequenceInputStream(fileInputStream1, fileInputStream2);
            
            //创建一个缓存字节数组
            byte[] buf = new byte[1024];
            int length = 0;
            while((length = sequenceInputStream.read(buf))!= -1) {
                fileOutputStream.write(buf, 0, length);
            }
            //先开后关原则
            fileOutputStream.close();
            sequenceInputStream.close();
        }
    }

    那么如果我们有很多个文件要合并呢?
    第二个构造方法:SequenceInputStream(Enumeration<? extends InputStream> e)
    此构造方法要接受一个Vector集合的迭代器

    有序集合的体系:
    -----------------| List   如果实现了List接口的集合类,具备的特点是:有序,可重复
    -------------| ArrayList   ArrayList底层维护的是一个Object类型的数组,特点是:查询快,增删慢
    -------------| LinkList    LinkedList底层使用了链表数据结构实现的。特点是:查询慢,增删快
    -------------| Vector     底层也是维护了一个Object类型的数组,实现与ArrayList一样,但是Vector线程安全,操作效率低

    Vector中的方法:
    elements()   返回一个Enumeration<E>类型的迭代器

    Enumeration接口中的方法:
    hasMoreElements()  判断是否还有下一个元素,有返回true,没有返回false       
    nextElement()          返回下一个元素

    //使用第二个构造方法实现2个文件合并SequenceInputStream(Enumeration<? extends InputStream> e)

    public class Demo3 {
        public static void main(String[] args) throws IOException {
            //找到目标文件的父路径
            File inputfile1 = new File("D:\新建文件夹\a.txt");
            File inputfile2 = new File("D:\新建文件夹\b.txt");
            File inputfile3 = new File("D:\新建文件夹\c.txt");
            File outputfile = new File("D:\新建文件夹\d.txt");
            //建立数据通道
            FileInputStream fileInputStream1 = new FileInputStream(inputfile1);
            FileInputStream fileInputStream2 = new FileInputStream(inputfile2);
            FileInputStream fileInputStream3 = new FileInputStream(inputfile3);
            FileOutputStream fileOutputStream = new FileOutputStream(outputfile);
            
            //把数据通道对象放入Vector有序集合中
            Vector<FileInputStream> vector = new Vector<FileInputStream>();
            vector.add(fileInputStream1);
            vector.add(fileInputStream2);
            vector.add(fileInputStream3);
            //获取迭代器
            Enumeration<FileInputStream> e = vector.elements();
            //创建SequenceInputStream(Enumeration<? extends InputStream> e)对象
            SequenceInputStream sequenceInputStream = new SequenceInputStream(e);
            //创建缓存字节数组
            byte[] buf = new byte[1024];
            //定义变量,用来存储每次存入数组中字节数组的数据长度
            int length = 0;
            //读取所有需要合并的文本并放入数组中
            while((length = sequenceInputStream.read(buf))!= -1) {
                //把数组中的文件写入d.txt文本中
                fileOutputStream.write(buf, 0, length);
            }
            
            fileOutputStream.close();
            sequenceInputStream.close();
        }
    }

    练习:

      需求1:把一个MP3格式音乐切割成n份
    解决:我们可以控制缓存数组的大小,用来分割。如果一个文件的大小是10MB那么我们可以把字节数组大小定义为1MB,那么每次读取的数据是1MB,
    然后我们把每次读取的数据都放在不同文件中,那么就实现了切割了
      需求2:把切割成n份MP3格式的音乐还原

    public class Demo4 {
        public static void main(String[] args) throws Exception {
            //splitMP3();
            mergeMP3();
        }
        
        //需求1:把一个MP3格式音乐切割成n份(注意:被分割的音乐可以播放哦)
        public static void splitMP3() throws IOException {
            //输入的目标
            File inputfile = new File("D:\新建文件夹\阿杜 - 撕夜.mp3");
            //输出的目标文件的父目录
            File outputparentfile = new File("D:\新建文件夹");
            //建立数据通道
            FileInputStream fileInputStream = new FileInputStream(inputfile);
            //建立缓存字节数组,并定义数组大小为1MB(1024字节 = 1kb   1014kb = 1MB)
            byte[] buf = new byte[1024*1024];
            //定义存储每次读取数据的长度的变量
            int length = 0;
            //读取文件并进行分割
            for(int i = 1 ; (length = fileInputStream.read(buf))!=-1 ; i++) {
                FileOutputStream fileOutputStream = new FileOutputStream(new File(outputparentfile, "part"+i+".mp3"));
                fileOutputStream.write(buf, 0, length);
                fileOutputStream.close();
            }
            fileInputStream.close();
        }
        
        //需求2:把切割成n份MP3格式的音乐还原(不按照顺序合并也可以听哦)
        public static void mergeMP3() throws IOException {
            //创建输入文件的父路径
            File inputparentfile = new File("D:\新建文件夹");
            
            //创建Vector有序集合
            Vector<FileInputStream> vector = new Vector<FileInputStream>();
            //定义File类的数组并存储在父路径找到的所有文件的绝对路径
            File[] files =  inputparentfile.listFiles();
            //遍历数组
            for (File temp : files) {
                //筛选出后缀名为MP3的文件temp:文件的绝对路径   getName()文件的名字  endsWith()文件的后缀名
                if(temp.getName().endsWith(".mp3")) {
                    vector.add(new FileInputStream(temp));
                }
            }
            //获取vector的迭代器
            Enumeration<FileInputStream> e = vector.elements();
            //创建输出文件的绝对路径
            File outputfile = new File("D:\新建文件夹\合并.mp3");
            //创建输出数据通道
            FileOutputStream fileOutputStream = new FileOutputStream(outputfile);
            //创建SequenceInputStream对象
            SequenceInputStream sequenceInputStream = new SequenceInputStream(e);
            //创建缓存数组
            byte[] buf = new byte[1024];
            //定义存储每次读取到数据的长度的变量
            int length = 0;
            //边读边写
            while((length = sequenceInputStream.read(buf))!= -1) {
                fileOutputStream.write(buf, 0, length);
            }
            
        }
    }
  • 相关阅读:
    Java根据百度API获得经纬度,然后根据经纬度在获得城市信息
    获取鼠标位置的几个通用的JS函数
    java 定时备份数据库
    基于commons-net实现ftp创建文件夹、上传、下载功能
    java自动识别用户上传的文本文件编码
    CSS3实现10种Loading效果
    Java实现拖拽上传
    JAVA 比较两张图片的相似度的代码
    Java jsp页面中jstl标签详解
    mysql去除重复数据
  • 原文地址:https://www.cnblogs.com/zjdbk/p/9085514.html
Copyright © 2011-2022 走看看