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是從裝置來源地讀取數(shù)據(jù)的抽象表示,例如System中的標(biāo)準(zhǔn)輸入流in對象就是一個InputStream類型的實例。
我們先來看看InputStream類的方法:
方法 | 說明 |
---|---|
read()throws IOException | 從輸入流中讀取數(shù)據(jù)的下一個字節(jié)(抽象方法) |
skip(long n) throws IOException | 跳過和丟棄此輸入流中數(shù)據(jù)的n個字節(jié) |
available() throws IOException | 返回流中可用字節(jié)數(shù) |
mark(int readlimit) throws IOException | 在此輸入流中標(biāo)記當(dāng)前的位置 |
reset() throws IOException | 將此流重新定位到最后一次對此輸入流調(diào)用mark方法時的位置 |
markSupport() throws IOException | 測試此輸入流是否支持mark 和 reset 方法 |
close() throws IOException | 關(guān)閉流 |
在InputStream類中,方法read()提供了三種從流中讀數(shù)據(jù)的方法;
- int read(): 從輸入流中讀一個字節(jié),形成一個0~255之間的整數(shù)返回(是一個抽象方法)
- int read(byte b[]): 從輸入流中讀取一定數(shù)量的字節(jié),并將其存儲在緩沖區(qū)數(shù)組b中。
- int read(byte b[], int off,int len): 從輸入流中讀取長度為len的數(shù)據(jù),寫入數(shù)組b中從索引off開始的位置,并返回讀取的字節(jié)數(shù)。
對于這三個方法,若返回-1,表明流結(jié)束,否則,返回實際讀取的字符數(shù)。
OutputStream
OutputStream 是所有表示字節(jié)輸出流類的基類。子類要重新定義其中所定義的抽象方法,OutputStream 是用于將數(shù)據(jù)寫入目的地的抽象表示。例如 System 中的標(biāo)準(zhǔn)輸出流對象 out 其類型是 java.io.PrintStream,這個類是 OutputStream 的子類。
OutputStream 類方法:
方法 | 說明 |
---|---|
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 個字節(jié)寫入此輸出流 |
flush()throws IOException | 刷新此輸出流并強制寫出所有緩沖的輸出字節(jié) |
close()throws IOException | 關(guān)閉流 |
看個例子
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 是一個字節(jié)一個字節(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 處理中,最常見的就是對文件的操作。java.io 包中所提供的文件操作類包括
- 用于讀寫本地文件系統(tǒng)中的文件:FileInputStream 和 FileOutputStream
- 描述本地文件系統(tǒng)中的文件或目錄: File、FileDescriptor 和 FilenameFilter
- 提供對本地文件系統(tǒng)中文件的隨機訪問支持:RandomAccessFile
今天我們來學(xué)習(xí)文件流的FileInputStream 和 FileOutputStream
FileInputStream 類用于打開一個輸入文件,若要打開的文件不存在,則會創(chuàng)建一個新的文件,否則原文件的內(nèi)容會被新寫入的內(nèi)容所覆蓋;
在進(jìn)行文件的讀/寫操作時,會產(chǎn)生非運行時異常IOException,必須捕獲或聲明拋棄(其他的輸入/輸出流處理時也同樣需要進(jìn)行輸入/輸出異常處理)
文件構(gòu)造方法:
//打開一個以 f 描述的文件作為輸入
FileInputStream(File f)
//打開一個文件路徑名為 name 的文件作為輸入
FileInputStream(String name)
//創(chuàng)建一個以 f 描述的文件作為輸出
//如果文件存在,則其內(nèi)容被清空
FileOutputStream(File f)
//創(chuàng)建一個文件路徑名為 name 的文件作為輸出
//文件如果已經(jīng)存在,則其內(nèi)容被清空
FileOutputStream(String name)
//創(chuàng)建一個文件路徑名為 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 沒有,系統(tǒng)可以創(chuàng)建,在 workspace 的 Test 項目下可以找到
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 實現(xiàn)了帶緩沖的過濾流,它提供了緩沖機制,把任意的I/O流“捆綁”到緩沖流上,可以提高I/O流的讀取效率
在初始化時,除了要指定所連接的I/O流之外,還可以指定緩沖區(qū)的大小,缺省時是用32字節(jié)大小的緩沖區(qū);最優(yōu)的緩沖區(qū)大小以來于主機操作系統(tǒng)、可使用的內(nèi)存空間以及機器的配置等;一般緩沖區(qū)的大小為內(nèi)存頁或磁盤塊等的整數(shù)倍
BufferedInputStream 的數(shù)據(jù)成員buf是一個位數(shù)組,默認(rèn)為2048字節(jié),當(dāng)讀取數(shù)據(jù)來源時例如文件,BufferedInputStream 會盡量將buf填滿。當(dāng)使用read() 方法時,實際上是先讀取buf中的數(shù)據(jù),而不是直接對數(shù)據(jù)來源作讀取。當(dāng)buf中的數(shù)據(jù)不足時,BufferedInputStream 才會再實現(xiàn)給定的InputStream對象的read() 方法,從指定的裝置中提取數(shù)據(jù)。
BufferedInputStream 的數(shù)據(jù)成員 buf 是一位數(shù)組,默認(rèn)為512字節(jié)。當(dāng)使用write() 方法寫入數(shù)據(jù)時,實際上會先將數(shù)據(jù)寫至buf中,當(dāng)buf已滿時才會實現(xiàn)給定的OutputStream 對象的write() 方法,將buf數(shù)據(jù)寫至目的地,而不是每次都對目的地作寫入的動作。
構(gòu)造方法:
//[ ] 里的內(nèi)容代表選填
BufferedInputStream(InputStream in [, int size])
BufferedOutputStream(OutputStream out [, int size])
舉個例子,將緩沖流與文件流相接
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 中得到的是實際讀取的長度,bArray 中得到的是數(shù)據(jù)
https://doc.shiyanlou.com/document-uid79144labid1113timestamp1436118879920.png/wm
對于 BufferedOutputStream,只有緩沖區(qū)滿時,才會將數(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è)計了一種較為高級的數(shù)據(jù)輸入輸出方式:除了可處理字節(jié)和字節(jié)數(shù)組外,還可以處理 int、float、boolean 等基本數(shù)據(jù)類型,這些數(shù)據(jù)在文件中的表示方式和它們在內(nèi)存中的一樣,無須轉(zhuǎn)換,如 read(), readInt(), readByte()...; write(), writeChar(), writeBoolean()... 此外,還可以用 readLine() 方法讀取一行信息。
方法 :
方法 | 返回值 | 說明 |
---|---|---|
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é),并將它們存儲在緩沖區(qū)數(shù)組b中 |
reaFully(byte[] b, int off, int len) | void | 從輸入流中讀取len個字節(jié) |
skipBytes(int n) | int | 與InputStream.skip 等價 |
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 | 只輸出每個字符的低 8 位;不完全支持 UNICODE |
writeChars(String s) | void | 每個字符在輸出中都占兩個字節(jié) |
數(shù)據(jù)流類 DataInputStream 和 DataOutputStream 的處理對象除了是字節(jié)或字節(jié)數(shù)組外,還可以實現(xiàn)對文件的不同數(shù)據(jù)類型的讀寫;
- 分別實現(xiàn)了DataInput 和 DataOutput 接口
- 在提供字節(jié)流的讀寫手段同時,以統(tǒng)一的形式向輸入流中寫入boolean,int,long,double 等基本數(shù)據(jù)類型,并可以再次把基本數(shù)據(jù)類型的值取回來
- 提供了字符串讀寫的手段
數(shù)據(jù)流可以連接一個已經(jīng)建立好的數(shù)據(jù)對象,例如網(wǎng)絡(luò)連接、文件等。數(shù)據(jù)流可以通過如下方式建立;
FileInputStream fis = new FileInputStream("file1.txt");
FileOutputStream fos = new FileOutputStream("file2.txt");
DataInputStream dis = new DataInputStream(fis);
DataOutputStream dos = new DataOutputStream(fos);
接下來我們通過具體的代碼,看一看它的用法吧;
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)流
語言包 java.lang 中的System類管理標(biāo)準(zhǔn)輸入/輸出流和錯誤流
System.in 從InputStream中繼承而來,用于從標(biāo)準(zhǔn)輸入設(shè)備中獲取輸入數(shù)據(jù)(通常是鍵盤)
System.out 從PrintStream 中繼承而來,把輸入送到缺省的顯示設(shè)備(通常是顯示器)
System.err 也是從PrintStream中繼承而來,把錯誤信息送到缺省的顯示設(shè)備(通常是顯示器)
每當(dāng)mian方法被執(zhí)行時,就會自動生產(chǎ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 相類似,不同點在于它是從字符緩沖區(qū) StringBuffer 中讀取 16位的 Unicode 數(shù)據(jù),而不是 8 位的字節(jié)數(shù)據(jù)(已被StringReader取代)
這里只做簡要的介紹,有興趣的同學(xué)可以查看一下這些類里具體的方法。
順序輸入流
java.io 中提供了類SequenceInputStream, 使應(yīng)用程序可以將幾個輸入流順序連接起來。順序輸入流提供了將多個不同的輸入流統(tǒng)一為一個輸入流的功能,這使得程序可能變得更加簡潔
例如:
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);
}