1. 程式人生 > 實用技巧 >IO操作

IO操作

原文連結http://zhhll.icu/2020/05/18/java%E5%9F%BA%E7%A1%80/IO/java%E5%9F%BA%E7%A1%80%E4%B9%8BIO%E6%93%8D%E4%BD%9C/

使用者程序發起請求,核心接收到請求後,從I/O裝置中獲取資料到buffer中,再將buffer中的資料copy到使用者程序的地址空間,該使用者程序獲取到資料後再響應客戶端。

資料輸入到buffer需要時間,從buffer複製資料至程序也需要時間,根據在這兩段時間內等待方式不同,I/O動作可分為五種模式

  • 阻塞I/O(Blocking I/O)
  • 非阻塞I/O(Non-Blocking I/O)
  • I/O複用(I/O Multiplexing)
  • 訊號驅動I/O
  • 非同步I/O

java的I/O操作在類的java.io包中

  • 基於位元組操作的I/O介面: InputStream和OutputStream

  • 基於字元操作的I/O介面: Writer和Reader

  • 基於磁碟操作的I/O介面: File

  • 基於網路操作的I/O介面: Socket(網路程式設計,不在io包中)

普通IO

  1. 位元組流對應原生的二進位制資料

  2. 字元流對應字元資料,會自動處理與本地字符集之間的轉換

  3. 緩衝流可以提高效能,通過減少底層API的呼叫次數來優化IO

位元組流

輸入流

位元組輸入流都繼承自InputStream,InputStream表示從不同資料來源產生輸入的類,這些資料員包括

  1. 位元組陣列
  2. String物件
  3. 檔案
  4. 管道,從一端輸入,從另一端輸出
  5. 一個由其他種類的流組成的序列,然後把它們匯聚為一個流
  6. 其他資料來源,如Internet連線
功能 構造器 如何使用
ByteArrayInputStream 允許將記憶體的緩衝區當做InputStream使用 緩衝區,位元組將從中取出 將其與FilterInputStream物件相連以提供有用介面
StringBufferInputStream 將String轉換為InputStream 字串。底層實現實際使用StringBuffer 將其與FilterInputStream物件相連以提供有用介面
FileInputStream 用於從檔案中讀取資訊 字串,表示檔名、檔案或FileDescriptor物件
PipedInputStream 產生用於寫入相關PipedOutputStream的資料。實現管道化概念 PipedOutputStream 作為多執行緒中的資料來源
SequenceInputStream 將兩個或多個InputStream物件轉換成一個InputStream 兩個InputStream物件或一個容納InputStream物件的容器Enumeration
FilterInputStream 抽象類,作為裝飾器的介面,為其他的InputStream類提供有用的功能

FilterInputStream型別子類包括以下幾種

功能 構造器 如何使用
DataInputStream 與DataOutputStream搭配使用,按照移植方式從流讀取基本資料型別 InputStream 包含用於讀取基本資料型別的全部介面
BufferedInputStream 使用它可以防止每次讀取時都得進行實際寫操作 InputStream 本質上不提供介面,只是向程序新增緩衝功能
LineNumberInputStream 跟蹤輸入流的行號,可呼叫getLineNumber()和setLineNumber(int) InputStream,可以指定緩衝區大小 僅增加了行號
PushbackInputStream 具有能彈出一個位元組的緩衝區,因此可以將讀到的最後一個字元回退 InputStream 通常作為編譯器的掃描器

輸出流

位元組輸入流都繼承自OuputStream,該類決定了輸出所要去的目標,位元組陣列、檔案或管道

功能 構造器 如何使用
ByteArrayOutputStream 在記憶體中建立緩衝區。所有送往流的資料都要放置在此緩衝區 緩衝區初始大小 用於指定資料的目的地
FileOutputStream 用於將資訊寫入檔案 字串,表示檔名、檔案或FileDescriptor物件
PipedOutputStream 任何寫入其中的資訊都會自動作為相關PipedInputStream的輸出,實現管道化概念 PipedInputStream 指定用於多執行緒的資料的目的地
FilterOutputStream 抽象類,作為裝飾器的介面,為其他OutputStream提供有用的功能

FilterOutputStream型別子類包括

