Java基礎知識整理:IO流

IO:

I:input 輸入
O:output 輸出

輸入:將外部的數據讀取到程序的內存中。
輸出:將程序內存中的數據寫出到其他的地方。

IO 流

File 類:不能對文件讀寫。

需要通過IO 流來實現對文件的讀寫。

概念:流就是信息的通道。通過該通道可以實現對文件的讀寫操作。 stream

流的分類:

   1:按照數據的流向來分:
           1:輸入流  可以將外部的數據讀取內存中的流   InputStream、Reader
           2:輸出流  將內存中的數據寫出到目的地的流   OutputStream、Writer


   2:按照流處理的最小的數據單元來分:
           1:字節流  流每次處理的數據的最小單元是 1 byte。 InputStream   OutputStream
           2:字符流  流每次處理的數據的最小單元是 1個 char Reader   Writer

           字節流,什麼類型的數據都可以處理。音頻,視頻,圖片,文本。
           字符流,只能處理文本數據。別的類型不能處理。處理字符功能更強。

   3:按照處理的數據的源頭不同來分:
           1:節點流 :直接和數據源相連的流。 FileInputStream FileOutputStream
           2:處理流、包裝流:以其他的流爲數據源的流。 BufferedInputStream  BufferedOutputStream

InputStream:是一個抽象類,是所有的字節輸入流的父類。
OutputStream:是一個抽象類,是所有的字節輸出流的父類。

Reader:是一個抽象類,是所有的字符輸入流的父類
Writer:是一個抽象類,使所有的字符輸出流的父類。

FileInputStream

和IO 相關的類 都在 java.io.*;

FileInputStream: 是InputStream 的子類。
文件 字節 輸入 節點流 。 可以用來將文件中的內容,讀取到內存中來。
看入參,一般選擇這兩種

在這裏插入圖片描述
read()看代碼中,註釋
在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class FileInputOutStreamTest {

       public static void main(String[] args) {
               testFileInputStream2();
       }


       //將指定的文件的內容全部讀取到內容中,並打印到控制檯。
       static void testFileInputStream(){
               //創建文件對象
               File file = new File("res/my_letter.txt");
               try {
                       //創建流對象,在程序內存和 數據源之間建立了信息的通道。
                       
                       FileInputStream fis = new FileInputStream(file);
                       //流對象提供了那些功能來讀取數據源的信息。
                       //從數據源讀取一個字節的數據,並返回  返回類型是 int。
                       //read 方法每次被調用,都會導致 流中記錄讀取位置的遊標後移一個字節。
                       //讀取下一個字節的數據。 如果流中不能在讀取到數據(讀取到了文件or 流的末尾返回-1)
                       int value = fis.read();
                       while(value != -1){//沒有到達數據的末尾
                               System.out.print((char)value);
                               value = fis.read();
                       }

               } catch (Exception e) {
                       e.printStackTrace();
               }
       }

       //將指定的文件的內容全部讀取到內容中,並打印到控制檯。
       static void testFileInputStream1(){
               //創建文件對象
               File file = new File("res/my_letter.txt");
               try {
                       //創建流對象,在程序內存和 數據源之間建立了信息的通道。
                       FileInputStream fis = new FileInputStream(file);
                       //流對象提供了那些功能來讀取數據源的信息。
                       byte[] buf = new byte[10];
                       //每次通過流從數據源最多可以讀取buf.length個字節的數據。
                       //被讀取的字節數據保存到 數組中。返回的是本次讀取到的有效的字節數。
                       //如果讀取到了文件的末尾,返回 -1;
                       int count = fis.read(buf);
                       while(count != -1){
                               //是用字節數組生成字符串對象 如果不加0,count,將會出現 最後一次數組內保存的是上一次的數據。所以要讀取最新的長度。
                               String str = new String(buf,0,count);
                               System.out.print(str);
                               count = fis.read(buf);
                       }

                       //讀取數據放到指定數組的區間中。
                       //                                fis.read(b, off, len)

               } catch (Exception e) {
                       e.printStackTrace();
               }
       }
       
       //測試其他的方法
       static void testFileInputStream2(){
               //創建文件對象
               File file = new File("res/my_letter.txt");
               FileInputStream fis = null;
               try {
                       //創建流對象,在程序內存和 數據源之間建立了信息的通道。
                       fis = new FileInputStream(file);
                       //TODO
//                        int count = 0;
//                        while((count = fis.read(buf))!= -1){
//                                String str = new String(buf,0,count);
//                                System.out.print(str);
//                        }
                       //跳過指定的字節數
                       fis.skip(10);
                       //得到文件的長度,創建足夠大的數據
                       long len = file.length();
                       byte[] buf = new byte[(int)len];
                       fis.read(buf);
                       String str = new String(buf);
                       System.out.println(str);
                       
                       // 得到的文件中可以讀取到的有效的字節數據個數
                       fis.available();
                       //

               } catch (Exception e) {
                       e.printStackTrace();
               }finally {
                       //要確保程序可以正常的關閉流對象。如果不關閉,那麼垃圾回收器都不能正常回收掉。
                       if(fis != null){
                               try {
                                       fis.close();
                               } catch (IOException e) {
                                       e.printStackTrace();
                               }
                       }
               }
       }



}

FileOutputStream

FileOutputStream: OutputStream 的子類。
文件字節輸出節點流:

作用:對文件進行寫入數據的。


//對指定的文件寫入指定的內容
       static void testFileOutputStream(){
               //
               FileOutputStream fos = null;
               try {
                       //創建流對象,當下面的語句執行的時候,會先將目的地的數據清空,然後再寫入。
                       fos = new FileOutputStream("./res/2.txt",true);//true ,尾部添加,默認爲false。
                       String str = "我女兒喜歡看海底小縱隊,她是裏面的皮醫生!我呢,是呱唧!\n";
                       //將字符串轉換爲字節數組
                       byte[] buf = str.getBytes();
                       //通過流對象去寫出指定內容
                       //將buf 中的全部的字節數據寫出到目的地
                       fos.write(buf);
                       //fos.write(int) 將參數 int 的對應的字節數據寫出去,每次寫出一個字節。把參數的後八位寫出去。
                       
               } catch (Exception e) {
                       e.printStackTrace();
               }finally {
                       if(fos != null){
                               try {
                                       fos.close();
                               } catch (IOException e) {
                                       e.printStackTrace();
                               }
                       }
               }
       }
       
       //使用文件輸入輸出流來實現文件的複製。。如果文件不存在,那麼使用FileOutputStream 往外寫,那麼會創建一個文件。
       static void copyFile()throws Exception{
               // 使用 文件輸入流,讀取字節數據,然後將讀取到的字節數據,再尾部追加到指定的文件中。
               FileInputStream fis = new FileInputStream("c:/dear.jpg");
               FileOutputStream fos = new FileOutputStream("c:/dear_copy.jpg",true);
               
               byte[] buf = new byte[1000];
               
               int count = fis.read(buf);
               while(count != -1){
                       //讀取多少數據,寫出去多少數據
                       fos.write(buf,0,count);
                       count = fis.read(buf);
               }
               
               fis.close();
               fos.close();
       }
       

