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