13Java進階——IO、執行緒

小島的每一段verse發表於2021-07-29

1 位元組緩衝流

BufferInputStream 將建立一個內部的緩衝區陣列,內部緩衝區陣列將根據需要從包含的輸入流中重新填充,一次可以讀取多個位元組

BufferOutputStream 該類實現緩衝輸出流。 通過設定這樣的輸出流,應用程式可以向底層輸出流寫入位元組,而不必為寫入的每個位元組導致底層系統的呼叫

構造方法:傳入位元組流,可以指定緩衝區大小

bos.write("hello\r\n".getBytes(StandardCharsets.UTF_8));

BufferedOutputStream 內部帶有緩衝區 寫資料的時候 先寫出到緩衝區,緩衝區寫滿的時候 ,才會將緩衝區的內容寫出到磁碟 呼叫flush方法 只重新整理緩衝流 但不釋放資源 close方法 在關閉流 釋放資源之前 會先重新整理緩衝流

為什麼緩衝流的構造方法中需要的是一個位元組流,而不是具體的檔案或者路徑呢?

位元組緩衝流僅僅提供緩衝區,而真正的讀寫資料還的移開基本的位元組流物件進行操作。

2 字元流

2.1 為什麼出現字元流

由於位元組流操作中文不是特別方便,所以就出現了字元流

字元流 = 位元組流 +字符集

中文位元組儲存方式

用位元組流複製文字檔案時,文字檔案也會有中文,但是沒有問題,原因就是最終底層操作會自動的進行位元組拼接成中文。

如何識別中文?

漢字在儲存的時候 無論使用那種編碼儲存 第一個位元組都是負數。

2.2. 字串中的編碼和解碼的問題

編碼就指的是將字元轉換成位元組

string.getBytes(),引數可指定String 字符集名

預設的編碼 UTF-8

// 解碼 編碼和解碼必須使用相同的碼錶 否則會出現中文亂碼

解碼: 將位元組陣列轉換為字元

String(byte[] bytes, String charsetName)構造一個新的String由指定用指定的位元組的陣列解碼charset

2.3. 字元流中的編碼問題

字元流的抽象基類:

Reader 字元輸入流的抽象基類 編碼

Writer 字元輸出流的抽象基類 解碼

字元流中和編碼相關的類:

  • InputStreamReader是從位元組流到字元流的橋:它讀取位元組,並使用指定的charset將其解碼為字元 。 它使用的字符集可以由名稱指定,也可以被明確指定,或者可以接受平臺的預設字符集。

  • OutputStreamWriter是字元的橋樑流以位元組流:向其寫入的字元編碼成使用指定的位元組charset 。 它使用的字符集可以由名稱指定,也可以被明確指定,或者可以接受平臺的預設字符集。

構造方法:位元組流+可選字符集名

  • 使用字元流完成對於中文的寫和讀

    2.4 字元流讀寫的方式

    寫:write(字元陣列/字串/字元,起始位置)

    重新整理和關閉close(),flush()

    讀:read(字元/字元陣列,起始位置)

字元流自帶緩衝區

2.5 字元流操作的便捷類

FileReader 是InputStreamReader的簡潔形式

FileWriter 是OutputStreamReader的簡潔形式

2.6 字元緩衝流

BufferedReader

  • 從字元輸入流讀取文字,緩衝字元,以提供字元,陣列和行的高效讀取。可以指定緩衝區大小,或者可以使用預設大小。

    BufferedReader(Reader in) 建立使用預設大小的輸入緩衝區的緩衝字元輸入流。

    readline()讀一行

BufferedWriter

  • 將文字寫入字元輸出流,緩衝字元,以提供單個字元,陣列和字串的高效寫入。

    可以指定緩衝區大小,或者可以接受預設大小。

    BufferedWriter(Writer out) 建立使用預設大小的輸出緩衝區的緩衝字元輸出流。

    newLine()寫分隔符

2.7 IO流小結

image-20210729105134952

位元組流可以賦值檔案資料,有四種方式一般採用位元組緩衝流一次去屑一個位元組陣列的形式。

3 標準輸入輸出流

PrintStream:err、out

InputStream:in

3.1.標準輸入流(位元組流)

    public static void main(String[] args) throws IOException {
        //位元組流
        InputStream is = System.in;// 位元組輸入流的資料來源來自標準輸入裝置鍵盤
        BufferedReader br = new BufferedReader(new InputStreamReader(isr));
        System.out.println("請輸入一個整數:");
        int i= Integer.parseInt(br.readLine());
        System.out.println("您輸入的整數為:"+(i + 1));
        //以上程式碼就是自己實現了鍵盤錄入字串和整數的方法   這樣寫起來有點麻煩,因此Java提供了
        Scanner sc = new Scanner(System.in);
    }

3.2. 標準輸出流

PrintStream ps = System.out;

4 列印流