read int write

read 讀取的是一個字節,返回的卻是 int???

原因:爲了避免讀取到的字節數據 是 八個二進制 的 1 的數據(-1)。如果讀取到了一個 字節數據 是 -1 ,那麼和 流的末尾的條件衝突。

即使讀取到了8個 二進制的1 ,需要轉換爲 int 類型。

使用int 的低八位 保存讀取到的 一個字節數據。
1111 1111 111111111111111111111111
000000000000000000000000 1111 1111 255

怎麼實現的呢?
使用按位與 &
&0xff 來實現 需求 使用int 的低八位 保存讀取到的 一個字節數據。

wirte(int value) 只將 value 的低八位寫出去。 (byte)value. 直接將 value 的高24位 全部砍掉了。

字符集

1:美國標準信息交換碼:ASCII。
單字節的字符集 一共128個字符,只用到了一個字節數據的低7位。最高位是0. 每一個字符都對應着一個唯一的整數。
A<—>65 0<---->48 a<—>97

2: gb2312:是中國早期的一個字符集。兼容了ASCII。用一個字節的數據表示 ASCII 部分的字符。
中文簡體,需要兩個字節的數據才能表示一箇中文字符。

3:gbk:兼容了gb2312. 增加了各個少數民族的符號,繁體中文。
中文簡體,需要兩個字節的數據才能表示一箇中文字符。

4:utf-8:兼容了ASCII。三個字節代表一箇中文。

5: iso8859-1:西歐字符集 ,單字節 256的字符。

5:Unicode:

FileReader-FileWriter

FileReader: 是 Reader 的子類。

是用來讀取字符的。

FileReader :可以每次實現從底層的字節數據中讀取一個或者多個字節數據,來保證這些字節數據是一個或者幾個完整的字符。要依賴於某個字符集(平臺默認的GBK)

FileReader,從底層讀取的是字節數據(整數)去默認的字符集中 找該整數對應的字符。 依賴的是平臺默認的 GBK

所有的字符流工作的時候都要依賴於某個字符集。

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;

public class TestFileReaderWriter {

       public static void main(String[] args) {
//                testFileReader();
               copyTextFile();
       }
       
       //從指定的文件中,讀取全部的字符
       static void testFileReader(){
               FileReader fr = null;
               try {
                       //創建字符輸入流對象
                       fr = new FileReader("./res/1.txt");
                       int value = fr.read();
                       while(value != -1){
                               System.out.print((char)value);
                               value = fr.read();
                       }
               } catch (Exception e) {
                       e.printStackTrace();
               }finally {
                       if(fr != null){
                               try {
                                       fr.close();
                               } catch (IOException e) {
                                       e.printStackTrace();
                               }
                       }
               }
       }
       
       //使用文件字符輸入輸出流實現文本的複製
       static void copyTextFile(){
               FileReader fr = null;
               FileWriter fw = null;
               try {
                       fr = new FileReader("./res/my_letter.txt");
                       fw = new FileWriter("./res/my_letter_todear.txt");
//                        int value = 0;
//                        while((value = fr.read())!= -1){
//                                //將value 寫出去
//                                fw.write(value);
//                        }
                       char[] buf = new char[10];
                       int count = 0;
                       while((count = fr.read(buf)) != -1){
                               System.out.println(Arrays.toString(buf));
                               //這個write 方法,並沒有直接將字符數據寫出到 目的文件中,
                               //寫到了一個緩衝區中。爲了減少直接對磁盤的IO 提高效率
                               //解決方案:1 把流正常關閉,關閉流的時候,所有的相關的緩衝區中的數據都將會被刷新到目的地。
                               //2:將緩衝區的數據,刷新出去。
                               fw.write(buf, 0, count);
                       }
                       //將緩衝區的數據,刷新出去到目的地。
                       fw.flush();
               } catch (Exception e) {
                       e.printStackTrace();
               }finally {
                       if(fr != null){
                               try {
                                       fr.close();
                               } catch (IOException e) {
                                       e.printStackTrace();
                               }
                       }
                       if(fw != null){
                               try {
                                       fw.close();
                               } catch (IOException e) {
                                       e.printStackTrace();
                               }
                       }
                       
               }
       }
       

}


flush

//使用文件字符輸入輸出流實現文本的複製
       static void copyTextFile(){
               FileReader fr = null;
               FileWriter fw = null;
               try {
                       fr = new FileReader("./res/my_letter.txt");
                       fw = new FileWriter("./res/my_letter_todear.txt");
                       char[] buf = new char[10];
                       int count = 0;
                       while((count = fr.read(buf)) != -1){
                               System.out.println(Arrays.toString(buf));
                               //這個write 方法,並沒有直接將字符數據寫出到 目的文件中,
                               //寫到了一個緩衝區中。爲了減少直接對磁盤的IO 提高效率
                               //解決方案:1 把流正常關閉,關閉流的時候,所有的相關的緩衝區中的數據都將會被刷新到目的地。
                               //2:將緩衝區的數據,刷新出去。
                               fw.write(buf, 0, count);
                       }
                       //將緩衝區的數據,刷新出去到目的地。
                       fw.flush();
               } catch (Exception e) {
                       e.printStackTrace();
               }finally {
                       if(fr != null){
                               try {
                                       fr.close();
                               } catch (IOException e) {
                                       e.printStackTrace();
                               }
                       }
                       if(fw != null){
                               try {
                                       fw.close();
                               } catch (IOException e) {
                                       e.printStackTrace();
                               }
                       }
                       
               }
       }

BufferedInputStream-BufferedOutputStream

BufferedInputStream
BufferedOutputStream

