java.io 字節(jié)流
基類 InputStream 和 OutputStream
字節(jié)流主要操作 byte 類型數(shù)據(jù),以 byte 數(shù)組為準(zhǔn),java 中每一種字節(jié)流的基本功能依賴于基本類 InputStream 和 Outputstream,他們是抽象類,不能直接使用。字節(jié)流能處理所有類型的數(shù)據(jù)(如圖片、avi 等)。
InputStream
InputStream 是所有表示字節(jié)輸入流的基類,繼承它的子類要重新定義其中所有定義的抽象方法.InputStream是從裝置來(lái)源地讀取數(shù)據(jù)的抽象表示,例如System中的標(biāo)準(zhǔn)輸入流in對(duì)象就是一個(gè)InputStream類型的實(shí)例。
我們先來(lái)看看InputStream類的方法:
| 方法 | 說(shuō)明 |
|---|---|
| read()throws IOException | 從輸入流中讀取數(shù)據(jù)的下一個(gè)字節(jié)(抽象方法) |
| skip(long n) throws IOException | 跳過(guò)和丟棄此輸入流中數(shù)據(jù)的n個(gè)字節(jié) |
| available() throws IOException | 返回流中可用字節(jié)數(shù) |
| mark(int readlimit) throws IOException | 在此輸入流中標(biāo)記當(dāng)前的位置 |
| reset() throws IOException | 將此流重新定位到最后一次對(duì)此輸入流調(diào)用mark方法時(shí)的位置 |
| markSupport() throws IOException | 測(cè)試此輸入流是否支持mark 和 reset 方法 |
| close() throws IOException | 關(guān)閉流 |
在InputStream類中,方法read()提供了三種從流中讀數(shù)據(jù)的方法;
- int read(): 從輸入流中讀一個(gè)字節(jié),形成一個(gè)0~255之間的整數(shù)返回(是一個(gè)抽象方法)
- int read(byte b[]): 從輸入流中讀取一定數(shù)量的字節(jié),并將其存儲(chǔ)在緩沖區(qū)數(shù)組b中。
- int read(byte b[], int off,int len): 從輸入流中讀取長(zhǎng)度為len的數(shù)據(jù),寫入數(shù)組b中從索引off開始的位置,并返回讀取的字節(jié)數(shù)。
對(duì)于這三個(gè)方法,若返回-1,表明流結(jié)束,否則,返回實(shí)際讀取的字符數(shù)。
OutputStream
OutputStream 是所有表示字節(jié)輸出流類的基類。子類要重新定義其中所定義的抽象方法,OutputStream 是用于將數(shù)據(jù)寫入目的地的抽象表示。例如 System 中的標(biāo)準(zhǔn)輸出流對(duì)象 out 其類型是 java.io.PrintStream,這個(gè)類是 OutputStream 的子類。
OutputStream 類方法:
| 方法 | 說(shuō)明 |
|---|---|
| write(int b)throws IOException | 將指定的字節(jié)寫入此輸出流(抽象方法) |
| write(byte b[])throws IOException | 將字節(jié)數(shù)組中的數(shù)據(jù)輸出到流中 |
| write(byte b[], int off, int len)throws IOException | 將指定 byte 數(shù)組中從偏移量 off 開始的 len 個(gè)字節(jié)寫入此輸出流 |
| flush()throws IOException | 刷新此輸出流并強(qiáng)制寫出所有緩沖的輸出字節(jié) |
| close()throws IOException | 關(guān)閉流 |
看個(gè)例子
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class test {
/**
* 把輸入流中的所有內(nèi)容賦值到輸出流中
* @param in
* @param out
* @throws IOException
*/
public void copy(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[4096];
int len = in.read(buf);
//read 是一個(gè)字節(jié)一個(gè)字節(jié)地讀,字節(jié)流的結(jié)尾標(biāo)志是-1
while (len != -1){
out.write(buf, 0, len);
len = in.read(buf);
}
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
test t = new test();
System.out.println("輸入字符:");
t.copy(System.in, System.out);
}
}
文件流
在 I/O 處理中,最常見(jiàn)的就是對(duì)文件的操作。java.io 包中所提供的文件操作類包括
- 用于讀寫本地文件系統(tǒng)中的文件:FileInputStream 和 FileOutputStream
- 描述本地文件系統(tǒng)中的文件或目錄: File、FileDescriptor 和 FilenameFilter
- 提供對(duì)本地文件系統(tǒng)中文件的隨機(jī)訪問(wèn)支持:RandomAccessFile
今天我們來(lái)學(xué)習(xí)文件流的FileInputStream 和 FileOutputStream
FileInputStream 類用于打開一個(gè)輸入文件,若要打開的文件不存在,則會(huì)創(chuàng)建一個(gè)新的文件,否則原文件的內(nèi)容會(huì)被新寫入的內(nèi)容所覆蓋;
在進(jìn)行文件的讀/寫操作時(shí),會(huì)產(chǎn)生非運(yùn)行時(shí)異常IOException,必須捕獲或聲明拋棄(其他的輸入/輸出流處理時(shí)也同樣需要進(jìn)行輸入/輸出異常處理)
文件構(gòu)造方法:
//打開一個(gè)以 f 描述的文件作為輸入
FileInputStream(File f)
//打開一個(gè)文件路徑名為 name 的文件作為輸入
FileInputStream(String name)
//創(chuàng)建一個(gè)以 f 描述的文件作為輸出
//如果文件存在,則其內(nèi)容被清空
FileOutputStream(File f)
//創(chuàng)建一個(gè)文件路徑名為 name 的文件作為輸出
//文件如果已經(jīng)存在,則其內(nèi)容被清空
FileOutputStream(String name)
//創(chuàng)建一個(gè)文件路徑名為 name 的文件作為輸出
//文件如果已經(jīng)存在,則在該輸出上輸出的內(nèi)容被接到原有內(nèi)容之后
FileOutputStream(String name, boolean append)
示例代碼 :
File f1 = new File("file1.txt");
File f2 = new File("file2.txt");
FileInputStream in = new FileInputStream(f1);
FileOutputStream out = new FileOutputStream(f2);
輸入流的參數(shù)是用于指定輸入的文件名,輸出流的參數(shù)則是用于指定輸出的文件名
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class test {
public static void main(String[] args) {
try {
//inFile 作為輸入流的數(shù)據(jù)文件必須存在,否則拋出異常
File inFile = new File("/Users/mumutongxue/Documents/file1.txt");
//file2.txt 沒(méi)有,系統(tǒng)可以創(chuàng)建,在 workspace 的 Test 項(xiàng)目下可以找到
File outFile = new File("file2.txt");
FileInputStream fis = new FileInputStream(inFile);
FileOutputStream fos = new FileOutputStream(outFile);
int c;
while((c = fis.read()) != -1){
fos.write(c);
}
//打開了文件一定要記著關(guān),釋放系統(tǒng)資源
fis.close();
fos.close();
}catch(FileNotFoundException e) {
System.out.println("FileStreamsTest:" + e);
}catch(IOException e){
System.err.println("FileStreamTest:" + e);
}
}
}
緩沖流
類BufferedInputStream 和 BufferedOutoutStream 實(shí)現(xiàn)了帶緩沖的過(guò)濾流,它提供了緩沖機(jī)制,把任意的I/O流“捆綁”到緩沖流上,可以提高I/O流的讀取效率
在初始化時(shí),除了要指定所連接的I/O流之外,還可以指定緩沖區(qū)的大小,缺省時(shí)是用32字節(jié)大小的緩沖區(qū);最優(yōu)的緩沖區(qū)大小以來(lái)于主機(jī)操作系統(tǒng)、可使用的內(nèi)存空間以及機(jī)器的配置等;一般緩沖區(qū)的大小為內(nèi)存頁(yè)或磁盤塊等的整數(shù)倍
BufferedInputStream 的數(shù)據(jù)成員buf是一個(gè)位數(shù)組,默認(rèn)為2048字節(jié),當(dāng)讀取數(shù)據(jù)來(lái)源時(shí)例如文件,BufferedInputStream 會(huì)盡量將buf填滿。當(dāng)使用read() 方法時(shí),實(shí)際上是先讀取buf中的數(shù)據(jù),而不是直接對(duì)數(shù)據(jù)來(lái)源作讀取。當(dāng)buf中的數(shù)據(jù)不足時(shí),BufferedInputStream 才會(huì)再實(shí)現(xiàn)給定的InputStream對(duì)象的read() 方法,從指定的裝置中提取數(shù)據(jù)。
BufferedInputStream 的數(shù)據(jù)成員 buf 是一位數(shù)組,默認(rèn)為512字節(jié)。當(dāng)使用write() 方法寫入數(shù)據(jù)時(shí),實(shí)際上會(huì)先將數(shù)據(jù)寫至buf中,當(dāng)buf已滿時(shí)才會(huì)實(shí)現(xiàn)給定的OutputStream 對(duì)象的write() 方法,將buf數(shù)據(jù)寫至目的地,而不是每次都對(duì)目的地作寫入的動(dòng)作。
構(gòu)造方法:
//[ ] 里的內(nèi)容代表選填
BufferedInputStream(InputStream in [, int size])
BufferedOutputStream(OutputStream out [, int size])
舉個(gè)例子,將緩沖流與文件流相接
FileInputStream in = new FileInputStream("file.txt");
FileOutputStream out = new FileOutputStream("file2.txt");
//設(shè)置輸入緩沖區(qū)大小為 256 字節(jié)
BufferedInputStream bin = new BufferedInputStream(in,256)
BufferedOutputStream bout = new BufferedOutputStream(out,256)
int len;
byte bArray[] = new byte[256];
len = bin.read(bArray); //len 中得到的是實(shí)際讀取的長(zhǎng)度,bArray 中得到的是數(shù)據(jù)
https://doc.shiyanlou.com/document-uid79144labid1113timestamp1436118879920.png/wm
對(duì)于 BufferedOutputStream,只有緩沖區(qū)滿時(shí),才會(huì)將數(shù)據(jù)真正送到輸出流,但可以使用 flush() 方法人為地將尚未填滿的緩沖區(qū)中的數(shù)據(jù)送出。
例如方法copy();
public void copy(InputStream in, OutputStream out) throws IOException {
out = new BufferedOutputStream(out, 4096);
byte[] buf = new byte[4096];
int len = in.read(buf);
while (len != -1) {
out.write(buf, 0, len);
len = in.read(buf);
}
//最后一次讀取得數(shù)據(jù)可能不到 4096 字節(jié)
out.flush();
}
數(shù)據(jù)流
接口 DataInput 和 DataOutput,設(shè)計(jì)了一種較為高級(jí)的數(shù)據(jù)輸入輸出方式:除了可處理字節(jié)和字節(jié)數(shù)組外,還可以處理 int、float、boolean 等基本數(shù)據(jù)類型,這些數(shù)據(jù)在文件中的表示方式和它們?cè)趦?nèi)存中的一樣,無(wú)須轉(zhuǎn)換,如 read(), readInt(), readByte()...; write(), writeChar(), writeBoolean()... 此外,還可以用 readLine() 方法讀取一行信息。
方法 :
| 方法 | 返回值 | 說(shuō)明 |
|---|---|---|
| readBoolean() | boolean | |
| readByte() | byte | |
| readShort() | short | |
| readChar() | char | |
| readInt() | int | |
| readLong() | long | |
| readDouble() | double | |
| readFloat() | float | |
| readUnsignedByte() | int | |
| readUnsignedShort() | int | |
| readFunlly(byte[] b) | void | 從輸入流中讀取一些字節(jié),并將它們存儲(chǔ)在緩沖區(qū)數(shù)組b中 |
| reaFully(byte[] b, int off, int len) | void | 從輸入流中讀取len個(gè)字節(jié) |
| skipBytes(int n) | int | 與InputStream.skip 等價(jià) |
| readUTF() | String | 按照UTF-8形式從輸入中讀取字符串 |
| readLine() | String | 按回車(\r)換行(\n)為分隔符讀取一行字符串,不完全支持UNICODE |
| writeBoolean(boolean v) | void | |
| writeByte(int v) | void | |
| writeShort(int v) | void | |
| writeChar(int v) | void | |
| writeInt(int v) | void | |
| writeLong(long v) | void | |
| writeFloat(float v) | void | |
| writeDouble(double v) | void | |
| write(byte[] b) | void | 與OutputStream.write 同義 |
| write(byte[] b,int off,int len) | void | 與OutputStream.write 同義 |
| write(int b) | void | 與OutputStream.write 同義 |
| writeBytes(String s) | void | 只輸出每個(gè)字符的低 8 位;不完全支持 UNICODE |
| writeChars(String s) | void | 每個(gè)字符在輸出中都占兩個(gè)字節(jié) |
數(shù)據(jù)流類 DataInputStream 和 DataOutputStream 的處理對(duì)象除了是字節(jié)或字節(jié)數(shù)組外,還可以實(shí)現(xiàn)對(duì)文件的不同數(shù)據(jù)類型的讀寫;
- 分別實(shí)現(xiàn)了DataInput 和 DataOutput 接口
- 在提供字節(jié)流的讀寫手段同時(shí),以統(tǒng)一的形式向輸入流中寫入boolean,int,long,double 等基本數(shù)據(jù)類型,并可以再次把基本數(shù)據(jù)類型的值取回來(lái)
- 提供了字符串讀寫的手段
數(shù)據(jù)流可以連接一個(gè)已經(jīng)建立好的數(shù)據(jù)對(duì)象,例如網(wǎng)絡(luò)連接、文件等。數(shù)據(jù)流可以通過(guò)如下方式建立;
FileInputStream fis = new FileInputStream("file1.txt");
FileOutputStream fos = new FileOutputStream("file2.txt");
DataInputStream dis = new DataInputStream(fis);
DataOutputStream dos = new DataOutputStream(fos);
接下來(lái)我們通過(guò)具體的代碼,看一看它的用法吧;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataStream {
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
//向文件 a.txt 寫入
FileOutputStream fos = new FileOutputStream("a.txt");
DataOutputStream dos = new DataOutputStream(fos);
try {
dos.writeBoolean(true);
dos.writeByte((byte)123);
dos.writeChar('J');
dos.writeDouble(3.1415926);
dos.writeFloat(2.122f);
dos.writeInt(123);
}
finally {
dos.close();
}
//從文件 a.txt 讀出
FileInputStream fis = new FileInputStream("a.txt");
DataInputStream dis = new DataInputStream(fis);
try {
System.out.println("\t" + dis.readBoolean());
System.out.println("\t" + dis.readByte());
System.out.println("\t" + dis.readChar());
System.out.println("\t" + dis.readDouble());
System.out.println("\t" + dis.readFloat());
System.out.println("\t" + dis.readInt());
}
finally {
dis.close();
}
}
}
標(biāo)準(zhǔn)流、內(nèi)存讀寫流、順序輸入流
標(biāo)準(zhǔn)流
語(yǔ)言包 java.lang 中的System類管理標(biāo)準(zhǔn)輸入/輸出流和錯(cuò)誤流
System.in 從InputStream中繼承而來(lái),用于從標(biāo)準(zhǔn)輸入設(shè)備中獲取輸入數(shù)據(jù)(通常是鍵盤)
System.out 從PrintStream 中繼承而來(lái),把輸入送到缺省的顯示設(shè)備(通常是顯示器)
System.err 也是從PrintStream中繼承而來(lái),把錯(cuò)誤信息送到缺省的顯示設(shè)備(通常是顯示器)
每當(dāng)mian方法被執(zhí)行時(shí),就會(huì)自動(dòng)生產(chǎn)上述三個(gè)對(duì)象。這里就不再寫代碼驗(yàn)證了。
內(nèi)存讀寫流
為了支持在內(nèi)存上的I/O,java.io 中提供了類;ByteArrayInputStream、ByteArrayOutputStream 和 StringBufferInputStream
- ByteArrayInputStream 可以從指定的字節(jié)數(shù)組中讀取數(shù)據(jù)
- ByteArrayOutputStream 中提供了 緩沖區(qū)可以存放數(shù)據(jù)(緩沖區(qū)大小可以在構(gòu)造方法中設(shè)定,缺省為32),可以用write() 方法 向其中寫入數(shù)據(jù),然后用toByArray() 方法將緩沖區(qū)中的有效字節(jié)寫到字節(jié)數(shù)組中去。size() 方法可以知道寫入的字節(jié)數(shù); reset() 可以丟棄所有內(nèi)容
- StringBufferInputStream 與 ByteArrayInputStream 相類似,不同點(diǎn)在于它是從字符緩沖區(qū) StringBuffer 中讀取 16位的 Unicode 數(shù)據(jù),而不是 8 位的字節(jié)數(shù)據(jù)(已被StringReader取代)
這里只做簡(jiǎn)要的介紹,有興趣的同學(xué)可以查看一下這些類里具體的方法。
順序輸入流
java.io 中提供了類SequenceInputStream, 使應(yīng)用程序可以將幾個(gè)輸入流順序連接起來(lái)。順序輸入流提供了將多個(gè)不同的輸入流統(tǒng)一為一個(gè)輸入流的功能,這使得程序可能變得更加簡(jiǎn)潔
例如:
FileInputStream f1,f2;
String s;
f1 = new FileInputStream("file1.txt");
f2 = new FileInputStream("file2.txt");
SequenceInputStream fs = new SequenceInputStream(f1,f2);
DataInputeStream ds = new DataInputStream(fs);
while((s = ds.readLine()) != null) {
System.out.println(s);
}