必讀:徹底明白Java的IO系統—JAVA之精髓IO流!

來源:互聯網
上載者:User

徹底明白Java的IO系統

一. Input和Output
1. stream代表的是任何有能力產出資料的資料來源,或是任何有能力接收資料的接收源。在Java的IO中,所有的stream(包括Input和Out stream)都包括兩種類型:
1.1 以位元組為導向的stream
以位元組為導向的stream,表示以位元組為單位從stream中讀取或往stream中寫入資訊。以位元組為導向的stream包括下面幾種類型:
1) input stream:
1) ByteArrayInputStream:把記憶體中的一個緩衝區作為InputStream使用
2) StringBufferInputStream:把一個String對象作為InputStream
3) FileInputStream:把一個檔案作為InputStream,實現對檔案的讀取操作
4) PipedInputStream:實現了pipe的概念,主要線上程中使用
5) SequenceInputStream:把多個InputStream合并為一個InputStream
2) Out stream
1) ByteArrayOutputStream:把資訊存入記憶體中的一個緩衝區中
2) FileOutputStream:把資訊存入檔案中
3) PipedOutputStream:實現了pipe的概念,主要線上程中使用
4) SequenceOutputStream:把多個OutStream合并為一個OutStream
1.2 以Unicode字元為導向的stream
以Unicode字元為導向的stream,表示以Unicode字元為單位從stream中讀取或往stream中寫入資訊。以Unicode字元為導向的stream包括下面幾種類型:
1) Input Stream
1) CharArrayReader:與ByteArrayInputStream對應
2) StringReader:與StringBufferInputStream對應
3) FileReader:與FileInputStream對應
4) PipedReader:與PipedInputStream對應
2) Out Stream
1) CharArrayWrite:與ByteArrayOutputStream對應
2) StringWrite:無與之對應的以位元組為導向的stream
3) FileWrite:與FileOutputStream對應
4) PipedWrite:與PipedOutputStream對應
以字元為導向的stream基本上對有與之相對應的以位元組為導向的stream。兩個對應類實現的功能相同,字是在操作時的導向不同。如CharArrayReader:和ByteArrayInputStream的作用都是把記憶體中的一個緩衝區作為InputStream使用,所不同的是前者每次從記憶體中讀取一個位元組的資訊,而後者每次從記憶體中讀取一個字元。
1.3 兩種不現導向的stream之間的轉換
InputStreamReader和OutputStreamReader:把一個以位元組為導向的stream轉換成一個以字元為導向的stream。
2. stream添加屬性
2.1 “為stream添加屬性”的作用
運用上面介紹的Java中操作IO的API,我們就可完成我們想完成的任何操作了。但通過FilterInputStream和FilterOutStream的子類,我們可以為stream添加屬性。下面以一個例子來說明這種功能的作用。
如果我們要往一個檔案中寫入資料,我們可以這樣操作:
FileOutStream fs = new FileOutStream(“test.txt”);
然後就可以通過產生的fs對象調用write()函數來往test.txt檔案中寫入資料了。但是,如果我們想實現“先把要寫入檔案的資料先緩衝到記憶體中,再把緩衝中的資料寫入檔案中”的功能時,上面的API就沒有一個能滿足我們的需求了。但是通過FilterInputStream和FilterOutStream的子類,為FileOutStream添加我們所需要的功能。
2.2 FilterInputStream的各種類型
2.2.1 用於封裝以位元組為導向的InputStream
1) DataInputStream:從stream中讀取基本類型(int、char等)資料。
2) BufferedInputStream:使用緩衝區
3) LineNumberInputStream:會記錄input stream內的行數,然後可以調用getLineNumber()和setLineNumber(int)
4) PushbackInputStream:很少用到,一般用於編譯器開發
2.2.2 用於封裝以字元為導向的InputStream
1) 沒有與DataInputStream對應的類。除非在要使用readLine()時改用BufferedReader,否則使用DataInputStream
2) BufferedReader:與BufferedInputStream對應
3) LineNumberReader:與LineNumberInputStream對應
4) PushBackReader:與PushbackInputStream對應
2.3 FilterOutStream的各種類型
2.2.3 用於封裝以位元組為導向的OutputStream
1) DataIOutStream:往stream中輸出基本類型(int、char等)資料。
2) BufferedOutStream:使用緩衝區
3) PrintStream:產生格式化輸出
2.2.4 用於封裝以字元為導向的OutputStream
1) BufferedWrite:與對應
2) PrintWrite:與對應
3. RandomAccessFile
1) 可通過RandomAccessFile對象完成對檔案的讀寫操作
2) 在產生一個對象時,可指明要開啟的檔案的性質:r,唯讀;w,唯寫;rw可讀寫
3) 可以直接跳到檔案中指定的位置
4. I/O應用的一個例子
import java.io.*;
public class TestIO{
public static void main(String[] args)
throws IOException{
//1.以行為單位從一個檔案讀取資料
BufferedReader in =
new BufferedReader(
new FileReader("F://nepalon//TestIO.java"));
String s, s2 = new String();
while((s = in.readLine()) != null)
s2 += s + "/n";
in.close();

//1b. 接收鍵盤的輸入
BufferedReader stdin =
new BufferedReader(
new InputStreamReader(System.in));
System.out.println("Enter a line:");
System.out.println(stdin.readLine());

//2. 從一個String對象中讀取資料
StringReader in2 = new StringReader(s2);
int c;
while((c = in2.read()) != -1)
System.out.println((char)c);
in2.close();

//3. 從記憶體取出格式化輸入
try{
DataInputStream in3 =
new DataInputStream(
new ByteArrayInputStream(s2.getBytes()));
while(true)
System.out.println((char)in3.readByte());
}
catch(EOFException e){
System.out.println("End of stream");
}

//4. 輸出到檔案
try{
BufferedReader in4 =
new BufferedReader(
new StringReader(s2));
PrintWriter out1 =
new PrintWriter(
new BufferedWriter(
new FileWriter("F://nepalon// TestIO.out")));
int lineCount = 1;
while((s = in4.readLine()) != null)
out1.println(lineCount++ + ":" + s);
out1.close();
in4.close();
}
catch(EOFException ex){
System.out.println("End of stream");
}

//5. 資料的儲存和恢複
try{
DataOutputStream out2 =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("F://nepalon// Data.txt")));
out2.writeDouble(3.1415926);
out2.writeChars("/nThas was pi:writeChars/n");
out2.writeBytes("Thas was pi:writeByte/n");
out2.close();
DataInputStream in5 =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("F://nepalon// Data.txt")));
BufferedReader in5br =
new BufferedReader(
new InputStreamReader(in5));
System.out.println(in5.readDouble());
System.out.println(in5br.readLine());
System.out.println(in5br.readLine());
}
catch(EOFException e){
System.out.println("End of stream");
}