帶緩衝區的字節輸入輸出流。 爲了提高讀寫的效率。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedInputOutputStreamTest {

   public static void main(String[] args) {
           long time = System.currentTimeMillis();
           copyFile();
           long cost = System.currentTimeMillis()-time;
           System.out.println("buffered cost = "+cost);

           time = System.currentTimeMillis();
           try {
                   copyFile1();
           } catch (Exception e) {
                   e.printStackTrace();
           }
           cost = System.currentTimeMillis()-time;
           System.out.println("cost = "+cost);
   }


   //帶緩衝區實現文件複製
   static void copyFile(){
           BufferedInputStream bis = null;
           BufferedOutputStream bos = null;
           try {
                   //這是一個包裝流,以其他的流爲數據源讀取數據。爲了提高效率的
                   bis = new BufferedInputStream(new FileInputStream("c:/dear.jpg"));
                   bos = new BufferedOutputStream(new FileOutputStream("c:/nan.jpg"));

                   byte[] buf = new byte[100];
                   int count = bis.read(buf);
                   while(count != -1){
                           bos.write(buf, 0, count);
                           count = bis.read(buf);
                   }

           } catch (Exception e) {
                   e.printStackTrace();
           }finally {
                   if(bis != null){
                           try {
                                   bis.close();
                           } catch (IOException e) {
                                   e.printStackTrace();
                           }
                   }
                   if(bos != null){
                           try {
                                   bos.close();
                           } catch (IOException e) {
                                   e.printStackTrace();
                           }
                   }
           }
   }

   //使用文件輸入輸出流來實現文件的複製。。如果文件不存在,那麼使用FileOutputStream 往外寫,那麼會創建一個文件。
   static void copyFile1()throws Exception{
           // 使用 文件輸入流,讀取字節數據,然後將讀取到的字節數據,再尾部追加到指定的文件中。
           FileInputStream fis = new FileInputStream("c:/dear.jpg");
           FileOutputStream fos = new FileOutputStream("c:/dear_copy.jpg",true);

           byte[] buf = new byte[1000];

           int count = fis.read(buf);
           while(count != -1){
                   //讀取多少數據,寫出去多少數據
                   fos.write(buf,0,count);
                   count = fis.read(buf);
           }

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

}

MyBufferedInputStream

import java.io.InputStream;
import java.io.OutputStream;

/**
* 自定義的帶緩衝區的字節輸入流,模擬  java.io.BufferedInputStream
* @author yhl
*
*/
public class MyBufferedInputStream {
       //定義默認的緩衝區大小
       public static final int DEFAULT_BUF_SIZE = 8192;
       //字節數組緩衝區
       private byte[] buf;
       //用於讀取數據源的字節輸入流的引用,可以是任意的字節輸入流
       private InputStream is;
       //記錄當前讀取到的字節數組數據的下標
       private int pos;
       //用於記錄緩衝區中有效的字節數據
       private int count;
       
       public MyBufferedInputStream(InputStream is) {
               this.is = is;
               buf = new byte[DEFAULT_BUF_SIZE];
       }
       
       public MyBufferedInputStream(InputStream is,int bufSize) {
               this.is = is;
               buf = new byte[bufSize];
       }
       
       //最核心對外提供的read 方法 讀取下一個字節的數據
       //從buf 中取一個字節的數據
       public int read() throws Exception{
               if(count == 0){//緩衝區沒有數據了
                       //一次性從通過is 讀取底層數據 到buf 中,並記錄讀取到了多少有效字節數據。
                       count = is.read(buf);
                       //一種是 數據源還有數據,一種是數據源沒有數據了,返回-1
                       if(count == -1)//return -1
                               return -1;
                       pos = 0;
                       //使用int 的低八位 保存 讀取到的字節數據。
                       int value = buf[pos] & 0xff;
                       pos ++;
                       count --;
                       return value;
               }else{//緩衝區有數據
                       int value = buf[pos] & 0xff;
                       pos ++;
                       count --;
                       return value;
               }
       }
       
       //包裝流的關閉問題,關閉的是被包裝的流。
       public void close() throws Exception{
               if(is != null){
                       is.close();
               }
       }
       
}

MyBufferedOutputStream

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class TestMyBufferedStream {

       public static void main(String[] args) {
               long time = System.currentTimeMillis();
               
               BufferedInputOutputStreamTest.copyFile();
               
               long cost = System.currentTimeMillis()-time;
               System.out.println("buffered cost = "+cost);
               

               time = System.currentTimeMillis();
               try {
                       copyFile();
               } catch (Exception e) {
                       e.printStackTrace();
               }
               cost = System.currentTimeMillis()-time;
               System.out.println("myBuffered cost = "+cost);
       }
       
       static void copyFile() throws Exception{
               
               MyBufferedInputStream mbis = new MyBufferedInputStream(new FileInputStream("c:/77.jpg"));
               MyBufferedOutputStream mbos = new MyBufferedOutputStream(new FileOutputStream("c:/99.jpg"));
               
               int value = 0;
               while((value = mbis.read()) != -1){
                       mbos.write(value);
               }
               
               mbis.close();
               mbos.flush();
               mbos.close();
               
       }
}




/**
* 自定義的帶緩衝區的輸出流
* @author yhl
*
*/
class MyBufferedOutputStream{
       //定義默認的緩衝區大小
               public static final int DEFAULT_BUF_SIZE = 8192;
               //字節數組緩衝區
               private byte[] buf;
               //用於讀取數據源的字節輸入流的引用,可以是任意的字節輸入流
               private OutputStream os;
               //用於記錄寫入緩衝區的字節數據的個數,和當前待寫入數組元素的下標
               private int pos;
               
               public MyBufferedOutputStream(OutputStream os) {
                       this.os = os;
                       buf = new byte[DEFAULT_BUF_SIZE];
               }
               
               public MyBufferedOutputStream(OutputStream os,int bufSize) {
                       this.os = os;
                       buf = new byte[bufSize];
               }
               
               /**
                * 將value 的後八位寫出去
                * @param value
                */
               public void write(int value) throws Exception{
                       //緩衝區滿了
                       if(pos == buf.length){
                               //將緩衝區的內容全部寫出去
                               os.write(buf);
                               pos = 0;
                               //然後再將value 寫入下標pos = 0 的位置
                               buf[pos] = (byte)value;
                               //pos 永遠指向 待寫入數據的下標
                               pos ++;
                       }else{//緩衝區沒有滿
                               //將value 寫入pos 位置
                               buf[pos] = (byte)value;
                               //pos 永遠指向 待寫入數據的下標
                               pos ++;
                       }
               }
               
               public void flush() throws Exception{
                       if(pos != 0){
                               //將緩衝區中沒有寫出去的數據,刷新到目的地
                               os.write(buf, 0, pos);
                               pos = 0;
                       }
               }
               
               //
               public void close() throws Exception{
                       if(os != null){
                               //確保在關閉的時候,可以將緩衝區中的數據刷新出去
                               flush();
                               os.close();
                       }
               }
               
}


包裝流的關閉問題:
   只關閉包裝流即可,因爲在關閉包裝流的方法中,對被包裝的流進行了關閉。

   如果 將包裝流和 被包裝的流全部關閉。關閉的順序:先打開的後關閉。

BufferedReader-BufferedWriter

BufferedReader
BufferedWriter

帶緩衝區的字符流。

緩衝區 8192 個字符。 char[]

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedReaderWriterTest {

       public static void main(String[] args) {
               copyTextFile();
       }
       
       
       static void copyTextFile(){
               FileReader fr = null;
               BufferedReader br = null;
               
               FileWriter fw = null;
               BufferedWriter bw = null;
               
               try {
                       fr = new FileReader("./res/my_letter.txt");
                       br = new BufferedReader(fr);
                       
                       fw = new FileWriter("./res/my_letter_copy.txt");
                       bw = new BufferedWriter(fw);
                       //用於讀取一行文本數據,如果方法返回null 則表示讀取到了文件的末尾
                       String str = br.readLine();
                       while(str != null){
                               bw.write(str);
                               //向輸出流中寫出一個當前系統的換行符  
                               bw.newLine();
                               str = br.readLine();
                       }
                       
               } catch (Exception e) {
                       e.printStackTrace();
               }finally {
                       if(br != null){
                               try {
                                       br.close();
                               } catch (IOException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                               }
                       }
                       if(bw != null){
                               try {
                                       bw.close();
                               } catch (IOException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                               }
                       }
                       if(fr != null){
                               try {
                                       fr.close();
                               } catch (IOException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                               }
                       }
                       if(fw != null){
                               try {
                                       fw.close();
                               } catch (IOException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                               }
                       }
               }
       }

}


readLine原理

readLine():用於讀取一行文本數據。當讀取到\r\n時候方法返回。把讀取到的所有的內容返回,返回的內容中不包含 \r\n .

LineNumberReader

LineNumberReader:是BufferedReader 的子類。增加了用於記錄讀取到文本數據的多少行的功能。

import java.io.FileReader;
import java.io.LineNumberReader;

public class LineNumberReaderTest {
       //將當前文件的所有的內容,打印到控制檯,輸出的時候,還有行號輸出。
       public static void main(String[] args) throws Exception{
               
               LineNumberReader lnr = new LineNumberReader(new FileReader("./src/com/bjsxt/io/LineNumberReaderTest.java"));
               
               //設置起始行號
               lnr.setLineNumber(100);
               String str = null;
               //讀取一行,並打印一行
               while((str = lnr.readLine()) != null){
                       //獲得行號
                       int number = lnr.getLineNumber();
                       System.out.println(number + " "+str);
               }
               
               lnr.close();
               
       }

}

裝飾設計模式

裝飾設計模式:
帶緩衝區的字節流,字符流都使用了該設計模式。

作用:增強擴展指定的類的。

public class DecorateTest {
       public static void main(String[] args) {
               SuperPeople people = new SuperPeople(new Person());
               people.eat();
       }
}

class Person{
       void eat(){
               System.out.println("人要喫飯,爲了生存!");
       }
}
//繼承擴展現有的類
class SuperPerson extends Person{
       void eat(){
               System.out.println("人喫飯不僅僅是爲了生存,還是爲了更好的生存!享受健康的生活");
       }
}

//使用組合擴展現有類
//組合優於繼承:組合既可以擴展指定的類型,還可以是指定類型的子類型。
class SuperPeople {
       //被擴展的類作爲擴展類的實例成員  組合
       private Person person;
       
       public SuperPeople(Person person) {
               this.person = person;
       }
       
       void eat(){
               System.out.println("我喜歡喫魚!");
               System.out.println("我喜歡羊腿+啤酒(不能太涼,慫人樂即可)!");
               person.eat();
       }
}


InputStreamReader-OutputStreamWriter

InputStreamReader:轉換流:從字節到字符的轉換的流。 字符流
解碼器 所有的字符流都以它爲基礎進行工作。

public class InputStreamReader extends Reader
InputStreamReader 是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺默認的字符集。

每次調用 InputStreamReader 中的一個 read() 方法都會導致從底層輸入流讀取一個或多個字節。

InputStreamReader :給它提供一堆字節數據,它可以根據字符集返回給你一堆字符數據。
喫的是字節,擠的是字符。

所有的字符輸出流,最終寫到磁盤中的是 字節數據。
write(String)

OutputStreamWriter: 字符輸出流

public class OutputStreamWriter extends Writer
OutputStreamWriter 是字符流通向字節流的橋樑:可使用指定的 charset 將要寫入流中的字符編碼成字節。它使用的字符集可以由名稱指定或顯式給定,否則將接受平臺默認的字符集。

每次調用 write() 方法都會導致在給定字符(或字符集)上調用編碼轉換器。在寫入底層輸出流之前,得到的這些字節將在緩衝區中累積。可以指定此緩衝區的大小,不過,默認的緩衝區對多數用途來說已足夠大。注意,傳遞給 write() 方法的字符沒有緩衝。

爲了獲得最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以避免頻繁調用轉換器。

總結:
InputStreamReader 是所有的字符輸入流字節到字符轉換的基礎。解碼轉換器。是所有的字符輸入流的實現都依賴於該類提供的解碼的功能。
OutputStreamWriter 是所有的字符輸出流字符到字節轉換的基礎。編碼轉換器。是所有的字符輸出流的實現都依賴於該類提供的編碼的功能。

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;

public class InputStreamReaderTest {

       public static void main(String[] args) throws Exception {
               test1();
       }
       
       
       static void test() throws Exception{
               //如果不顯示指定字符集,使用平臺默認的字符集工作的 轉換流,給它提供字節數據
               //可以顯式指定字符集
               InputStreamReader isr = new InputStreamReader(new FileInputStream("./res/3.txt"),"utf-8");
               BufferedReader br = new BufferedReader(isr);
               
               String str = br.readLine();
               while(str != null){
                       System.out.println(str);
                       str = br.readLine();
               }
               br.close();
       }
       
       //接收鍵盤的輸入,將輸入的內容寫入到指定的文件中。如果輸入了bye,那麼輸入終止
       static void test1() throws Exception{
               //將鍵盤輸入的字節流,轉換爲字符流
               InputStreamReader isr = new InputStreamReader(System.in);
               //爲了提高效率 使用BufferedReader 包一層
               BufferedReader br = new BufferedReader(isr);
               
               BufferedWriter bw = new BufferedWriter(new FileWriter("./res/input.txt"));
               //接收鍵盤的輸入了,當回車的時候,該方法返回。
               String str = br.readLine();
               while(!"bye".equals(str)){
                       bw.write(str);
                       bw.newLine();
                       bw.flush();
                       str = br.readLine();
               }
               
               br.close();
               bw.close();
       }

}
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

public class OutputStreamWriterTest {

       public static void main(String[] args) throws Exception {
               test();
       }
       
       static void test() throws Exception{
               //使用平臺默認的字符集進行編碼 成字節,通過out 字節流,將 編碼得到的字節寫出到底層
//                OutputStreamWriter osw = new OutputStreamWriter(out)
               OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("./res/6.txt"),"UTF-8");
               BufferedWriter bw = new BufferedWriter(osw);
               //寫到bw 中的緩衝區中
               bw.write("月上柳梢頭,人約黃昏後!");
               bw.close();
       }

}

