Java字节流的使用
InputStream 是 Java 所有字節輸入流類的父類,OutputStream 是 Java 所有字節輸出流類的父類,它們都是一個抽象類,因此繼承它們的子類要重新定義父類中的抽象方法。
下面首先介紹上述兩個父類提供的常用方法,然后介紹如何使用它們的子類輸入和輸出字節流,包括 ByteArrayInputStream 類、ByteArrayOutputStream 類、FileInputStream 類和 FileOutputStream 類。
字節輸入流
InputStream 類及其子類的對象表示字節輸入流,InputStream 類的常用子類如下。
ByteArrayInputStream 類:將字節數組轉換為字節輸入流,從中讀取字節。FileInputStream 類:從文件中讀取數據。PipedInputStream 類:連接到一個 PipedOutputStream(管道輸出流)。SequenceInputStream 類:將多個字節輸入流串聯成一個字節輸入流。ObjectInputStream 類:將對象反序列化。使用 InputStream 類的方法可以從流中讀取一個或一批字節。
InputStream類的常用方法
| int read() | 從輸入流中讀取一個 8 位的字節,并把它轉換為 0~255 的整數,最后返回整數。如果返回 -1,則表示已經到了輸入流的末尾。為了提高 I/O 操作的效率,建議盡量使用 read() 方法的另外兩種形式 |
| int read(byte[] b) | 從輸入流中讀取若干字節,并把它們保存到參數 b 指定的字節數組中。 該方法返回讀取的字節數。如果返回 -1,則表示已經到了輸入流的末尾 |
| int read(byte[] b, int off, int len) | 從輸入流中讀取若干字節,并把它們保存到參數 b 指定的字節數組中。其中,off 指定在字節數組中開始保存數據的起始下標;len 指定讀取的字節數。該方法返回實際讀取的字節數。如果返回 -1,則表示已經到了輸入流的末尾 |
| void close() | 關閉輸入流。在讀操作完成后,應該關閉輸入流,系統將會釋放與這個輸入流相關的資源。注意,InputStream 類本身的 close() 方法不執行任何操作,但是它的許多子類重寫了 close() 方法 |
| int available() | 返回可以從輸入流中讀取的字節數 |
| long skip(long n) | 從輸入流中跳過參數 n 指定數目的字節。該方法返回跳過的字節數 |
| void mark(int readLimit) | 在輸入流的當前位置開始設置標記,參數 readLimit 則指定了最多被設置標記的字節數 |
| boolean markSupported() | 判斷當前輸入流是否允許設置標記,是則返回 true,否則返回 false |
| void reset() | 將輸入流的指針返回到設置標記的起始處 |
注意:在使用 mark() 方法和 reset() 方法之前,需要判斷該文件系統是否支持這兩個方法。
字節輸出流
OutputStream 類及其子類的對象表示一個字節輸出流。OutputStream 類的常用子類如下。
ByteArrayOutputStream 類:向內存緩沖區的字節數組中寫數據。FileOutputStream 類:向文件中寫數據。PipedOutputStream 類:連接到一個 PipedlntputStream(管道輸入流)。ObjectOutputStream 類:將對象序列化。利用 OutputStream 類的方法可以從流中寫入一個或一批字節。
OutputStream 類的常用方法
| void write(int b) | 向輸出流寫入一個字節。這里的參數是 int 類型,但是它允許使用表達式,而不用強制轉換成 byte 類型。為了提高 I/O 操作的效率,建議盡量使用write() 方法的另外兩種形式 |
| void write(byte[] b) | 把參數 b 指定的字節數組中的所有字節寫到輸出流中 |
| void write(byte[] b,int off,int len) | 把參數 b 指定的字節數組中的若干字節寫到輸出流中。其中,off 指定字節數組中的起始下標,len 表示元素個數 |
| void close() | 關閉輸出流。寫操作完成后,應該關閉輸出流。系統將會釋放與這個輸出流相關的資源。注意,OutputStream 類本身的 close() 方法不執行任何操作,但是它的許多子類重寫了 close() 方法 |
| void flush() | 為了提高效率,在向輸出流中寫入數據時,數據一般會先保存到內存緩沖區中,只有當緩沖區中的數據達到一定程度時,緩沖區中的數據才會被寫入輸出流中。使用 flush() 方法則可以強制將緩沖區中的數據寫入輸出流,并清空緩沖區 |
字節數組輸入流
ByteArrayInputStream 類可以從內存的字節數組中讀取數據,該類有如下兩種構造方法重載形式。
ByteArrayInputStream(byte[] buf):創建一個字節數組輸入流,字節數組類型的數據源由參數 buf 指定。ByteArrayInputStream(byte[] buf,int offse,int length):創建一個字節數組輸入流,其中,參數 buf 指定字節數組類型的數據源,offset 指定在數組中開始讀取數據的起始下標位置,length 指定讀取的元素個數。使用 ByteArrayInputStream 類實現從一個字節數組中讀取數據,再轉換為 int 型進行輸出。代碼如下:
public class test {public static void main(String[] args) {byte[] b = new byte[] { 1, -1, 25, -22, -5, 23 }; // 創建數組ByteArrayInputStream bais = new ByteArrayInputStream(b, 0, 6); // 創建字節數組輸入流int i = bais.read(); // 從輸入流中讀取下一個字節,并轉換成int型數據while (i != -1) { // 如果不返回-1,則表示沒有到輸入流的末尾System.out.println("原值=" + (byte) i + "\t\t\t轉換為int類型=" + i);i = bais.read(); // 讀取下一個}} }上例中,字節輸入流 bais 從字節數組 b 的第一個元素開始讀取 4 字節元素,并將這 4 字節轉換為 int 類型數據,最后返回。
提示:上述示例中除了打印 i 的值外,還打印出了 (byte)i 的值,由于 i 的值是從 byte 類型的數據轉換過來的,所以使用 (byte)i 可以獲取原來的 byte 數據。
該程序的運行結果如下:
原值=1 轉換為int類型=1 原值=-1 轉換為int類型=255 原值=25 轉換為int類型=25 原值=-22 轉換為int類型=234 原值=-5 轉換為int類型=251 原值=23 轉換為int類型=23從結果可以看出,字節類型的數據 -1 和 -22 轉換成 int 類型的數據后變成了 255 和 234,對這種結果的解釋如下:
字節類型的 1,二進制形式為 00000001,轉換為 int 類型后的二進制形式為 00000000 00000000 0000000000000001,對應的十進制數為 1。字節類型的 -1,二進制形式為 11111111,轉換為 int 類型后的二進制形式為 00000000 00000000 0000000011111111,對應的十進制數為 255。可見,從字節類型的數轉換成 int 類型的數時,如果是正數,則數值不變;如果是負數,則由于轉換后,二進制形式前面直接補了 24 個 0,這樣就改變了原來表示負數的二進制補碼形式,所以數值發生了變化,即變成了正數。
提示:負數的二進制形式以補碼形式存在,例如 -1,其二進制形式是這樣得來的:首先獲取 1 的原碼 00000001,然后進行反碼操作,1 變成 0,0 變成 1,這樣就得到 11111110,最后進行補碼操作,就是在反碼的末尾位加 1,這樣就變成了 11111111。
字節數組輸出流
ByteArrayOutputStream 類可以向內存的字節數組中寫入數據,該類的構造方法有如下兩種重載形式。
ByteArrayOutputStream():創建一個字節數組輸出流,輸出流緩沖區的初始容量大小為 32 字節。ByteArrayOutputStream(int size):創建一個字節數組輸出流,輸出流緩沖區的初始容量大小由參數 size 指定。ByteArrayOutputStream 類中除了有前面介紹的字節輸出流中的常用方法以外,還有如下兩個方法。
intsize():返回緩沖區中的當前字節數。byte[] toByteArray():以字節數組的形式返回輸出流中的當前內容。使用 ByteArrayOutputStream 類實現將字節數組中的數據輸出,代碼如下所示。
public class Test {public static void main(String[] args) {ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] b = new byte[] { 1, -1, 25, -22, -5, 23 }; // 創建數組baos.write(b, 0, 6); // 將字節數組b中的前4個字節元素寫到輸出流中System.out.println("數組中一共包含:" + baos.size() + "字節"); // 輸出緩沖區中的字節數byte[] newByteArray = baos.toByteArray(); // 將輸出流中的當前內容轉換成字節數組System.out.println(Arrays.toString(newByteArray)); // 輸出數組中的內容} }該程序的輸出結果如下:
數組中一共包含:6字節 [1, -1, 25, -22, -5, 23]文件輸入流
FileInputStream 是 Java 流中比較常用的一種,它表示從文件系統的某個文件中獲取輸入字節。通過使用 FileInputStream 可以訪問文件中的一個字節、一批字節或整個文件。
在創建 FileInputStream 類的對象時,如果找不到指定的文件將拋出 FileNotFoundException 異常,該異常必須捕獲或聲明拋出。
FileInputStream 常用的構造方法主要有如下兩種重載形式。
FileInputStream(File file):通過打開一個到實際文件的連接來創建一個 FileInputStream,該文件通過文件系統中的 File 對象 file 指定。FileInputStream(String name):通過打開一個到實際文件的鏈接來創建一個 FileInputStream,該文件通過文件系統中的路徑名 name 指定。示例 FileInputStream() 兩個構造方法的使用。
try {// 以File對象作為參數創建FileInputStream對象FileInputStream fis1 = new FileInputStream(new File("F:/mxl.txt"));// 以字符串值作為參數創建FilelnputStream對象FileInputStream fis2 = new FileInputStream("F:/mxl.txt"); } catch(FileNotFoundException e) {System.out.println("指定的文件找不到!"); }假設有一個 D:\myJava\HelloJava.java 文件,下面使用 FileInputStream 類讀取并輸出該文件的內容。代碼如下:
public class Test {public static void main(String[] args) {File f = new File("D:/myJava/HelloJava.java");FileInputStream fis = null;try {// 因為File沒有讀寫的能力,所以需要有個InputStreamfis = new FileInputStream(f);// 定義一個字節數組byte[] bytes = new byte[1024];int n = 0; // 得到實際讀取到的字節數System.out.println("D:\\myJava\\HelloJava.java文件內容如下:");// 循環讀取while ((n = fis.read(bytes)) != -1) {String s = new String(bytes, 0, n); // 將數組中從下標0到n的內容給sSystem.out.println(s);}} catch (Exception e) {e.printStackTrace();} finally {try {fis.close();} catch (IOException e) {e.printStackTrace();}}} }如上述代碼,在 FileInputDemo 類的 main() 方法中首先創建了一個 File 對象 f,該對象指向 D:\myJava\HelloJava.java 文件。接著使用 FileInputStream 類的構造方法創建了一個 FileInputStream 對象 fis,并聲明一個長度為 1024 的 byte 類型的數組,然后使用 FileInputStream 類中的 read() 方法將 HelloJava.java 文件中的數據讀取到字節數組 bytes 中,并輸出該數據。最后在 finally 語句中關閉 FileInputStream 輸入流。
D:\myJava\HelloJava.java文件內容如下:
/* *第一個java程序 */ public class HelloJava {// 這里是程序入口public static void main(String[] args) {// 輸出字符串System.out.println("你好 Java");} }注意:FileInputStream 類重寫了父類 InputStream 中的 read() 方法、skip() 方法、available() 方法和 close() 方法,不支持 mark() 方法和 reset() 方法。
文件輸出流
FileOutputStream 類繼承自 OutputStream 類,重寫和實現了父類中的所有方法。FileOutputStream 類的對象表示一個文件字節輸出流,可以向流中寫入一個字節或一批字節。在創建 FileOutputStream 類的對象時,如果指定的文件不存在,則創建一個新文件;如果文件已存在,則清除原文件的內容重新寫入。
FileOutputStream 類的構造方法主要有如下 4 種重載形式。
FileOutputStream(File file):創建一個文件輸出流,參數 file 指定目標文件。FileOutputStream(File file,boolean append):創建一個文件輸出流,參數 file 指定目標文件,append 指定是否將數據添加到目標文件的內容末尾,如果為 true,則在末尾添加;如果為 false,則覆蓋原有內容;其默認值為 false。FileOutputStream(String name):創建一個文件輸出流,參數 name 指定目標文件的文件路徑信息。FileOutputStream(String name,boolean append):創建一個文件輸出流,參數 name 和 append 的含義同上。注意:使用構造方法 FileOutputStream(String name,boolean append) 創建一個文件輸出流對象,它將數據附加在現有文件的末尾。該字符串 name 指明了原文件,如果只是為了附加數據而不是重寫任何已有的數據,布爾類型參數 append 的值應為 true。
對文件輸出流有如下四點說明:
1 . 在 FileOutputStream 類的構造方法中指定目標文件時,目標文件可以不存在。
2 . 目標文件的名稱可以是任意的,例如 D:\abc、D:\abc.de 和 D:\abc.de.fg 等都可以,可以使用記事本等工具打開并瀏覽這些文件中的內容。
3 . 目標文件所在目錄必須存在,否則會拋出 java.io.FileNotFoundException 異常。
4 . 目標文件的名稱不能是已存在的目錄。例如 D 盤下已存在 Java 文件夾,那么就不能使用 Java 作為文件名,即不能使用 D:\Java,否則拋出 java.io.FileNotFoundException 異常。
讀取 D:\myJava\HelloJava.java 文件的內容,在這里使用 FileInputStream 類實現,然后再將內容寫入新的文件 D:\myJava\HelloJava.txt 中。具體的代碼如下:
public class Test {public static void main(String[] args) {FileInputStream fis = null; // 聲明FileInputStream對象fisFileOutputStream fos = null; // 聲明FileOutputStream對象fostry {File srcFile = new File("D:/myJava/HelloJava.java");fis = new FileInputStream(srcFile); // 實例化FileInputStream對象File targetFile = new File("D:/myJava/HelloJava.txt"); // 創建目標文件對象,該文件不存在fos = new FileOutputStream(targetFile); // 實例化FileOutputStream對象byte[] bytes = new byte[1024]; // 每次讀取1024字節int i = fis.read(bytes);while (i != -1) {fos.write(bytes, 0, i); // 向D:\HelloJava.txt文件中寫入內容i = fis.read(bytes);}System.out.println("寫入結束!");} catch (Exception e) {e.printStackTrace();} finally {try {fis.close(); // 關閉FileInputStream對象fos.close(); // 關閉FileOutputStream對象} catch (IOException e) {e.printStackTrace();}}} }如上述代碼,將 D:\myJava\HelloJava.java 文件中的內容通過文件輸入/輸出流寫入到了 D:\myJava\HelloJava.txt 文件中。由于 HelloJava.txt 文件并不存在,所以在執行程序時將新建此文件,并寫入相應內容。
運行程序,成功后會在控制臺輸出“寫入結束!”。此時,打開 D:\myJava\HelloJava.txt 文件會發現,其內容與 HelloJava.java 文件的內容相同。
提示:在創建 FileOutputStream 對象時,如果將 append 參數設置為 true,則可以在目標文件的內容末尾添加數據,此時目標文件仍然可以暫不存在。
總結
以上是生活随笔為你收集整理的Java字节流的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ 求一元二次方程的根
- 下一篇: Pycharm 项目运行的多种技巧