//6. 通過RandomAccessFile操作檔案
RandomAccessFile rf =
new RandomAccessFile("F://nepalon// rtest.dat", "rw");
for(int i=0; i<10; i++)
rf.writeDouble(i*1.414);
rf.close();

rf = new RandomAccessFile("F://nepalon// rtest.dat", "r");
for(int i=0; i<10; i++)
System.out.println("Value " + i + ":" + rf.readDouble());
rf.close();

rf = new RandomAccessFile("F://nepalon// rtest.dat", "rw");
rf.seek(5*8);
rf.writeDouble(47.0001);
rf.close();

rf = new RandomAccessFile("F://nepalon// rtest.dat", "r");
for(int i=0; i<10; i++)
System.out.println("Value " + i + ":" + rf.readDouble());
rf.close();
}
}
關於代碼的解釋(以區為單位):
1區中,當讀取檔案時,先把檔案內容讀到緩衝中,當調用in.readLine()時,再從緩衝中以字元的方式讀取資料(以下簡稱“緩衝位元組讀取方式”)。
1b區中,由於想以緩衝位元組讀取方式從標準IO(鍵盤)中讀取資料,所以要先把標準IO(System.in)轉換成字元導向的stream,再進行BufferedReader封裝。
2區中,要以字元的形式從一個String對象中讀取資料,所以要產生一個StringReader類型的stream。
4區中,對String對象s2讀取資料時,先把對象中的資料存入緩衝中,再從緩衝中進行讀取;對TestIO.out檔案進行操作時,先把格式化後的資訊輸出到緩衝中,再把緩衝中的資訊輸出到檔案中。
5區中,對Data.txt檔案進行輸出時,是先把基本類型的資料輸出屋緩衝中,再把緩衝中的資料輸出到檔案中;對檔案進行讀取操作時,先把檔案中的資料讀取到緩衝中,再從緩衝中以基本類型的形式進行讀取。注意in5.readDouble()這一行。因為寫入第一個writeDouble(),所以為了正確顯示。也要以基本類型的形式進行讀取。
6區是通過RandomAccessFile類對檔案進行操作。