編碼-解碼

密文:21356 28746 893489 4390
密碼本:將密文 翻譯爲 明文
明文:

解碼:密文—>明文
編碼:明文—>密文

程序:
字節數據:密文
字符集:整數和字符對應的一個映射表
字節數據對應的字符序列:明文

程序中:
編碼:字符–>字節
解碼:字節–>字符

適配器設計模式

InputStreamReader :

InputStreamReader :喫的是字節,產出的是字符。

適配器:Adapter:

筆記本 和 手機充電器 中的適配器 的作用: 喫的是生活電壓(220V),產出的是我們筆記本,和手機充電需要的電壓。

類適配器設計模式
對象適配器設計模式

public class AdapterTest {

       public static void main(String[] args) {
//                MyAdapter adapter = new MyAdapter();
//                adapter.run();
               
               MyObjAdapter adapter = new MyObjAdapter(new Adaptee());
               adapter.run();
       }

}

//底層工作的電壓
class Adaptee{
       int run(){
               System.out.println("我提供了220V的電壓");
               return 220;
       }
}

//類適配器設計模式  使用繼承
class MyAdapter extends Adaptee{
       //筆記本的工作電壓爲22V
       int run() {
               int num = super.run();
               System.out.println("220V電壓被轉換爲22V工作電壓了!");
               return num/10;
       }
}

