隨筆-153  評(píng)論-235  文章-19  trackbacks-0
          轉(zhuǎn)載:http://www.cnblogs.com/wjun530/archive/2007/06/14/782898.html

          徹底明白Java的IO系統(tǒng)

          一. Input和Output
          1. stream代表的是任何有能力產(chǎn)出數(shù)據(jù)的數(shù)據(jù)源,或是任何有能力接收數(shù)據(jù)的接收源。在Java的IO中,所有的stream(包括Input和Out stream)都包括兩種類型:
          1.1 以字節(jié)為導(dǎo)向的stream
          以字節(jié)為導(dǎo)向的stream,表示以字節(jié)為單位從stream中讀取或往stream中寫入信息。以字節(jié)為導(dǎo)向的stream包括下面幾種類型:
          1) input stream:
          1) ByteArrayInputStream:把內(nèi)存中的一個(gè)緩沖區(qū)作為InputStream使用
          2) StringBufferInputStream:把一個(gè)String對(duì)象作為InputStream
          3) FileInputStream:把一個(gè)文件作為InputStream,實(shí)現(xiàn)對(duì)文件的讀取操作
          4) PipedInputStream:實(shí)現(xiàn)了pipe的概念,主要在線程中使用
          5) SequenceInputStream:把多個(gè)InputStream合并為一個(gè)InputStream
          2) Out stream
          1) ByteArrayOutputStream:把信息存入內(nèi)存中的一個(gè)緩沖區(qū)中
          2) FileOutputStream:把信息存入文件中
          3) PipedOutputStream:實(shí)現(xiàn)了pipe的概念,主要在線程中使用
          4) SequenceOutputStream:把多個(gè)OutStream合并為一個(gè)OutStream
          1.2 以Unicode字符為導(dǎo)向的stream
          以Unicode字符為導(dǎo)向的stream,表示以Unicode字符為單位從stream中讀取或往stream中寫入信息。以Unicode字符為導(dǎo)向的stream包括下面幾種類型:
          1) Input Stream
          1) CharArrayReader:與ByteArrayInputStream對(duì)應(yīng)
          2) StringReader:與StringBufferInputStream對(duì)應(yīng)
          3) FileReader:與FileInputStream對(duì)應(yīng)
          4) PipedReader:與PipedInputStream對(duì)應(yīng)
          2) Out Stream
          1) CharArrayWrite:與ByteArrayOutputStream對(duì)應(yīng)
          2) StringWrite:無(wú)與之對(duì)應(yīng)的以字節(jié)為導(dǎo)向的stream
          3) FileWrite:與FileOutputStream對(duì)應(yīng)
          4) PipedWrite:與PipedOutputStream對(duì)應(yīng)
          以字符為導(dǎo)向的stream基本上對(duì)有與之相對(duì)應(yīng)的以字節(jié)為導(dǎo)向的stream。兩個(gè)對(duì)應(yīng)類實(shí)現(xiàn)的功能相同,字是在操作時(shí)的導(dǎo)向不同。如CharArrayReader:和ByteArrayInputStream的作用都是把內(nèi)存中的一個(gè)緩沖區(qū)作為InputStream使用,所不同的是前者每次從內(nèi)存中讀取一個(gè)字節(jié)的信息,而后者每次從內(nèi)存中讀取一個(gè)字符。
          1.3 兩種不現(xiàn)導(dǎo)向的stream之間的轉(zhuǎn)換
          InputStreamReader和OutputStreamReader:把一個(gè)以字節(jié)為導(dǎo)向的stream轉(zhuǎn)換成一個(gè)以字符為導(dǎo)向的stream。
          2. stream添加屬性
          2.1 “為stream添加屬性”的作用
          運(yùn)用上面介紹的Java中操作IO的API,我們就可完成我們想完成的任何操作了。但通過FilterInputStream和FilterOutStream的子類,我們可以為stream添加屬性。下面以一個(gè)例子來(lái)說(shuō)明這種功能的作用。
          如果我們要往一個(gè)文件中寫入數(shù)據(jù),我們可以這樣操作:
          FileOutStream fs = new FileOutStream(“test.txt”);
          然后就可以通過產(chǎn)生的fs對(duì)象調(diào)用write()函數(shù)來(lái)往test.txt文件中寫入數(shù)據(jù)了。但是,如果我們想實(shí)現(xiàn)“先把要寫入文件的數(shù)據(jù)先緩存到內(nèi)存中,再把緩存中的數(shù)據(jù)寫入文件中”的功能時(shí),上面的API就沒有一個(gè)能滿足我們的需求了。但是通過FilterInputStream和FilterOutStream的子類,為FileOutStream添加我們所需要的功能。
          2.2 FilterInputStream的各種類型
          2.2.1 用于封裝以字節(jié)為導(dǎo)向的InputStream
          1) DataInputStream:從stream中讀取基本類型(int、char等)數(shù)據(jù)。
          2) BufferedInputStream:使用緩沖區(qū)
          3) LineNumberInputStream:會(huì)記錄input stream內(nèi)的行數(shù),然后可以調(diào)用getLineNumber()和setLineNumber(int)
          4) PushbackInputStream:很少用到,一般用于編譯器開發(fā)
          2.2.2 用于封裝以字符為導(dǎo)向的InputStream
          1) 沒有與DataInputStream對(duì)應(yīng)的類。除非在要使用readLine()時(shí)改用BufferedReader,否則使用DataInputStream
          2) BufferedReader:與BufferedInputStream對(duì)應(yīng)
          3) LineNumberReader:與LineNumberInputStream對(duì)應(yīng)
          4) PushBackReader:與PushbackInputStream對(duì)應(yīng)
          2.3 FilterOutStream的各種類型
          2.2.3 用于封裝以字節(jié)為導(dǎo)向的OutputStream
          1) DataIOutStream:往stream中輸出基本類型(int、char等)數(shù)據(jù)。
          2) BufferedOutStream:使用緩沖區(qū)
          3) PrintStream:產(chǎn)生格式化輸出
          2.2.4 用于封裝以字符為導(dǎo)向的OutputStream
          1) BufferedWrite:與對(duì)應(yīng)
          2) PrintWrite:與對(duì)應(yīng)
          3. RandomAccessFile
          1) 可通過RandomAccessFile對(duì)象完成對(duì)文件的讀寫操作
          2) 在產(chǎn)生一個(gè)對(duì)象時(shí),可指明要打開的文件的性質(zhì):r,只讀;w,只寫;rw可讀寫
          3) 可以直接跳到文件中指定的位置
          4. I/O應(yīng)用的一個(gè)例子
          import java.io.*;
          public class TestIO{
          public static void main(String[] args)
          throws IOException{
          //1.以行為單位從一個(gè)文件讀取數(shù)據(jù)
          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. 從一個(gè)String對(duì)象中讀取數(shù)據(jù)
          StringReader in2 = new StringReader(s2);
          int c;
          while((c = in2.read()) != -1)
          System.out.println((char)c);
          in2.close();

          //3. 從內(nèi)存取出格式化輸入
          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. 數(shù)據(jù)的存儲(chǔ)和恢復(fù)
          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();
          }
          }
          關(guān)于代碼的解釋(以區(qū)為單位):
          1區(qū)中,當(dāng)讀取文件時(shí),先把文件內(nèi)容讀到緩存中,當(dāng)調(diào)用in.readLine()時(shí),再?gòu)木彺嬷幸宰址姆绞阶x取數(shù)據(jù)(以下簡(jiǎn)稱“緩存字節(jié)讀取方式”)。
          1b區(qū)中,由于想以緩存字節(jié)讀取方式從標(biāo)準(zhǔn)IO(鍵盤)中讀取數(shù)據(jù),所以要先把標(biāo)準(zhǔn)IO(System.in)轉(zhuǎn)換成字符導(dǎo)向的stream,再進(jìn)行BufferedReader封裝。
          2區(qū)中,要以字符的形式從一個(gè)String對(duì)象中讀取數(shù)據(jù),所以要產(chǎn)生一個(gè)StringReader類型的stream。
          4區(qū)中,對(duì)String對(duì)象s2讀取數(shù)據(jù)時(shí),先把對(duì)象中的數(shù)據(jù)存入緩存中,再?gòu)木彌_中進(jìn)行讀取;對(duì)TestIO.out文件進(jìn)行操作時(shí),先把格式化后的信息輸出到緩存中,再把緩存中的信息輸出到文件中。
          5區(qū)中,對(duì)Data.txt文件進(jìn)行輸出時(shí),是先把基本類型的數(shù)據(jù)輸出屋緩存中,再把緩存中的數(shù)據(jù)輸出到文件中;對(duì)文件進(jìn)行讀取操作時(shí),先把文件中的數(shù)據(jù)讀取到緩存中,再?gòu)木彺嬷幸曰绢愋偷男问竭M(jìn)行讀取。注意in5.readDouble()這一行。因?yàn)閷懭氲谝粋€(gè)writeDouble(),所以為了正確顯示。也要以基本類型的形式進(jìn)行讀取。
          6區(qū)是通過RandomAccessFile類對(duì)文件進(jìn)行操作。

          ----

          重要提示:

          LineNumberInputStream,StringBufferInputStream已經(jīng)廢除!大家不要再用!

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

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


          ----------------關(guān)心IO,就是關(guān)心你的JAVA前途之路!-----------------------

          DataInputStream流中已經(jīng)沒有readLine()整個(gè)方法!

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

          --------把字節(jié)流轉(zhuǎn)換為字符流接入緩存讀取字符流中,再進(jìn)行處理!
          這個(gè)方法很大的優(yōu)勢(shì)!

          ----------------------
          -----------------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.

          ----------標(biāo)準(zhǔn)設(shè)備System.in讀取數(shù)據(jù)------------------
          -----------------------------------------------------
          讀取字節(jié):BufferedInputStream
          讀取字符:BufferedReader + InputStreamReader
          ----------------------------------------------
          import java.io.*;

          public class systemin
          {
          public static void main(String args[])
          { try{ //流轉(zhuǎn)換!
          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);
          }
          }
          }
          --------------------------------------------------------------------------------

          -----------------標(biāo)準(zhǔn)輸出System.out是一個(gè)打印流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();
          }
          }
          -----------------------------------------------------------------------------------
          -----------------------要讀取(輸出到—)一個(gè)文本文件-----------------------------


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

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

          ---------------利用 BufferedReader--FileReader讀取文本文件!-----------

          ---------------在IO中始終要注意是字節(jié)流還是字符流----------------------
          -----------------------------------------------------------------------
          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)構(gòu)造函數(shù),
          *文件自字符讀取流FileReader接入BufferedReader
          *流中,以便用BufferedReader的對(duì)象方法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來(lái)暫時(shí)保存讀取的字符數(shù)據(jù)!
          }
          catch(IOException e1){}
          }
          //---------main()----------
          public static void main(String args[])
          {
          filewindow win=new filewindow();
          win.pack();
          }
          }


          -------------------RandomAccessFile隨機(jī)讀取文件---------------
          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
          }
          }

          寫得很辛苦,我本來(lái)不想再說(shuō)什么了,但本著對(duì)技術(shù)負(fù)責(zé)的精神還是說(shuō)出來(lái).

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

          java.io主要從四個(gè)接口延伸:
          字節(jié):
          InputStream/OutputStream,其下為封裝,過濾,特定對(duì)象處理的具體實(shí)現(xiàn)類.
          字符:
          Reader/Writer(原文中連Writer接口全都寫成Write,足以說(shuō)明根本不了解這了接口,如果你經(jīng)常使用Writer接口怎么會(huì)連Writer和Write都分不清,不是一處失誤,而是全部都是Write)

          以上四個(gè)接口中,底層全部是操作字節(jié)的阻塞方式流.

          java.nio主要以塊操作塊(Buffer)為主,通過可以設(shè)定的阻塞和非陰塞模式,極大地提過了數(shù)據(jù)輸出輸
          入的性能,而且將Channel通過選選擇器模式的控制,可以實(shí)現(xiàn)在同一輸出輸入通道上多用戶并發(fā)進(jìn)行數(shù)據(jù)傳輸入.比如一個(gè)Socket端口可以同時(shí)被無(wú)限多(理論上不受限制)個(gè)客戶端并發(fā)訪問.就是經(jīng)典的I/O多路復(fù)用技術(shù).

          posted on 2008-03-17 14:26 流浪汗 閱讀(826) 評(píng)論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 黎川县| 祁东县| 临猗县| 松阳县| 五大连池市| 黎平县| 嘉善县| 武定县| 交口县| 武胜县| 民乐县| 遂宁市| 清原| 崇文区| 革吉县| 太谷县| 彭泽县| 丽江市| 泸西县| 浦北县| 绩溪县| 邢台县| 石家庄市| 通道| 吴川市| 杭锦后旗| 乌鲁木齐县| 大关县| 兴山县| 常州市| 苗栗县| 高邑县| 蓝田县| 临江市| 宜宾市| 乃东县| 阜新市| 德州市| 兴宁市| 小金县| 阿坝|