Java中I/O操作主要是指使用Java進行輸入,輸出操作. Java所有的I/O機制都是基于數據流進行輸入輸出,這些數據流表示了字符或者字節數據的流動序列。
數據流是一串連續不斷的數據的集合,就象水管里的水流,在水管的一端一點一點地供水,而在水管的另一端看到的是一股連續不斷的水流。數據寫入程序可以是一段、一段地向數據流管道中寫入數據,這些數據段會按先后順序形成一個長的數據流。對數據讀取程序來說,看不到數據流在寫入時的分段情況,每次可以讀取其中的任意長度的數據,但只能先讀取前面的數據后,再讀取后面的數據(不能隨機讀取)。不管寫入時是將數據分多次寫入,還是作為一個整體一次寫入,讀取時的效果都是完全一樣的。
簡而言之:數據流是一組有序,有起點和終點的字節的數據序列。包括輸入流和輸出流。
當程序需要讀取數據的時候,就會建立一個通向數據源的連接,這個數據源可以是文件,內存,或是網絡連接。類似的,當程序需要寫入數據的時候,就會建立一個通向目的地的連接。
數據流分類:
流序列中的數據既可以是未經加工的原始二進制數據,也可以是經一定編碼處理后符合某種格式規定的特定數據。因此Java中的流分為兩種:** 1) 字節流:數據流中最小的數據單元是字節 2) 字符流:**數據流中最小的數據單元是字符, Java中的字符是Unicode編碼,一個字符占用兩個字節。
概覽
Java.io包中最重要的就是5個類和一個接口。5個類指的是File、OutputStream、InputStream、Writer、Reader;一個接口指的是Serializable。掌握了這些就掌握了Java I/O的精髓了。
Java I/O主要包括如下3層次:
流式部分——最主要的部分。如:OutputStream、InputStream、Writer、Reader等
非流式部分——如:File類、RandomAccessFile類和FileDescriptor等類
其他——文件讀取部分的與安全相關的類,如:SerializablePermission類,以及與本地操作系統相關的文件系統的類,如:FileSystem類和Win32FileSystem類和WinNTFileSystem類。
主要類如下:
File(文件特征與管理):用于文件或者目錄的描述信息,例如生成新目錄,修改文件名,刪除文件,判斷文件所在路徑等。
InputStream(字節流,二進制格式操作):抽象類,基于字節的輸入操作,是所有輸入流的父類。定義了所有輸入流都具有的共同特征。
OutputStream(字節流,二進制格式操作):抽象類。基于字節的輸出操作。是所有輸出流的父類。定義了所有輸出流都具有的共同特征。
Reader(字符流,文本格式操作):抽象類,基于字符的輸入操作。
Writer(字符流,文本格式操作):抽象類,基于字符的輸出操作。
RandomAccessFile(隨機文件操作):它的功能豐富,可以從文件的任意位置進行存取(輸入輸出)操作。
I/O流
java.io包里有4個基本類:InputStream、OutputStream及Reader、Writer類,它們分別處理字節流和字符流。
其他各種各樣的流都是由這4個派生出來的。
按來源/去向分類:
File(文件): FileInputStream, FileOutputStream, FileReader, FileWriter
byte[]:ByteArrayInputStream, ByteArrayOutputStream
Char[]: CharArrayReader, CharArrayWriter
String: StringBufferInputStream, StringReader, StringWriter
網絡數據流:InputStream, OutputStream, Reader, Writer
InputStream
InputStream 為字節輸入流,它本身為一個抽象類,必須依靠其子類實現各種功能,此抽象類是表示字節輸入流的所有類的超類。 繼承自InputStream 的流都是向程序中輸入數據的,且數據單位為字節(8bit);
InputStream是輸入字節數據用的類,所以InputStream類提供了3種重載的read方法.Inputstream類中的常用方法:
public abstract int read( ):讀取一個byte的數據,返回值是高位補0的int類型值。若返回值=-1說明沒有讀取到任何字節讀取工作結束。
public int read(byte b[ ]):讀取b.length個字節的數據放到b數組中。返回值是讀取的字節數。該方法實際上是調用下一個方法實現的
public int read(byte b[ ], int off, int len):從輸入流中最多讀取len個字節的數據,存放到偏移量為off的b數組中。
public int available( ):返回輸入流中可以讀取的字節數。注意:若輸入阻塞,當前線程將被掛起,如果InputStream對象調用這個方法的話,它只會返回0,這個方法必須由繼承InputStream類的子類對象調用才有用,
public long skip(long n):忽略輸入流中的n個字節,返回值是實際忽略的字節數, 跳過一些字節來讀取
public int close( ) :使用完后,必須對我們打開的流進行關閉。
來看看幾種不同的InputStream:
FileInputStream把一個文件作為InputStream,實現對文件的讀取操作
ByteArrayInputStream:把內存中的一個緩沖區作為InputStream使用
StringBufferInputStream:把一個String對象作為InputStream
PipedInputStream:實現了pipe的概念,主要在線程中使用
SequenceInputStream:把多個InputStream合并為一個InputStream
OutputStream
OutputStream提供了3個write方法來做數據的輸出,這個是和InputStream是相對應的。
public void write(byte b[ ]):將參數b中的字節寫到輸出流。
public void write(byte b[ ], int off, int len) :將參數b的從偏移量off開始的len個字節寫到輸出流。
public abstract void write(int b) :先將int轉換為byte類型,把低字節寫入到輸出流中。
public void flush( ) : 將數據緩沖區中數據全部輸出,并清空緩沖區。
public void close( ) : 關閉輸出流并釋放與流相關的系統資源。
幾種不同的OutputStream:
ByteArrayOutputStream:把信息存入內存中的一個緩沖區中
FileOutputStream:把信息存入文件中
PipedOutputStream:實現了pipe的概念,主要在線程中使用
SequenceOutputStream:把多個OutStream合并為一個OutStream
Reader和InputStream類似;Writer和OutputStream類似。
有兩個需要注意的:
**InputStreamReader **: 從輸入流讀取字節,在將它們轉換成字符。
BufferReader :接受Reader對象作為參數,并對其添加字符緩沖器,使用readline()方法可以讀取一行。
如何選擇I/O流
確定是輸入還是輸出輸入:輸入流 InputStream Reader輸出:輸出流 OutputStream Writer
明確操作的數據對象是否是純文本是:字符流 Reader,Writer否:字節流 InputStream,OutputStream
明確具體的設備。文件:讀:FileInputStream,, FileReader,寫:FileOutputStream,FileWriter
數組:byte[ ]:ByteArrayInputStream, ByteArrayOutputStreamchar[ ]:CharArrayReader, CharArrayWriter
String:StringBufferInputStream(已過時,因為其只能用于String的每個字符都是8位的字符串), StringReader, StringWriter
Socket流鍵盤:用System.in(是一個InputStream對象)讀取,用System.out(是一個OutoutStream對象)打印
是否需要轉換流是,就使用轉換流,從Stream轉化為Reader、Writer:InputStreamReader,OutputStreamWriter
是否需要緩沖提高效率是就加上Buffered:BufferedInputStream, BufferedOuputStream, BufferedReader, BufferedWriter
是否需要格式化輸出
示例代碼
將標準輸入(鍵盤輸入)顯示到標準輸出(顯示器),支持字符。
char ch;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); //將字節流轉為字符流,帶緩沖
try {
while ((ch = (char) in.read()) != -1){
System.out.print(ch);
}
} catch (IOException e) {
e.printStackTrace();
}
將AtomicityTest.java的內容打印到顯示器
方法一:
BufferedReader in = new BufferedReader(new FileReader("AtomicityTest.java"));
String s;
try {
while ((s = in.readLine()) != null){
System.out.println(s);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
方法二:
FileReader in = new FileReader("AtomicityTest.java");
int b;
try {
while ((b = in.read()) != -1){
System.out.print((char)b);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
方法三:(有可能出現亂碼)
FileInputStream in = new FileInputStream("AtomicityTest.java");
int n = 50;
byte[] buffer = new byte[n];
try {
while ((in.read(buffer,0,n) != -1 && n > 0)){
System.out.print(new String(buffer));
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
將文件A的內容拷貝到文件B
FileInputStream in = new FileInputStream("AtomicityTest.java");
FileOutputStream out = new FileOutputStream("copy.txt");
int b;
while ((b = in.read()) != -1){
out.write(b);
}
out.flush();
in.close();
out.close();
將標準輸入的內容寫入文件
Scanner in = new Scanner(System.in);
FileWriter out = new FileWriter("systemIn.log");
String s;
while (!(s = in.nextLine()).equals("Q")){
out.write(s + "\n");
}
out.flush();
out.close();
in.close();