//對象適配器設計模式   使用組合方式    把被適配的對象作爲 成員存在
class MyObjAdapter{
       Adaptee adaptee;
       public MyObjAdapter(Adaptee adaptee) {
               this.adaptee = adaptee;
       }
       int run(){
               int num = adaptee.run();
               System.out.println("220V電壓被轉換爲22V工作電壓了!");
               return num/10;
       }
}


PrintStream

PrintStream:
打印流,只有輸出流,沒有輸入流。字節流。

作用:
提供了對8種基本數據類型,以及String,以及對象的轉換爲字符串(PrintStream內部實現),然後寫出去的方法。
寫入字符串並寫入換行符的方法。

特點:
1:只有輸出流,沒有輸入流
2:PrintStream 永遠不會拋出 IOException。
3:PrintStream 提供了自動刷新的功能。

System.out 就是PrintStream 的一個靜態的實例。 在系統啓動的時候就初始化好了。對應着標準的輸出設備,控制檯。
System.in 是一個InputStream 的靜態的實例。在系統啓動的時候初始化好。對應着標準輸入設備 鍵盤。
System.err 就是PrintStream 的一個靜態的實例,系統啓動初始化。 錯誤打印流,輸出的內容爲紅色。

改變標準輸入輸出設備

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class PrintStreamTest {

       public static void main(String[] args) throws Exception {
               test5();
       }
       
       //八種基本數據類型和 String 和 對象的字符串 輸出到指定的文件中
       static void test1() throws Exception{
               //自動刷新功能
               PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("./res/ps.txt")), true);
               ps.println(127);
               ps.println(3232);
               ps.println(100000000);
               ps.println(10000000000000L);
               
               ps.println(1.0);
               ps.println(1.0f);
               
               ps.println('A');
               ps.println(false);
               
               ps.println("fjdsljfowe;iuro");
               
               ps.println(new PrintStreamTest());
               
               ps.close();
       }
       
       //改變標準輸出設備
       static void test2() throws Exception{
               PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("./res/ps.txt",true)), true);
               PrintStream out = System.out;
               //改變標準輸出流,
               System.setOut(ps);
               System.out.println("11111111111");
               System.out.println("11111111111");
               System.out.println("11111111111");
               System.out.println("11111111111");
               System.out.println("11111111111");
               
               System.setOut(out);
               System.out.println(343);
               ps.close();
       }
       
       //改變標準輸入設備
       static void test3() throws Exception{
               FileInputStream fis = new FileInputStream("./res/my_letter.txt");
               System.setIn(fis);
               
               BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
               
               System.out.println(br.readLine());
               
               br.close();
       }
       
       
       //面試題
       static  void test4(){
               int x = 10;
               //重寫一個PrintStream 的println(int) 方法
               PrintStream ps = new PrintStream(System.out){
                       @Override
                       public void println(int x) {
                               System.out.println("x = "+x);
                       }
               };
               //重新設置out
               System.setOut(ps);
               
               //x = 10;  重寫println 方法
               System.out.println(x);
       }
       
       //PrintStream 的應用
       //
       static void test5() throws FileNotFoundException{
               try {
                       int a = 10;
                       int b = 0;
                       a/=b;
               } catch (Exception e) {
//                        e.printStackTrace();
                       //將異常信息輸出到打印流中
                       PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("./res/exception.log",true)),true);
                       Date date = new Date();
                       DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                       ps.println("************************************************************");
                       ps.println(sdf.format(date));
                       e.printStackTrace(ps);
                       ps.println("************************************************************");
                       ps.close();
               }
       }
       
       
       
       
       

}

打印異常信息

//PrintStream 的應用
       //
       static void test5() throws FileNotFoundException{
               try {
                       int a = 10;
                       int b = 0;
                       a/=b;
               } catch (Exception e) {
//                        e.printStackTrace();
                       //將異常信息輸出到打印流中
                       PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("./res/exception.log",true)),true);
                       Date date = new Date();
                       DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                       ps.println("************************************************************");
                       ps.println(sdf.format(date));
                       e.printStackTrace(ps);
                       ps.println("************************************************************");
                       ps.close();
               }
       }
       

PrintWriter

PrintWriter 是字符打印流。

和PrintStream 的區別:

1:構造方法,PrintWriter 多了2個可以用使用向字符流作爲輸出 的構造方法。
2:PrintWriter 沒有提供原始的 write(字節) 寫出字節數據的方法。

DataInputStream-DataOutputStream

DataInputStream
DataOutputStream

數據輸入輸出字節流。

這兩個流在一種特定的時候使用。

作用:這兩個流提供了對8種基本數據類型和 String(UTF-8)類型 的原始字節數據的讀寫的方法。