----

重要提示:

LineNumberInputStream,StringBufferInputStream已經廢除!大家不要再用!

StringBufferInputStream,This class does not properly convert characters into bytes!

StringBufferInputStream,Deprecated. This class incorrectly assumes that bytes adequately represent characters!

----------------關心IO,就是關心你的JAVA前途之路!-----------------------

DataInputStream流中已經沒有readLine()整個方法!

替換為: BufferedReader d=new BufferedReader(new InputStreamReader(in));

--------把位元組流轉換為字元流接入緩衝讀取字元流中,再進行處理!
這個方法很大的優勢!

----------------------
-----------------Why use character streams?------------------
The primary advantage of character streams is that they make it easy to write programs that are not dependent upon a specific character encoding, and are therefore easy to internationalize.
Java stores strings in Unicode, an international standard character encoding that is capable of representing most of the world's written languages. Typical user-readable text files, however, use encodings that are not necessarily related to Unicode, or even to ASCII, and there are many such encodings. Character streams hide the complexity of dealing with these encodings by providing two classes that serve as bridges between byte streams and character streams. The InputStreamReader class implements a character-input stream that reads bytes from a byte-input stream and converts them to characters according to a specified encoding. Similarly, the OutputStreamWriter class implements a character-output stream that converts characters into bytes according a specified encoding and writes them to a byte-output stream.

A second advantage of character streams is that they are potentially much more efficient than byte streams. The implementations of many of Java's original byte streams are oriented around byte-at-a-time read and write operations. The character-stream classes, in contrast, are oriented around buffer-at-a-time read and write operations. This difference, in combination with a more efficient locking scheme, allows the character stream classes to make up for the added overhead of encoding conversion in many cases.

----------標準裝置System.in讀取資料------------------
-----------------------------------------------------
讀取位元組:BufferedInputStream
讀取字元:BufferedReader + InputStreamReader
----------------------------------------------
import java.io.*;

public class systemin
{
public static void main(String args[])
{ try{ //流轉換!
BufferedReader is=new BufferedReader(new InputStreamReader(System.in))
String inputline=null;
while((inputline=is.readLine())!=null)
System.out.println(inputline);
is.close();
}
catch(IOException e)
{ System,out.println("IOXE: "+e);
}
}
}
--------------------------------------------------------------------------------

-----------------標準輸出System.out是一個列印流PrintStream---------------------
import java.io.*;

public class PrintStandardOutput {

public static void main(String[] args) {
String myAnswer = "No, and that's final,";
System.out.println("Hello World of Java");
System.out.println("The answer is " + myAnswer + " at this time.");

PrintWriter pw = new PrintWriter(System.out);
pw.println("The answer is " + myAnswer + " at this time.");

int i = 42;
pw.println(i + '=' + " the answer.");
pw.println("Note: " + i + '=' + " the answer.");
pw.println(i + "=" + " the answer.");
pw.println(i + ('=' + " the answer."));

pw.close();
}
}
-----------------------------------------------------------------------------------
-----------------------要讀取(輸出到—)一個文字檔-----------------------------

