成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java I/O簡介

darkbug / 2279人閱讀

摘要:如果不指定字符集,則使用系統(tǒng)默認字符編碼,系統(tǒng)的默認字符編碼一般是。所以更準確的說,是將一個字節(jié)輸入流按照給定的字符編碼來解碼,從而得到一個字符輸入流。當然,缺點就是不能選擇使用的字符編碼。

相對于PythonC來說,Java的I/O操作API比較復雜,因此本文打算做個簡單的介紹。

1. I/O分類

總的來說Java的I/O按照處理數(shù)據(jù)的粒度和方向來劃分,一共可以分為4類:

基于字節(jié)

輸入 InputStream

輸出 OutputStream

基于字符

輸入 Reader

輸出 Writer

使用原則:要讀寫二進制數(shù)據(jù)時,使用基于字節(jié)的API;要讀寫文本數(shù)據(jù)時,使用基于字符的API,文本數(shù)據(jù)操作需要指定字符編碼。強調(diào)一點,本文說的字符是指Java的數(shù)據(jù)類型char類型,并不是C語言中的char類型(該類型長度為8位,一個字節(jié)),即Java中的一個字符有可能包含多個字節(jié)。

這里提到的InputStream, OutputStream, ReaderWriter 是Java API里的4個抽象類,不能用來初始化新的實例,我們只能從這4個類的子類(或者后代類)來創(chuàng)建I/O操作的實例,而且正是這些子類實現(xiàn)類不同介質(zhì)和不同功能的I/O。另外,兩個用于輸入的抽象類都定義了一個抽象的int read()方法,兩個用于輸出的抽象類都定義了一個抽象的void write()方法,這些抽象方法則由子類來實現(xiàn)。

2. 文件I/O的使用

Java I/O可以可以應用于各種輸入輸出介質(zhì),包括文件、控制臺(也是文件的一種)、內(nèi)存、網(wǎng)絡(luò)等。這里先介紹文件I/O,搞懂了文件I/O相關(guān)的API后,其他的I/O就都好理解了。

最基本方法

根據(jù)第一節(jié)的分類,文件I/O的API也分為基于字節(jié)基于字符 的兩大類。我們先來看最基礎(chǔ)的文件I/O的類:

基于字節(jié)

FileInputStream
該類的read()方法每次從文件讀取一個字節(jié)。

FileOutputStream
該類的write()方法每次向文件寫入一個字節(jié)。

基于字符

InputStreamReader
該類的read()方法每次從一個輸入流中讀取一個字符。該類的構(gòu)造函數(shù)的第一個參數(shù)是一個InputStream實例,也就是將說該類將一個基于字節(jié)的輸入流變成一個基于字符的輸入流。如果不指定字符集,則使用系統(tǒng)默認字符編碼,Ubuntu系統(tǒng)的默認字符編碼一般是UTF-8。所以更準確的說,是將一個字節(jié)輸入流按照給定的字符編碼來解碼,從而得到一個字符輸入流。

OutputStreamWriter
該類的write()方法每次向一個輸出流中寫入一個字符。該類的構(gòu)造函數(shù)的第一個參數(shù)是一個OutputStream實例,也就是說該類將一個基于字節(jié)的輸出流變成一個基于字符的輸出流。如果不指定字符集,則使用系統(tǒng)默認字符編碼,Ubuntu系統(tǒng)的默認字符編碼一般是UTF-8。所以更準確的說,是將一個字節(jié)輸出流按照給定的字符編碼來編碼(把要輸出的字符轉(zhuǎn)換成二進制數(shù)據(jù)),從而得到一個字符輸出流。

FileReader
該類的read()方法每次從文件讀取一個字符。這個類的作用等于如下代碼:

InputStreamReader in = new InputStreamReader(new FileInputStream(pathToFile));
也就是先從一個文件創(chuàng)建一個字節(jié)輸入流,然后再采用系統(tǒng)默認編碼方式轉(zhuǎn)換成一個字符輸入流。當然,缺點就是不能選擇使用的字符編碼。

FileWriter
該類的write()方法每次向文件寫入一個字符。這個類的作用等于如下代碼:

`OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(pathToFile));
具體解釋和FileReader類似。

介紹完常用類,我們來講下如何使用。

二進制數(shù)據(jù)讀寫(基于字節(jié))

如果要從文件讀入二進制數(shù)據(jù),則先構(gòu)造一個FileInputStream實例,然后調(diào)用read()方法每次讀入一個字節(jié),也可以調(diào)用read方法的其他實現(xiàn),每次讀入多個字節(jié)。

如果要向文件寫入二進制數(shù)據(jù),則先構(gòu)造一個FileOutputStream示例,然后調(diào)用write()方法每次寫入一個字節(jié),也可以調(diào)用write方法的其他實現(xiàn),每次寫入多個字節(jié)。

文本數(shù)據(jù)讀寫(基于字符)

如果要從文件讀入文本數(shù)據(jù),可以選擇如下兩種方式:

構(gòu)造一個FileReader實例,使用系統(tǒng)默認編碼,然后調(diào)用read()方法每次讀入一個字符,也可以調(diào)用read方法的其他實現(xiàn),每次讀入多個字符。

采用如下方式構(gòu)造一個InputStreamReader實例:new InputStreamReader(new FileInputStream(pathToFile), codecName),使用指定的字符編碼,然后調(diào)用read()方法每次讀入一個字符,也可以調(diào)用read方法的其他實現(xiàn),每次讀入多個字符。

如果要向文件寫入文本數(shù)據(jù),可以選擇如下兩種方式:

構(gòu)造一個FileWriter實例,使用系統(tǒng)默認編碼,然后調(diào)用write()方法每次寫入一個字符,也可以調(diào)用write方法的其他實現(xiàn),每次寫入多個字符。

采用如下方式構(gòu)造一個OutputStreamwriter實例:new OutputStreamWriter(new FileOutputStream(pathToFile), codecName),使用指定的字符編碼,然后調(diào)用write()方法每次寫入一個字符,也可以調(diào)用write方法的其他實現(xiàn),每次寫入多個字符。

來看下代碼實例,文件~/tmp/words中存放了一行中文字符,采用的是UTF-8編碼方式:

~/tmp/words 
你好

下面的代碼展示了基于字節(jié)和基于字符兩種方式讀取文件內(nèi)容的區(qū)別:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Hello {

  public static void main(String[] args) {
    String wordFileName = "~/tmp/words";
    String wordFilePath = wordFileName.replace("~", System.getProperty("user.home"));

    try {
      // byte-based input
      System.out.println("InputStream");
      FileInputStream fin = new FileInputStream(wordFilePath);
      int c;
      while ((c = fin.read()) != -1) {
        System.out.printf("%02x ", c);
      }
      System.out.println();

      // char-based input
      System.out.println("Reader");
      InputStreamReader rin = new InputStreamReader(
          new FileInputStream(wordFilePath), "UTF-8");
      while ((c = rin.read()) != -1) {
        System.out.printf("%02x ", c);
      }
      System.out.println();
    } catch (IOException e) {
      System.out.println(e);
      System.exit(1);
    }
  }
}

運行結(jié)果為:

InputStream
e4 bd a0 e5 a5 bd 0a 
Reader
4f60 597d 0a 

可以看出,基于字節(jié)的輸入每次讀入一個字節(jié),兩個漢字一共6個字節(jié),換行符一個字節(jié)(0x0a),一共讀了7次。而基于字符的輸入每次讀入后保存的結(jié)果為兩個字節(jié)(因為Java內(nèi)部都是UTF-16表示的,因此從文件讀入字符的時候已經(jīng)做了UTF-8到UTF-16轉(zhuǎn)換),兩個漢字和一個換行符一共讀了三次。

更方便的方法

上一小節(jié)說的方法其實相當于C語言中的中的如下函數(shù):

FileInputStream: read, fgetc, fread等

FileOutputStream: write, fputc, fwrite等

InputStreamReader, FileReader: 如果文件不是ASCII編碼的,則相當于fgetwc(wchar.h文件中定義)等;如果文件是ASCII編碼,則相當于fgetc等。

OutputStreamWriter, FileWriter: 同上,相當于fputwc和fputc等。

這些只能基于單個字符或者單個字節(jié)進行輸入輸出的API使用起來比較麻煩,比較使用用來操作二進制數(shù)據(jù)。本節(jié)會介紹一些更方便的文件I/O方法。

讀寫二進制文件

在不考慮對象序列化等更復雜的方法時,Java也提供了DataInputStreamDataOutputStream 的類,用來從二進制流中讀取Java的基本類型數(shù)據(jù)或者向二進制流中寫入基本類型數(shù)據(jù),比如讀一個整型和寫入一個整型。

DataInputStream是FilterInputStream的子類,DataOutputStream則是FilterOutputStream的子類,都屬于過濾類的流,其作用是從一個流讀入數(shù)據(jù),然后轉(zhuǎn)換一下表達方式在輸出,比如DataInputStream可以從FileInputStream連續(xù)讀出4個字節(jié),然后轉(zhuǎn)換成一個整型返回給調(diào)用者。

讀寫二進制文件更高級的就是各種對象序列化方法了,這個本文不討論。

讀寫文本文件

讀寫文本文件我們很習慣于按照行來進行讀寫,比如C語言的scanfprintf 函數(shù)。在Java中分別使用下面兩個類來進行:

Scanner: 有眾多構(gòu)造函數(shù),其中一個可以從指定輸入流,然后實現(xiàn)類似scanf函數(shù)的效果。

PrintWritter: 該類在一個Writer的基礎(chǔ)上實現(xiàn)了常用的print, println和printf接口。

如下代碼從一個文件構(gòu)造一個Scanner實例,然后你就可以調(diào)用Scanner類的next, nextInt, nextLine的函數(shù)來從文件讀取輸入:

Scanner in = new Scanner(new FileInputStream(pathToFile));

Scanner類還有其他構(gòu)造函數(shù),能夠指定字符編碼,以及從其他類型的參數(shù)構(gòu)造出一個實例。

如下代碼從一個文件構(gòu)造出一個PrintWriter實例,然后你就可以調(diào)用print, println和printf了:

PrintWriter out = new PrintWriter(new FileWriter(pathToFile));

不過還有個更方便的構(gòu)造函數(shù):

PrintWriter out = new PrintWriter(pathToFile);
3. 標準輸入,標準輸出和標準錯誤

System類的三個成員in, out, err分別系統(tǒng)的標準輸入、標準輸出和標準錯誤,通過查看源碼可以發(fā)現(xiàn)他們的定義是這樣的:

public final class System {
  ...
  public static final InputStream in = null;
  public static final PrintStream out = null;
  public static final PrintStream err = null;
  ...
}

因此要從標準輸出讀取數(shù)據(jù)的化,可以直接使用InputStream的read方法,或者構(gòu)造一個Scanner實例來使用:

System.in.read();
Scanner in = new Scanner(System.in);

標準輸出和標準錯誤則是兩個PrintStream類的實例,查看代碼可以發(fā)現(xiàn),這個類的實現(xiàn)基本上和PrintWriter一樣,也就是說可以直接使用print, println和printf等方法進行數(shù)據(jù)輸出。還有,PrintStream類是繼承自FilterOutputStream,因此write方法也是可用的。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/64168.html

相關(guān)文章

  • JAVA NIO.1

    摘要:特點面向塊的傳統(tǒng)是面向流的。有四個基本屬性容量,能夠容納的最大元素數(shù)目,在創(chuàng)建時設(shè)定并不能更改中有效位置數(shù)目,不能對超過中的區(qū)域進行讀寫。與緩沖區(qū)不同,通道主要由接口指定。方法獲取支持的所有字符集獲取實例編解碼文件鎖進程級支持文件鎖定功能。 簡介 NIO的所有類都被放在java.nio包或其子包下。 特點 面向塊的I/O:傳統(tǒng)JavaIO是面向流的I/O。流I/O一次處理一個字節(jié)。N...

    Steve_Wang_ 評論0 收藏0
  • 高并發(fā) - 收藏集 - 掘金

    摘要:在中一般來說通過來創(chuàng)建所需要的線程池,如高并發(fā)原理初探后端掘金閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細原理解析 - 后端 - 掘金今天我們來研究學習一下AbstractQueuedSynchronizer類的相關(guān)原理,java.util.concurrent包中很多類都依賴于這個類所提供的隊列式...

    levius 評論0 收藏0
  • 高并發(fā) - 收藏集 - 掘金

    摘要:在中一般來說通過來創(chuàng)建所需要的線程池,如高并發(fā)原理初探后端掘金閱前熱身為了更加形象的說明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細原理解析 - 后端 - 掘金今天我們來研究學習一下AbstractQueuedSynchronizer類的相關(guān)原理,java.util.concurrent包中很多類都依賴于這個類所提供的隊列式...

    fantix 評論0 收藏0
  • 通用文件服務(wù)組件(Netty實現(xiàn)版本)

    摘要:操作指引該文件服務(wù)組件的使用需要分為兩個部分,一個是服務(wù)端配置與啟動,一個是客戶端的配置與啟動。在調(diào)用文件服務(wù)返回的路徑的時候,需要用到服務(wù)端訪問文件的地址,進而訪問相應的文件內(nèi)容。 本文所述文件服務(wù)組件在筆者此前一篇文章中已有闡述(基于netty的文件上傳下載組件),不過本文將基于之前這個實現(xiàn)再次進行升級改造,利用基于注解的方式進行自動裝配。 1. 簡介 1.1 Netty簡介 Ne...

    fou7 評論0 收藏0
  • java中的NIO

    摘要:緩沖區(qū)一個對象是固定數(shù)量的數(shù)據(jù)的容器。緩沖區(qū)的工作與通道緊密聯(lián)系。對于操作而言,從通道讀取的數(shù)據(jù)會按順序被散布稱為到多個緩沖區(qū),將每個緩沖區(qū)填滿直至通道中的數(shù)據(jù)或者緩沖區(qū)的最大空間被消耗完。文件通道總是阻塞式的,因此不能被置于非阻塞模式。 簡介 從JDK1.4開始,java中提供一個種叫NIO(Non-Blocking IO)的IO處理機制。與以往的標準IO機制(BIO,Blockin...

    crossoverJie 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<