1
000000000000000000000000000000001

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class DataInputOutputStreamTest {

       public static void main(String[] args) throws Exception {
//                writeData();
               readData();
       }
       
       //使用DataOutputStream 寫出8種基本數據類型和 字符串
       static void writeData() throws Exception{
               
               DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("./res/7.txt")));
               
               dos.writeByte(1);//1
               dos.writeShort(1);//2
               dos.writeInt(1);//4
               dos.writeLong(1L);//8
               
               dos.writeFloat(1.0f);//4
               dos.writeDouble(1.1);//8
               //
               dos.writeBoolean(true);//1
               dos.writeChar('你');//2
               //使用utf-8 將字符序列編碼爲字節
               //先寫入一個writeShort(short value)  value 值的大小是  當前要寫入的字符串 使用utf-8 編碼爲的字節數組的長度
               dos.writeUTF("起風了");//9
               
               dos.close();
               
       }
       //什麼樣的順序寫入,那麼就需要什麼樣的順序讀出去
       static void readData() throws Exception{
               DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("./res/7.txt")));
               
               System.out.println(dis.readByte());
               System.out.println(dis.readShort());
               System.out.println(dis.readInt());
               System.out.println(dis.readLong());
               System.out.println(dis.readFloat());
               System.out.println(dis.readDouble());
               System.out.println(dis.readBoolean());
               System.out.println(dis.readChar());
               //先readShort  得到接下來的使用多長的字節數組還原 字符序列。
               System.out.println(dis.readUTF());//??讀多少字節

               dis.close();
               
       }

}

Properties

java.util.Properties:這是一個容器。

是Hashtable 的子類。 是一個用於保存鍵值對的容器。

特點:
1:沒有泛型,key 和 value 必須都是 String。
2:支持中文不好。
3:用於操作配置的文件。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;

/**
* 配置文件
* @author yhl
*
*/
public class PropertiesTest {

       public static void main(String[] args) throws Exception {
               test4();
       }
       //使用Properties 創建一個配置文件
       //配置信息  fontSize=20   bkColor=red
       static void test1() throws Exception{
               //創建Properties 對象
               Properties prop = new Properties();
               //將配置的信息 添加到 容器中
               prop.setProperty("fontSize", "20");
               prop.setProperty("bkColor", "red");
               //生成配置文件
               prop.store(new FileOutputStream("./res/prop.ini"), "我是註釋");
               
       }
       
       //修改配置文件的信息
       static void test2() throws Exception{
               //將配置文件的信息加載進來
               Properties prop = new Properties();
               prop.load(new FileReader("./res/prop.ini"));
               System.out.println(prop);
               //修改
               prop.setProperty("bkColor", "black");
               prop.setProperty("fontSize", "12");
               //保存
               prop.store(new FileOutputStream("./res/prop.ini"), "I am the comments");
       }
       
       static void test3(){
               //裝的是所有的jvm 啓動的時候,加載的本地系統的配置信息
               Properties properties = System.getProperties();
               
               Set<Object> set = properties.keySet();
               Iterator<Object> iterator = set.iterator();
               while (iterator.hasNext()) {
                       String key = (String) iterator.next();
                       String value = properties.getProperty(key);
                       System.out.println(key+"-->"+value);
               }
       }
       
       
       

}

系統信息

       static void test3(){
               //裝的是所有的jvm 啓動的時候,加載的本地系統的配置信息
               Properties properties = System.getProperties();
               
               Set<Object> set = properties.keySet();
               Iterator<Object> iterator = set.iterator();
               while (iterator.hasNext()) {
                       String key = (String) iterator.next();
                       String value = properties.getProperty(key);
                       System.out.println(key+"-->"+value);
               }
       }
       

軟件試用

//控制軟件試用的次數,在配置信息中,添加一條用於記錄用戶使用軟件的次數 count=4,最多試用的次數是5次。
       static void test4() throws Exception{
               //軟件運行的時候,將所有的配置信息加載,看配置信息中是否包含了試用次數的key 和 value。
               Properties prop = new Properties();
               FileInputStream fis = new FileInputStream("./res/prop.ini");
               prop.load(fis);
               
               fis.close();
               
               String value = prop.getProperty("count");
               if(value == null){//沒有,添加一條 count=1
                       prop.setProperty("count", "1");
                       System.out.println("剩餘試用次數 = " + 4);
               }else{//如果已經存在,把value 取出來,+1 再寫回去。
                       //是否達到了試用的次數
                       int count = Integer.parseInt(value);
                       if(count < 5){
                               int newCount = Integer.parseInt(value)+1;
                               System.out.println("剩餘試用次數 = " + (5-newCount));
                               prop.setProperty("count", Integer.toString(newCount));
                       }else{//試用結束
                               System.out.println("軟件試用結束,請付費使用,程序員也需要生活!");
                               System.exit(0);
                       }
               }
               FileOutputStream fos = new FileOutputStream("./res/prop.ini");
               prop.store(fos, "");
               fos.close();
       }

SequenceInputStream-合併,切割

SequenceInputStream:序列流,一個功能流。用於合併數據。

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

public class SequenceInputStreamTest {

       public static void main(String[] args) throws Exception {
               mergeFile1();
               //                cutFile();
       }


       //將多個文本文件合併爲一個文本文件
       static void test1() throws Exception{
               //三個文件字節輸入流,合併爲一個
               SequenceInputStream temp = new SequenceInputStream(new FileInputStream("./res/2.txt"), new FileInputStream("./res/3.txt"));
               SequenceInputStream sis = new SequenceInputStream(temp, new FileInputStream("./res/6.txt"));

               BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("./res/236.txt"));

               int value = sis.read();
               while(value != -1){
                       bos.write(value);
                       value = sis.read();
               }