功能 構造器 如何使用
DataOutputStream 與DataInputStream搭配使用,可以按照移植方式向流中寫入基本資料型別 OutputStream 包含用於寫入基本資料型別的全部介面
PrintStream 用於產生改格式化輸出。其中DataOutputStream處理資料的儲存,PrintStream處理顯示 OutputStream,可以用boolean值指示是否每次換行時清空緩衝區 應該是對OutputStream物件的final封裝
BufferedOutputStream 使用它以避免每次傳送資料時都進行實際的寫操作,可以呼叫flush()清空緩衝區 OutputStream,可以指定緩衝區大小 只是向程序新增緩衝功能

字元流

InputStream和OutputStream是面向位元組I/O的,而Reader和Writer則提供相容Unicode和麵向字元I/O的功能,InputStreamReader可以把InputStream轉換為Reader,而OutputStreamWriter可以把OutputStream轉換為Writer

RandomAccessFile類

適用於由大小已知的記錄組成的檔案,可以使用seek()將檔案指標從一條記錄移動到另一條記錄,然後對記錄進行讀取和修改。檔案中記錄的大小不一定相同,只要我們能確定那些記錄有多大以及它們在檔案中的位置即可。

RandomAccessFile類不是InputStream或者OutputStream的子類,只是實現了DataInput和DataOutput介面,沒有使用InputStream和OutputStream的任何功能,所有方法都是獨立的,大部分為native方法

常用的IO操作

緩衝輸入檔案

想要開啟一個檔案進行字元輸入,可以使用FileReader物件,然後傳入一個String或者File物件作為檔名。為了提高速度,對檔案進行緩衝,可以將所產生的引用傳遞給一個BufferedReader構造器。BufferedReader提供了lines()方法,會產生一個Stream物件

 public static void read(String file) {
        try(BufferedReader bufferedReader = new BufferedReader(new FileReader(file))){
            String line = null;
            while((line = bufferedReader.readLine()) != null){
                System.out.println(line);
            }
        } catch (IOException e) {
            throw new RuntimeException("讀取失敗",e);
        }
    }

讀取字元

public static void read() throws IOException {
        StringReader stringReader = new StringReader("qaw試試");
        int c;
        while ((c = stringReader.read()) != -1) {
            System.out.println((char)c);
        }
    }

StringReader的read方法是以int形式返回的下一個位元組,所以列印的時候型別必須轉為char

格式化資料

要讀取格式化資料,可以使用DataInputStream,是面向位元組的,所以要使用InputStream類

檔案輸出

FileWrite物件用於向檔案寫入資料,通常使用BufferedWriter將其包裝起來增加緩衝的功能,

try(BufferedReader in = new BufferedReader(new StringReader("1111111111111111\n2222222222222\n3333333333"));
            PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter("test.txt")))
        ){
            in.lines().forEach(printWriter :: println);
        } catch (IOException e) {
            e.printStackTrace();
        }

標準IO

標準輸入流Systom.in、標準輸出流System.out、標準錯誤流Sytem.err。

System.out和System.err是預先包裝成了PrintStream物件,但是System.in沒有進行包裝,屬於原生的InputStream,所以在讀取時需要對其進行包裝

標準輸入

通常一行一行地讀取輸入,將System.in包裝成BufferedReader

public static void main(String[] args) {
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) {
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                if (line.equals("end")) {
                    break;
                }
                System.out.println(line);
            }
        } catch (IOException e) {

        }
    }

重定向標準I/O

System類提供了簡單的靜態方法呼叫,重定向標準輸入流、標準輸出流和標準錯誤流

  • setIn(InputStream)

  • setOut(PrintStream)

  • setErr(PrintStream)

public static void main(String[] args) {
        try(BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("C:\\Users\\sinosoft\\Desktop\\剩餘工作.txt"));
            PrintStream printStream = new PrintStream(new BufferedOutputStream(new FileOutputStream("C:\\Users\\sinosoft\\Desktop\\剩餘工作副本.txt")))
        ){
            System.setIn(bufferedInputStream);
            System.setOut(printStream);
            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) {
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    if (line.equals("end")) {
                        break;
                    }
                    System.out.println(line);
                }
            } catch (IOException e1) {

            }
        }catch (IOException e){

        }
    }

由於本身的部落格百度沒有收錄,部落格地址http://zhhll.icu