java IO詳解

1.     Abstract:
Java將I/O分爲高階I/O與低階I/O,高階I/O在使用上提供更多的讀寫方法,如讀寫int、double、String的資料型態,而低階的I/O大部份只提供write、read的byte[]存取,由於程式大部份的資料都是以字串或其它主要型態資料來運算,所以低階的I/O在使用上不利於程式設計,因此Java將許多好用的方法所有集合成高階I/O; 換言之,低階I/O的主要工做是負責與媒體資料做存取,高階I/O類別主要做資料型態的轉換及提供一些特殊的功能。在使用Java I/O時要謹記的一個重要原則是,在創建一個I/O以前必需先用低階I/O類別來存取媒體資料(如檔案或pipe),之後再使用高階I/O來控制低階I/O類別的動做,這種一層又一層的架構稱I/O Chain。底下爲Java的I/O架構圖,第一個爲以byte爲單位的I/O,第二個則是以char爲單位。
 
2.     File I/O:
A.     FileInputStream & FileOutputStream
FileInputStream是讀取檔案用的類別,其建構式有叄個:
public FileInputStream(String strFilename) throws FileNotFoundException
public FileInputStream(File fIn) throws FileNotFoundException
public FileInputStream(FileDescriptor fdObj)
   在這裏我只講第一個,這是最直覺的方式,以下的範例1,會一次從e:\test.txt讀10個bytes,將讀入的結果輸出到標準輸出設備,直到檔案結束。在這個範例中要注意的是,available會傳回輸入串流中還有多少個bytes,read則會根據buffer的大小來決定一次讀幾個bytes,並將實際讀到的byte數傳回。