BufferedReader is=new BufferedReader(new FileReader("xxxx.text"));讀取
BufferedOutputStream byteout=new BufferedOutputStream(new FileOutputStream("XX.dat"));
// 寫出到文本!

-----------------------------------------------

---------------利用 BufferedReader--FileReader讀取文字檔!-----------

---------------在IO中始終要注意是位元組流還是字元流----------------------
-----------------------------------------------------------------------
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

class filewindow extends JFrame implements ActionListener
{
JTextArea text;
BufferedReader in;
JButton button;
FileReader file;
filewindow()
{
super("檔案字元流");
Container con=getContentPane();
text=new JTextArea(50,50);
text.setBackground(Color.blue);
try{
File f=new File("E://a.txt");
file=new FileReader(f);
in=new BufferedReader(file);
/**BufferedReader(Reader in)建構函式,
*檔案自字元讀取流FileReader接入BufferedReader
*流中,以便用BufferedReader的對象方法readLine()高效成行讀取!
*/

}
catch(FileNotFoundException e){}
catch(IOException e){}
button=new JButton("讀取");
button.addActionListener(this);
con.setLayout(new BorderLayout());
setSize(300,200);
setVisible(true);

con.add(text,"Center");
con.add(button,"South");
addWindowListener(new WindowAdapter()
{public void windowClosing(WindowEvent e)
{setVisible(false);System.exit(0);}});

}
public void actionPerformed(ActionEvent e)
{
String s;
if(e.getSource()==button)
try{
while((s=in.readLine())!=null)
text.append(s+'/n');
//在這裡大家還可以用BufferString來暫時儲存讀取的字元資料!
}
catch(IOException e1){}
}
//---------main()----------
public static void main(String args[])
{
filewindow win=new filewindow();
win.pack();
}
}

-------------------RandomAccessFile隨機讀取檔案---------------
import java.io.*;

public class RandomRead
{
final static String FILENAME="E://a.txt";
protected String fileName;
protected RandomAccessFile seeker;

public static void main(String[] argv) throws IOException {
RandomRead r = new RandomRead(FILENAME);

System.out.println("Offset is " + r.readOffset());
System.out.println("Message is /"" + r.readMessage() + "/".");
}

/** Constructor: save filename, construct RandomAccessFile */
public RandomRead(String fname) throws IOException {
fileName = fname;
seeker = new RandomAccessFile(fname, "rw");
}

/** Read the Offset field, defined to be at location 0 in the file. */
public int readOffset() throws IOException {
seeker.seek(0);
seeker.writeChars(FILENAME); // move to very beginning
return seeker.readInt(); // and read the offset
}

/** Read the message at the given offset */
public String readMessage() throws IOException {
seeker.seek(120); // move to where
return seeker.readLine(); // and read the String
}
}

寫得很辛苦,我本來不想再說什麼了,但本著對技術負責的精神還是說出來.

對於I/O的理解屬於3級水平(如果java IO有十級的話)
錯誤太多.
對於I/O層次不熟悉
java IO主要包括
java.io包和java.nio包.

java.io主要從四個介面延伸:
位元組:
InputStream/OutputStream,其下為封裝,過濾,特定對象處理的具體實作類別.
字元:
Reader/Writer(原文中連Writer介面全都寫成Write,足以說明根本不瞭解這了介面,如果你經常使用Writer介面怎麼會連Writer和Write都分不清,不是一處失誤,而是全部都是Write)

以上四個介面中,底層全部是操作位元組的阻塞方式流.

java.nio主要以塊操作塊(Buffer)為主,通過可以設定的阻塞和非陰塞模式,極大地提過了資料輸出輸
入的效能,而且將Channel通過選選取器模式的控制,可以實現在同一輸出輸入通道上多使用者並發進行資料轉送入.比如一個Socket連接埠可以同時被無限多(理論上不受限制)個用戶端並發訪問.就是經典的I/O多工技術.

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.