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 = newFileInputStream(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); } } }
70. SequenceInputStream(文件合並)