===== 範例 1 =====
import java.io.*;
public class FIn {
  public FIn() {
    try {
      FileInputStream fis = new FileInputStream("e:/in.txt");
      while (fis.available() > 0) {
        byte[] b = new byte[10];
        int nResult = fis.read(b);
        if (nResult == -1) break;
        System.out.println(new String(b));
      }
      fis.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    FIn fIn = new FIn();
  }
}
        FileOutputStream是寫入檔案用的類別,其建構式有四個:
                Public FileOutputStream(String strFilename) throws FileNotFoundException
                Public FileOutputStream(File fOut) throws FileNotFound Exception
                Public FileOutputStream(FileDescriptor fdObj)
public FileOutputStream(String name, boolean append) throws FileNotFoundException
        第四個和第一個的差異只在於當檔案存在時,第一個會將原來的檔案內容覆蓋,第四個則能夠選擇覆蓋或將新內容接在原內容後面。範例2以建構式一講解如何寫入一個檔案…在這個範例中要注意的是,fIn每一個讀10個bytes,可是最後一次不必定會讀10個bytes,所以,fOut在write時,要指明要寫幾個bytes到檔案中,不然最後一次仍會寫入10個bytes,因Java在new byte時會先將內容先填0,因此後面的幾個bytes會是0。
===== 範例2 =====
import java.io.*;
public class FOut {
  public FOut() {
    try {
      FileInputStream fIn = new FileInputStream("e:/in.txt");
      FileOutputStream fOut = new FileOutputStream("e:/out.txt");
      while (fIn.available() > 0) {
        byte[] b = new byte[10];
        int nResult = fIn.read(b);
        if (nResult == -1) break;
        fOut.write(b, 0, nResult);
      }
      fIn.close();
      fOut.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    FOut FOut1 = new FOut();
  }
}
B.     FileReader & FileWriter
FileReader和FileInputStream最大不一樣在於,FileInputStream讀取的單位是byte,FileReader讀取的單位是char。另外要注意的是,在FileInputStream中以available來判斷是否還有資料可讀取,在FileReader中是以ready來判斷,
可是,available是傳回還有多少個bytes能夠讀取,ready則傳回true或false,當傳回true時表示,下次read時保證不會停頓,當傳回false時,表示下次read時」可能」停頓,所謂多是指不保證不會停頓。
Ps. 測試時,in.txt裏放些中文字就能夠看出以byte和以char爲單位有什麼不一樣。
===== 範例 3 =====
import java.io.*;
public class chFIn {
  public chFIn() {
    try {
      FileReader rdFile = new FileReader("e:/in.txt");
      while (rdFile.ready()) {
        char[] chIn = new char[10];
        int nResult = rdFile.read(chIn);
        if (nResult == -1) break;
        System.out.println(chIn);
      }
rdFile.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    chFIn chFIn1 = new chFIn();
  }
}
        FileWriter和FileOutputStream的最大不一樣也在於寫入單位的不一樣,FileOutputStream爲byte,FileWriter爲char。
===== 範例 4 =====
import java.io.*;
public class chFOut {
  public chFOut() {
    try {
      FileReader rdFile = new FileReader("e:/in.txt");
      FileWriter wrFile = new FileWriter("e:/out.txt");
      while (rdFile.ready()) {
        char[] chIn = new char[10];
        int nResult = rdFile.read(chIn);
        if (nResult == -1) break;
        wrFile.write(chIn, 0, nResult);
      }
      rdFile.close();
      wrFile.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    chFOut chFOut1 = new chFOut();
  }
}java

C.     BufferedReader & BufferedWriter
File I/O是至關耗時的做業,一般電腦在作處理時,者會創建一個緩衝區,一次讀取或寫入一個區塊,藉由減小I/O次數,來節省時間 ,在Java中的BufferedReader和BufferedWriter就是提供這樣的緩衝功能。
在範例5中,咱們將FileReader導向BufferedReader,將FileWriter導向BufferedWriter,來達到區塊讀取、寫入的目的。BufferedReader提供的readLine一次能夠讀取一行,當遇到檔尾時,會傳回null。BufferedWriter提供的newLine會產生列尾符號,這個列尾符號隨做業系統的不一樣而不一樣,在Windows上爲\r\n,在Unix上爲\n,在Mac上爲\r,這個符號是依據line.separator系統性質而來的。需注意的是,若是將BufferedWriter應用到網路程式時,絕對不要使用newLine,由於絕大多數的網路協定都是以\r\n爲列尾,不會因做業系統不一樣而異。
===== 範例 5 =====
import java.io.*;
public class bufIn {
  public bufIn() {
    try {
      FileReader rdFile = new FileReader("e:/in.txt");
      BufferedReader brdFile = new BufferedReader(rdFile);
       FileWriter wrFile = new FileWriter("e:/out.txt");
      BufferedWriter bwrFile = new BufferedWriter(wrFile);
      String strLine;
      while ((strLine = brdFile.readLine()) != null) {
        bwrFile.write(strLine);
        bwrFile.newLine();
      }
      brdFile.close();
      bwrFile.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    bufIn bufIn1 = new bufIn();
  }
}
 D.     File
在檔案處理方面,程式不僅是要對檔案作讀、寫,有時也須要得知檔案的屬性,或刪除、移動、改名,有時則是要找出或列出某目錄下的某些檔案,針對這些運做,Java提供了File這個類別。底下的範例,說明如何使用File類別。
a.       如何得知檔案屬性:
在範例6中需注意的是lastModified傳回的最後更改時間是自1970/1/1 00:00:00算起的時間,單位爲毫秒,因此要用Date將它轉換成日期、時間; 另外getCanonicalPath和getAbsolutePath獲得的值在Windows上會是同樣的,在Unix可能就會不同。
===== 範例 6 =====
import java.io.*;
import java.util.*;
public class FileSpy {
  public FileSpy(String strFilename) {
    File fFile = new File(strFilename);
    if (fFile.exists()) {
      System.out.println("Name: " + fFile.getName());
      System.out.println("Absolute path: " + fFile.getAbsolutePath());
      try {
        System.out.println("Canonical path: " + fFile.getCanonicalPath());
      }
      catch (IOException e) {
        e.printStackTrace();
      }
      if (fFile.canWrite()) System.out.println(fFile.getName() + " is writable");
      if (fFile.canRead()) System.out.println(fFile.getName() + " is readable");
      if (fFile.isFile()) {
        System.out.println(fFile.getName() + " is a file");
      }
      else if (fFile.isDirectory()) {
        System.out.println(fFile.getName() + " is a directory");
      }
      else {
        System.out.println("What is this?");
      }
      long lngMilliseconds = fFile.lastModified();
      if (lngMilliseconds !=0) System.out.println("last modified at " + new Date(lngMilliseconds));
      long lngLen = fFile.length();
      if (lngLen !=0) System.out.println("size: " + lngLen);
    }
    else
      System.out.println("file not found");
  }
  public static void main(String[] args) {
    if (args.length == 1) {
      FileSpy fileSpy1 = new FileSpy(args[0]);
    }
    else
      System.out.println("Usage: java FileSpy Filename");
  }
}
 
b.      創建、刪除、移動、改名:
File類別提供了createNewFile、renameTo、delete做爲創建(createNewFile)、刪除(delete)、移動、改名(renameTo)之用,使用方式以下: (移動和改名都用renameTo,就如在Unix上檔案搬移和改名都用mv同樣)
===== 範例 7 =====
import java.io.*;
public class OperateFile {git