               bos.close();
               sis.close();
       }

       //切割文件
       static void cutFile() throws Exception{
               FileInputStream fis = new FileInputStream("c:/77.jpg");

               byte[] buf = new byte[10240];

               int count = fis.read(buf);
               int counter = 0;
               while(count != -1){
                       //將1M的數據生成一個單獨的文件
                       FileOutputStream fos = new FileOutputStream("c:/77_"+counter ++ +".jpg");
                       fos.write(buf, 0, count);
                       fos.close();
                       count = fis.read(buf);
               }
               fis.close();
       }

       //合併
       static void mergeFile() throws Exception{
               //將所有的合併的文件,放到一個容器中,
               Vector<InputStream> vector = new Vector<>();
               for(int i=0;i<6;i++){
                       vector.add(new FileInputStream("c:/77_"+i+".jpg"));
               }
               //然後得到容器的枚舉器。
               Enumeration<InputStream> enumeration = vector.elements();
               //然後創建 序列流對象
               SequenceInputStream sis = new SequenceInputStream(enumeration);
               byte[] buf = new byte[100000];
               //創建用於生成合並文件的輸出流
               FileOutputStream fos = new FileOutputStream("c:/77_copy.jpg");

               int count = sis.read(buf);
               while(count != -1){
                       fos.write(buf, 0, count);
                       count = sis.read(buf);
                       Thread.sleep(100);
               }

               sis.close();
               fos.close();
       }

       //合併
       static void mergeFile1() throws Exception{
               //將所有的合併的文件,放到一個容器中,
               ArrayList<InputStream> list = new ArrayList<>();
               for(int i=0;i<6;i++){
                       list.add(new FileInputStream("c:/77_"+i+".jpg"));
               }
               //然後得到容器的枚舉器。
               //                Enumeration<InputStream> enumeration = vector.elements();
               //得到ArrayList 的枚舉器
               //                Enumeration<InputStream> enumeration = Collections.enumeration(list);

               //創建枚舉器對象,用於遍歷 list
               Enumeration<InputStream> enumeration = new Enumeration<InputStream>() {
                       int index = 0;
                       //list 的當前元素是否還有下一個元素
                       public boolean hasMoreElements() {
                               return list.size()>index;
                       }
                       // 返回list 的下一個元素
                       public InputStream nextElement() {
                               InputStream is = list.get(index);
                               index ++;
                               return is;
                       }
               };
               //然後創建 序列流對象
               SequenceInputStream sis = new SequenceInputStream(enumeration);
               byte[] buf = new byte[100000];
               //創建用於生成合並文件的輸出流
               FileOutputStream fos = new FileOutputStream("c:/77_copy111.jpg");

               int count = sis.read(buf);
               while(count != -1){
                       fos.write(buf, 0, count);
                       count = sis.read(buf);
                       Thread.sleep(100);
               }

               sis.close();
               fos.close();
       }


       //合併
       static void mergeFile2() throws Exception{
               //將所有的合併的文件,放到一個容器中,
               ArrayList<InputStream> list = new ArrayList<>();
               for(int i=0;i<6;i++){
                       list.add(new FileInputStream("c:/77_"+i+".jpg"));
               }
               //然後得到容器的枚舉器。
               //                        Enumeration<InputStream> enumeration = vector.elements();
               //得到ArrayList 的枚舉器
               //                        Enumeration<InputStream> enumeration = Collections.enumeration(list);
               //使用list 的迭代器,得到 list 的枚舉器
               Iterator<InputStream> iterator = list.iterator();
               //創建枚舉器對象,用於遍歷 list
               Enumeration<InputStream> enumeration = new Enumeration<InputStream>() {
                       //list 的當前元素是否還有下一個元素
                       public boolean hasMoreElements() {
                               return iterator.hasNext();
                       }
                       // 返回list 的下一個元素
                       public InputStream nextElement() {
                               return iterator.next();
                       }
               };
               //然後創建 序列流對象
               SequenceInputStream sis = new SequenceInputStream(enumeration);
               byte[] buf = new byte[100000];
               //創建用於生成合並文件的輸出流
               FileOutputStream fos = new FileOutputStream("c:/77_copy111.jpg");

               int count = sis.read(buf);
               while(count != -1){
                       fos.write(buf, 0, count);
                       count = sis.read(buf);
                       Thread.sleep(100);
               }

               sis.close();
               fos.close();
       }




}

管道流

和線程通信相關的兩個流。
PipedInputStream
PipedOutputStream

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

/**
* 兩個線程 獨立的 類,進行信息的交互
* 管道輸出流寫出的數據,被管道輸入流讀取到。
* 在一個線程中用管道輸出流寫出數據。
* 在另外一個線程中使用管道輸入流讀取 管道輸出流寫出的數據
* @author yhl
*
*/
public class PipedStreamTest {

       public static void main(String[] args) throws Exception {
               PipedInputStream pis = new PipedInputStream();
               PipedOutputStream pos = new PipedOutputStream();
               //可以通過構造方法將管道輸入輸出流建立關聯,也可以通過方法。
               pis.connect(pos);
               
               PipedOutputStreamThread thread1 = new PipedOutputStreamThread(pos);
               PipedInputStreamThread thread2 = new PipedInputStreamThread(pis);
               
               new Thread(){
                       public void run() {
                               thread2.start();
                       };
               }.start();
               
               Thread.sleep(5000);
               
               new Thread(){
                       public void run() {
                               thread1.start();
                       };
               }.start();
       }

}

//管道輸出流的線程類
class PipedOutputStreamThread extends Thread{
       //持有管道輸出流的引用。
       private PipedOutputStream pos;
       
       public PipedOutputStreamThread(PipedOutputStream pos) {
               this.pos = pos;
       }
       
       public void run() {
               try {
                       //使用管道輸出流寫出數據
                       String str = "多年不見,你還好麼?";
//                        byte[] bs = str.getBytes();
                       BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(pos));
                       bw.write(str);
//                        pos.write(bs);
                       bw.newLine();
                       bw.flush();
                       bw.close();
               } catch (Exception e) {
                       e.printStackTrace();
               }finally {
                       try {
                               pos.close();
                       } catch (IOException e) {
                               e.printStackTrace();
                       }
               }
       }
}

//用於讀取管道輸出流寫出數據的輸入流
class PipedInputStreamThread extends Thread{
       private PipedInputStream pis;
       public PipedInputStreamThread(PipedInputStream pis) {
               this.pis = pis;
       }
       @Override
       public void run() {
               try {
                       BufferedReader br = new BufferedReader(new InputStreamReader(pis));
                       String str = br.readLine();
                       System.out.println("接收到的內容爲:"+str);
                       br.close();
               } catch (Exception e) {
                       e.printStackTrace();
               }finally{
                       try {
                               pis.close();
                       } catch (IOException e) {
                               e.printStackTrace();
                       }
               }
       }
}


RandomAccessFile

java.io.RandomAccessFile:隨機存取文件。

這是一個功能很強大的,隨機 可以 跳着讀寫。

import java.io.RandomAccessFile;

public class RandomAccessFileTest {

       public static void main(String[] args) throws Exception {
                test2();
       }
       
       //往指定的文件中寫入三個學生的信息。
       static void test1() throws Exception{
               RandomAccessFile raf = new RandomAccessFile("./res/students.txt", "rw");
               
               raf.seek(40);//可以來回跳
//                raf.skipBytes(n)//只能往前跳
               raf.writeUTF("小明");
               raf.writeInt(21);
               raf.writeInt(90);
               
               raf.seek(0);
               //每個人的信息佔用的字節數爲 20
               raf.writeUTF("小剛");
               raf.writeInt(20);
               raf.writeInt(100);
               
               //跳到第20個字節開始繼續寫
               raf.seek(20);
               raf.writeUTF("小花");
               raf.writeInt(17);
               raf.writeInt(99);
               
               raf.close();
       }
       
