序列流、物件流、列印流和轉換流
序列流、物件流、列印流和轉換流
一、序列流
使用SequenceInputStream進行檔案的合併:
public class Demo1 { public static void main(String[] args) throws IOException { merge3(); } //把三個檔案合併成一個檔案 public static void merge3() throws IOException{ //找到目標檔案 File file1 = new File("F:\\a.txt"); File file2 = new File("F:\\b.txt"); File file3 = new File("F:\\c.txt"); File file4 = new File("F:\\d.txt"); //建立對應 的輸入輸出流物件 FileOutputStream fileOutputStream = new FileOutputStream(file4); FileInputStream fileInputStream1 = new FileInputStream(file1); FileInputStream fileInputStream2 = new FileInputStream(file2); FileInputStream fileInputStream3 = new FileInputStream(file3); //建立序列流物件 Vector<FileInputStream> vector = new Vector<FileInputStream>(); vector.add(fileInputStream1); vector.add(fileInputStream2); vector.add(fileInputStream3); Enumeration<FileInputStream> e = vector.elements(); SequenceInputStream sequenceInputStream = new SequenceInputStream(e); //讀取檔案資料 byte[] buf = new byte[1024]; int length = 0; while((length = sequenceInputStream.read(buf))!=-1){ fileOutputStream.write(buf,0,length); } //關閉資源 sequenceInputStream.close(); fileOutputStream.close(); } //使用SequenceInputStream合併檔案。 public static void merge2() throws IOException{ //找到目標檔案 File inFile1 = new File("F:\\a.txt"); File inFile2 = new File("F:\\b.txt"); File outFile = new File("F:\\c.txt"); //建立資料的輸入輸出通道 FileOutputStream fileOutputStream = new FileOutputStream(outFile); FileInputStream fileInputStream1 = new FileInputStream(inFile1); FileInputStream fileInputStream2 = new FileInputStream(inFile2); //建立序列流物件 SequenceInputStream inputStream = new SequenceInputStream(fileInputStream1,fileInputStream2); byte[] buf = new byte[1024]; int length = 0 ; while((length = inputStream.read(buf))!=-1){ fileOutputStream.write(buf,0,length); } //關閉資源 inputStream.close(); fileOutputStream.close(); } //需求:把a.txt與b.txt 檔案的內容合併。 public static void merge1() throws IOException{ //找到目標檔案 File inFile1 = new File("F:\\a.txt"); File inFile2 = new File("F:\\b.txt"); File outFile = new File("F:\\c.txt"); //建立資料的輸入輸出通道 FileOutputStream fileOutputStream = new FileOutputStream(outFile); FileInputStream fileInputStream1 = new FileInputStream(inFile1); FileInputStream fileInputStream2 = new FileInputStream(inFile2); //把輸入流儲存到集合中,然後再從集合中讀取 ArrayList<FileInputStream> list = new ArrayList<FileInputStream>(); list.add(fileInputStream1); list.add(fileInputStream2); //準備一個緩衝陣列 byte[] buf = new byte[1024]; int length = 0 ; for(int i = 0 ; i< list.size() ; i++){ FileInputStream fileInputStream = list.get(i); while((length = fileInputStream.read(buf))!=-1){ fileOutputStream.write(buf,0,length); } //關閉資源 fileInputStream.close(); } fileOutputStream.close(); } }
二、物件流
物件的輸入輸出流 : 物件的輸入輸出流主要的作用是用於寫物件的資訊與讀取物件的資訊。
物件資訊一旦寫到檔案上那麼物件的資訊就可以做到持久化了。
物件的輸出流: ObjectOutputStream
物件的輸入流: ObjectInputStream
class Address implements Serializable{ String country; String city; public Address(String country,String city){ this.country = country; this.city = city; } } class User implements Serializable{ private static final long serialVersionUID = 1L; String userName ; String password; transient int age;// transient 透明 Address address ; public User(String userName , String passwrod) { this.userName = userName; this.password = passwrod; } public User(String userName , String passwrod,int age,Address address) { this.userName = userName; this.password = passwrod; this.age = age; this.address = address; } @Override public String toString() { return "使用者名稱:"+this.userName+ " 密碼:"+ this.password+" 年齡:"+this.age+" 地址:"+this.address.city; } } public class Demo3 { public static void main(String[] args) throws IOException, Exception { writeObj(); //readObj(); } //把檔案中的物件資訊讀取出來-------->物件的反序列化 public static void readObj() throwsIOException, ClassNotFoundException{ //找到目標檔案 File file = new File("F:\\obj.txt"); //建立資料的輸入通道 FileInputStream fileInputStream = new FileInputStream(file); //建立物件的輸入流物件 ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); //讀取物件資訊 User user = (User) objectInputStream.readObject(); //建立物件肯定要依賴物件所屬的class檔案。 System.out.println("物件的資訊:"+ user); } //定義方法把物件的資訊寫到硬碟上------>物件的序列化。 public static void writeObj() throws IOException{ //把user物件的資訊持久化儲存。 Address address = new Address("中國","深圳"); User user = new User("admin","123",15,address); //找到目標檔案 File file = new File("F:\\obj.txt"); //建立資料輸出流物件 FileOutputStream fileOutputStream = new FileOutputStream(file); //建立物件的輸出流物件 ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); //把物件寫出 objectOutputStream.writeObject(user); //關閉資源 objectOutputStream.close(); } }
物件輸入輸出流要注意的細節:
- 如果物件需要被寫出到檔案上,那麼物件所屬的類必須要實現Serializable介面。 Serializable介面沒有任何的方法,是一個標識介面而已。
- 物件的反序列化建立物件的時候並不會呼叫到構造方法。
- serialVersionUID 是用於記錄class檔案的版本資訊的,serialVersionUID這個數字是通過一個類的類名、成員、包名、工程名算出的一個數字。
- 使用ObjectInputStream反序列化的時候,ObjectInputStream會先讀取檔案中的serialVersionUID,然後與本地的class檔案的serialVersionUID進行對比,如果這兩個id不一致,那麼反序列化就失敗了。
- 如果序列化與反序列化的時候可能會修改類的成員,那麼最好一開始就給這個類指定一個serialVersionUID,如果類已經指定的serialVersionUID,那麼在序列化與反序列化的時候,jvm都不會再自己算這個class的serialVersionUID了。
- 如果一個物件某個資料不想被序列化到硬碟上,可以使用關鍵字transient修飾。
- 如果一個類維護了另外一個類的引用,那麼另外一個類也需要實現Serializable介面。
注意:所有的集合都實現了Serializable介面。
使用transient來修飾變數,則該變數的資訊就不會寫到硬碟上去。
三、列印流(printStream)
列印流可以列印任意型別的資料,而且列印資料之前都會先把資料轉換成字串再進行列印。
class Animal{ String name; String color; public Animal(String name,String color){ this.name = name; this.color = color; } @Override public String toString() { return "名字:"+this.name+ " 顏色:"+ this.color; } } public class Demo { public static void main(String[] args) throws IOException { /*FileOutputStream fileOutputStream = new FileOutputStream("F:\\a.txt"); fileOutputStream.write(97);//寫過去的是a fileOutputStream.write("97".getBytes());//寫過去的是97 fileOutputStream.close();*/ //列印流可以列印任何型別的資料,而且列印資料之前都會先把資料轉換成字串再進行列印。 File file = newFile("F:\\a.txt"); //建立一個列印流 PrintStream printStream = new PrintStream(file); /* printStream.println(97); //97 printStream.println(3.14);//3.14 printStream.println('a');//a printStream.println(true);// Animal a = new Animal("豬", "粉色"); printStream.println(a);//名字:豬 顏色:粉色 //預設標準的輸出流就是向控制檯輸出的, System.setOut(printStream); //重新設定了標準的輸出流物件 讓內容輸出到了PrintStream(file);檔案中。 System.out.println("Hello World!!"); */ //收集異常的日誌資訊。 File logFile = new File("F:\\log.log"); //追加內容 PrintStream logPrintStream = new PrintStream( new FileOutputStream(logFile,true) ); try{ int c = 4/0; System.out.println("c="+c); int[] arr = null; System.out.println(arr.length); }catch(Exception e){ e.printStackTrace(logPrintStream); } } }
四、轉換流
輸入位元組流的轉換流:
InputStreamReader 是位元組流通向字元流的橋
注意:FileReader本身不能指定編碼表,預設使用的是GBK碼錶;使用InputStreamReader(InputStream in,String charsetName)該構造方法可以指定具體的碼錶。
輸出位元組流的轉換流:
OutputStreamWriter 可以把輸出位元組流轉換成輸出字元流
轉換流的作用:
- 如果目前所獲取到的是一個位元組流需要轉換字元流使用,此時就可以使用轉換流。 (位元組流----> 字元流)
- 使用轉換流可以指定編碼表進行讀寫檔案。
public class Demo8 { public static void main(String[] args) throws IOException { //readTest(); //writeTest();' //writeTest2(); readTest2(); } //使用輸入位元組流的轉換流指定碼錶進行讀取檔案資料 public static void readTest2() throws IOException{ File file = new File("F:\\a.txt"); FileInputStream fileInputStream = new FileInputStream(file); //建立位元組流的轉換流並且指定碼錶進行讀取 InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8"); char[] buf = new char[1024]; int length = 0; while((length = inputStreamReader.read(buf))!=-1){ System.out.println(new String(buf,0,length)); } } //使用輸出位元組流的轉換流指定碼錶寫出資料 public static void writeTest2() throws IOException{ File file = new File("F:\\a.txt"); //建立資料的輸出通道 FileOutputStream fileOutputStream = new FileOutputStream(file); //把輸出位元組流轉換成字元流並且指定編碼表。 OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8"); outputStreamWriter.write("你好世界"); //關閉資源 outputStreamWriter.close(); } public static void writeTest() throws IOException{ File file = new File("F:\\a.txt"); FileOutputStream fileOutputStream = new FileOutputStream(file); //把輸出位元組流轉換成輸出字元流。 OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream); outputStreamWriter.write("你好世界"); outputStreamWriter.close(); } public static void readTest() throws IOException{ InputStream in = System.in; //獲取了標準的輸入流。 //System.out.println("讀取的字元:"+ (char)in.read());//讀取控制檯的內容,read()一次只能讀取一個位元組。 //把位元組流轉換成字元流。 InputStreamReader inputStreamReader = new InputStreamReader(in); //使用字元流的緩衝類 BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String line = null; while((line = bufferedReader.readLine())!=null){ System.out.println("內容:"+ line); } } }