列印流分為:

  • 位元組 列印流 PrintStream

  • 字元列印流 PrintWtriter

列印流的特點:

只負責資料的輸出 不能讀取資料

有一些特有的方法 println() print()

5 物件的序列化流

物件序列化: 就是將物件儲存到磁碟或者在網路中傳輸物件 為了物件儲存的正確性 和傳輸的安全性,需要對物件進行編碼處理,那麼把這種處理方式稱為物件的序列化

反序列化:將序列化的物件解析為原物件的過程 就稱為反序列化

  • ObjectOutputStream oos.writeObject(obj);

  • ObjectInputStream ois.readObject();再強制轉型

對於物件傳輸 物件必須實現java.io.Serializable介面

6 Porperties

Porperties是Map集合的一個實現類

Properties prop = new Properties(); prop.put(k,v); prop.entrySet();

Porperties可以儲存到流中或者從流中載入。 屬性列表中的鍵及其對應的值都是字串

prop.getProperty(k) prop.setProperty(k,v)

prop.load(輸入位元組流/reader) prop().store(輸出位元組流/writer,註解預設為null)

7 多執行緒

7.1 程式 執行緒 程式

程式: 是為了完成特定任務 用某種語言編寫的一組指令的集合。指的一段靜態。

程式:是程式的一次執行過程,或是正在執行的一個程式,是一個動態的過程:有他自身的產生 存在 以及消亡的過程--生命週期

程式是靜態的 程式是動態的程式作為資源分配單位,系統在執行時會為每個程式分配不同的記憶體區域。

執行緒(thread) 程式進一步細化就是執行緒,是一個程式內部的一條執行路徑。

若一個程式同一時間並行執行多個執行緒,就是支援多執行緒。

執行緒作為排程和執行的單位,每個執行緒擁有獨立的執行棧和程式計數器,執行緒的切換開銷比較小。

一個程式中的多個執行緒共享相同的記憶體單元和記憶體地址空間,他們從一個堆中分配物件,可以訪問相同的變數和物件。這就是的執行緒間的通訊變得簡便和高效。但多個執行緒操作共享的系統資源可能會帶來安全隱患。

單核CPU和多核CPU

在java中 一個程式至少有三個執行緒組成, 主執行緒(main) 垃圾回收執行緒(gc) 異常處理執行緒。

並行和併發:

  • 並行:多個CPU同時執行多個任務

  • 併發: 一個CPU在同一時刻,同時處理多個任務。

使用多執行緒的優點:

1 提高了應用程式的響應。

2 提高了計算機CPU的利用率

3 改善程式結構。

何時需要多執行緒?

  • 程式需要同時執行兩個或多個任務

  • 程式需要實現一些需要等待的任務的時候:如:使用者輸入,檔案讀寫 網路操作等。

  • 需要一些後臺執行的程式時

7.2 實現多執行緒

建立一個新的執行執行緒有兩種方法。

  • 一個是將一個類宣告為Thread的子類。 這個子類應該重寫Thread的run方法 。 然後可以分配並啟動子類的例項

  • 另一種方法來建立一個執行緒是宣告實現類Runnable介面。 那個類然後實現了run方法。 然後可以分配類的例項,在建立Thread時作為引數傳遞,並啟動

7.2.1 實現執行緒的方式一: 繼承Thread類

為什麼要重寫run方法?

因為run方法是用來封裝被執行緒執行的程式碼的。

run方和start方法的區別?

run()封裝了執行緒執行的程式碼,直接呼叫的,相當於普通方法呼叫。

start方法 啟動執行緒,然後由jvm呼叫此執行緒的run方法

7.2.2 實現執行緒的方式二: 實現Runnable介面

  • public interface Runnable

    Runnable介面應由任何類實現,其例項將由執行緒執行。 該類必須定義一個無引數的方法,稱為run

    Runnable r = new MyRannable(); Thread t1 = new Thread(r);

    t1.start();

或 new Thread(new Runnable(){@Override public void run(){sout;} }).start();

7.3 設定和獲取執行緒的名稱

Thread(name):有參構造,引數是執行緒的名字

th.setName(name);

Thread.currentThread();返回當前正在執行的執行緒物件的引用。

th.getName();

7.4 執行緒的優先順序

th.getPriority();

th.setPriority(pri);

  • 每個執行緒都有優先權。 具有較高優先順序的執行緒優先於優先順序較低的執行緒執行

執行緒的兩種排程模型

分時排程: 所有執行緒輪流實現CPU的使用權,平均分配每個執行緒佔有CPU的時間片

搶佔式排程: 優先讓優先順序高的執行緒使用CPU,如果執行緒的優先順序相同,那麼會隨機選擇一個。優先順序高的執行緒獲得CPU執行權的概率更高。

java是的是搶佔式的排程模型。

執行緒的預設優先順序為5,執行緒的優先順序的範圍為1(小)--10(大)

 

相關文章