       //讀取學生的信息
       static void test2() throws Exception{
               RandomAccessFile raf = new RandomAccessFile("./res/students.txt", "r");
               raf.seek(20);
               System.out.println(raf.readUTF());
               System.out.println(raf.readInt());
               System.out.println(raf.readInt());
               
               raf.seek(0);
               System.out.println(raf.readUTF());
               System.out.println(raf.readInt());
               System.out.println(raf.readInt());
               
               raf.close();
       }

}

ObjectInputStream-ObjectOutputStream

ObjectInputStream:
ObjectOutputStream:

對象字節輸入輸出流。

需求:將一個內存中的對象寫入到一個本地文件中。實現對對象的持久化存儲。還要將磁盤中的文件中保存的對象數據,還原到內存中對象數據來。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectStreamTest {

       public static void main(String[] args) throws Exception {
               writeObj();
               readObj();
       }
       
       //將一個Student 對象寫入到指定的文件中,持久化存儲
       static void writeObj() throws Exception{
               
               ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("./res/student.obj")));
               //
               Student student = new Student("小剛", 19, Gender.MALE);
               oos.writeInt(10);
               oos.writeObject(student);
               
               oos.close();
       }
       
       //將一個文件中的對象數據,還原到程序的內存中。
       static void readObj() throws Exception{
               ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("./res/student.obj")));
               
               System.out.println(ois.readInt());
               Student student = (Student)ois.readObject();
               System.out.println(student);
               
               ois.close();
       }
}

class Student implements Serializable{
       /**
        * 最好將類型信息版本號顯式的定義
        */
       private static final long serialVersionUID = 1L;
       
       private String name;
       private int age;
       private transient Gender gender;
       private int score;
       
       private Book book = new Book("魯濱遜漂流記");
       
       public Student() {
               System.out.println("Student.Student()");
       }

       Student(String name, int age, Gender gender) {
               super();
               System.out.println("Student.Student()");
               this.name = name;
               this.age = age;
               this.gender = gender;
       }

       @Override
       public String toString() {
               return "Student [name=" + name + ", age=" + age + ", gender=" + gender + ", score=" + score + "]";
       }
}


class Book implements Serializable{
       private String name;
       public Book(String name) {
               this.name = name;
       }
}


enum Gender{
       FEMALE,MALE
}

序列化反序列化

序列化:將內存中的對象,轉換爲字節數組的過程。稱爲對象的序列化。
字節數組包含的內容:對象的類型信息。屬性的類型信息。還包含了用於將字節數據還原爲對象的信息。

反序列化:將字節數組還原爲對象的過程。反序列化。

作用:
1:對象的持久化存儲。
2:可以在網絡中傳輸對象,網絡中傳輸的都是字節信息。必須將對象序列化之後傳輸過去,對方收到字節數據之後再反序列化,得到對象的信息。

1:如果一個對象可以被序列化和反序列化,那麼該對象的類型 必須 實現 接口 java.io.Serializable.
該接口是一個空接口,標記性接口。
類通過實現 java.io.Serializable 接口以啓用其序列化功能。未實現此接口的類將無法使其任何狀態序列化或反序列化。可序列化類的所有子類型本 身都是可序列化的。序列化接口沒有方法或字段,僅用於標識可序列化的語義。

2:反序列化 還原對象的時候,並不會調用對象類中的構造方法。所有對象的生成的過程,全部依賴於序列化的字節數據。

3:如果想反序列化成功,那麼被序列化的時候類中的 serialVersionUID 字段的值,必須和 反序列化的時候,類中的serialVersionUID
值相同。不然會拋出 類型版本號不一致的異常,導致不能反序列化成功。
所以建議,在序列化的類中,顯式的定義 serialVersionUID 值,指定一個隨意的long類型的值即可。
private static final long serialVersionUID = 1L;

4:靜態的類的成員變量是不會被序列化的。因爲不再對象的內部,依賴於類存在的。

5:如果類中的某些實例變量也不想被序列化,那麼將 該實例成員 使用關鍵字 transient 修飾即可。
如果一個實例變量,被 transient 修飾,那麼被反序列化的時候,該字段的值是該類型的 默認值。

6:如果一個對象可以被序列化,那麼該對象的所有的成員都必須是可以被序列化的。基本數據類型可以直接被序列化,那麼引用數據類型必須實現接口Serializable。

7:如果想將字節數據反序列化成功,那麼字節碼中的類型信息(包名+類名)必須和本地的一致。還有的類型的版本號必須一致。

ByteArrayInputStream-ByteArrayOutputStream

字節數組輸入輸出流。

如何將一個對象的序列化之後的字節數組得到??
1:將對象序列化到一個文件中。然後再使用字節流讀取出來就行了。

作用:
1:ByteArrayOutputStream 可以將任意類型的數據 得到對應的字節數組形式。
2:ByteArrayInputStream 可以將 字節數組中包含的我們需要的類型的信息,還原回來。

ByteArrayOutputStream 流中包含的字節數組信息,這個流關閉之後,ByteArrayOutputStream 對象中包含的字節數組仍然可以獲得。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ByteArrayStreamTest {

       public static void main(String[] args) throws Exception {
               test();
       }

       //
       static void test() throws Exception{
               //將寫出的數據,寫出到了 baos 對象中的字節數組中了。
               ByteArrayOutputStream baos = new ByteArrayOutputStream();
               ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(baos));
               oos.writeInt(10);
               oos.writeObject(new Student("小明",21,Gender.MALE));
               oos.flush();
               //關閉之後,baos 對象仍然可以使用。
               oos.close();
               byte[] array = baos.toByteArray();
               System.out.println(array.length);
               
               //以字節數組爲數據源讀取數據
               ByteArrayInputStream bais = new ByteArrayInputStream(array);
               ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(bais));
               System.out.println(ois.readInt());
               System.out.println(ois.readObject());
               
               ois.close();
       }

}

1:對文件讀寫操作
讀取文件的內容:
1:如果是文本文件
new BufferedReader(new FileReader(file));
readLine();
2: 非文本文件
new BufferedInputStream(new FileInputStream(file));
read(byte[])
往文件中寫數據:
1:文本數據:
new BufferedWriter(new FileWriter(file,append));
write(String)
newLine()

           2:字節數據:
                   new BufferedOutputStream(new FileOutputStream(file,append));
                   wirete(byte[])
                   flush();

2 : 使用流接收鍵盤輸入的信息
new BufferedReader(new InputStreamReader(System.in));
readLine();
3: 想對八種基本數據類型進行讀寫 還可以包括 String
DataInputStream、DataOutputStream
4:對對象進行序列化和反序列化
ObjectInputStream、ObjectOutputStream

5:內存和內存之間的數據的交互。
想操作的數據和 字節數組之間的相互的轉換。
ByteArrayInputStream
ByteArrayOutputStream
6:如果想將字符序列使用指定的字符集編碼爲字節數據
OutputStreamWriter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章