  public OperateFile() {
    //create new file
    File fNewFile = new File("C:/newfile.txt");
    try {
      if (fNewFile.exists() == false) {
        if (fNewFile.createNewFile() == true) {
          System.out.println("create c:/newfile.txt success");
        }
        else {
          System.out.println("create c:/newfile.txt fail");
        }
      }
      else {
        System.out.println("file already exists");
      }
    }
    catch (IOException e) {
      e.printStackTrace();
    }架構

//rename file
    File fRenameFile = new File("c:/renamefile.txt");
    fNewFile.renameTo(fRenameFile);
    //remove file
    File fRemoveFile = new File("d:/" + fRenameFile.getName());
    fRenameFile.renameTo(fRemoveFile);
    //delete file
    try {
      File fDelFile = new File(fRemoveFile.getCanonicalPath());
      fDelFile.delete();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    OperateFile operateFile1 = new OperateFile();
  }
}
c.       找出某特定目錄裏的全部檔案:
File類別提供的list和listFiles均可以列出某特定目錄裏的全部檔案,其中list傳回的是String[],listFiles傳回的是File[],這兩個函式都會傳回全部的檔案和目錄。
===== 範例 8 =====
import java.io.*;
public class ListAllFiles {
  public ListAllFiles(String strDir) {
    File fDir = new File(strDir);
    File[] fAllFiles = fDir.listFiles();
    for(int i=0; i
      if (fAllFiles.isFile())
        System.out.println("File: " + fAllFiles.getName());
      else
        System.out.println("Dir: " + fAllFiles.getName());
    }
  }
  public static void main(String[] args) {
    ListAllFiles listAllFiles1 = new ListAllFiles(args[0]);
  }
}
3.     Network I/O:
Java對網路的支援只有TCP/IP和UDP/IP,提供的類別有URL、URLConnection、Socket、ServerSocket,在這裏我只打算用ServerSocket、Socket爲例,來講明Network I/O。
基本上,Java的I/O無論在任何的媒體上都是將它們視爲stream,因此,網路I/O和檔案I/O原理也是一致的,底下的兩個程式分別爲server socket及client socket。在看範例以前,能夠再複習一下前面的abstract…
===== 範例 9 =====
import java.net.*;
import java.io.*;
public class myServer {
  public myServer(String strPort) {
    int nPort = new Integer(strPort).intValue();
    try {
      ServerSocket ss = new ServerSocket(nPort);
      Socket s = ss.accept();
      OutputStream out = s.getOutputStream();
      PrintStream psOut = new PrintStream(out);
      String strResponse = "Hello " + s.getInetAddress() + " on port " + s.getPort() + "\r\n";
      strResponse += "This is " + s.getLocalAddress() + " on port " + s.getLocalPort() + "\r\n";
      psOut.print(strResponse);
      s.close();
      ss.close();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
 
  public static void main(String[] args) {
    myServer myServer1 = new myServer(args[0]);
  }
}
===== 範例 10 =====
import java.net.*;
import java.io.*;
public class myClient {
  public myClient(String strIP, String strPort) {
    int nPort = new Integer(strPort).intValue();
    try {
      Socket s = new Socket(strIP, nPort);
      InputStream in = s.getInputStream();
      BufferedInputStream bisIn = new BufferedInputStream(in);
      while (bisIn.available() > 0) {
        byte[] b = new byte[30];
        int nLen = bisIn.read(b);
        System.out.println(new String(b, 0, nLen));
      }
    }
    catch (UnknownHostException e) {
      e.printStackTrace();
    }
    catch (IOException e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    myClient myClient1 = new myClient(args[0], args[1]);
  }
}app

4.     Object Serialization:
A.     所謂Object Serialization就是把物件的」狀態」儲存成一系列的位元組,而這些位元組在稍候可用來恢復物件。更簡單的說,Object Serialization是讓物件能夠以物件爲儲存單位。在Java中,任何物件要能Serialization,必須implements Serializable這個Interface,如下是一個簡單的程式範例,能夠將物件儲存到e:\point.ser,或從e:\point.ser將物件恢復原值。
===== 範例 11 =====
import java.io.*;
public class ThreeDPoint implements Serializable
{
  private double m_dblX, m_dblY, m_dblZ;socket

  public ThreeDPoint(double x, double y, double z)
  {
    m_dblX = x;
    m_dblY = y;
    m_dblZ = z;
  }
 public void PrintXYZ()
  {
    System.out.println("X: " + m_dblX);
    System.out.println("Y: " + m_dblY);
    System.out.println("Z: " + m_dblZ);
  }
  public static void main(String[] args)
  {
    if (args[0].equalsIgnoreCase("w")) {
      ThreeDPoint threeDPoint1 = new ThreeDPoint(10 ,20, 30);
      try {
        FileOutputStream fout = new FileOutputStream("e:\\point.ser");
        ObjectOutputStream oout = new ObjectOutputStream(fout);
        oout.writeObject(threeDPoint1);
        oout.close();
         System.out.println("write:");
        threeDPoint1.PrintXYZ();
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }
    else if (args[0].equalsIgnoreCase("r")) {
      try {
        FileInputStream fin = new FileInputStream("e:\\point.ser");
        ObjectInputStream oin = new ObjectInputStream(fin);
        Object o = oin.readObject();
        ThreeDPoint threeDPoint1 = (ThreeDPoint) o;
        oin.close();
        System.out.println("read:");
        threeDPoint1.PrintXYZ();
      }
      catch (Exception e) {
      }
    }
  } //end of main
}
B.     在Java中,一個實做某特定介面的類別,其子類別也因繼承的原故而被視爲實做了該介面,所以,許多沒有明確宣告實做Serializable介面的類別,事實上也是能夠被Serialization的。
C.     並不是每一個實做了Serializable介面的物件均可以被Serialization,若是這個物件繼承圖上的祖先,有其中一個是不能夠被Serialization,那麼這個物件就不能夠被Serialization。
5.     Formated I/O:
在Java的I/O裏,並無所謂的型別,不論是int、long、double…最後都是以String輸出,因此若是要讓數字以特定格式輸出,需透過Java提供的兩個類別java.text.NumberFormat和java.text.DecimalFormat將數字格式化後再輸出。
範例12簡要說明NumberFormat如何使用,在開始使用NumberFormat時,應先用getInstance取得NumberFormat的實體,範例12中的setMaximumIntegerDigits和setMinimumFractionDigits是用來設定整數和小數的位數,另外還有setMinimumIntegerDigits和setMaximumFractionDigits也是一樣功能。這些設定若有衝突,Java以最後設定的爲準。
===== 範例 12 =====
import java.text.*;
public class myFormat {
  public myFormat() {
    NumberFormat nf = NumberFormat.getInstance();
    double dblNum = Math.PI;
   System.out.println(dblNum);
    nf.setMaximumIntegerDigits(5);
    nf.setMinimumFractionDigits(4);
    System.out.println("PI: " + nf.format(dblNum));
  }
  public static void main(String[] args) {
    myFormat myFormat1 = new myFormat();
  }
}
另外一個類別DecimalFormat是繼承NumberFormat的子類別,它提供了更強的格式化功能,透過設定pattern,可使咱們的輸出更多樣化,至於Java提供的pattern有那些? 在API Document中有詳細說明! 範例13僅舉其一,說明DecimalFormat如何使用。
===== 範例 13 =====
import java.text.*;
public class myDecimalFormat {
  public myDecimalFormat() {
    DecimalFormat df = new DecimalFormat("0000.000");
    double dblNum = 123.45;
    System.out.println("dblNum: " + dblNum);
    System.out.println("dblNum: " + df.format(dblNum));
  }
  public static void main(String[] args) {
    myDecimalFormat myDecimalFormat1 = new myDecimalFormat();
  }
測試

相關文章
相關標籤/搜索