1.???? Abstract:
Java將I/O分為高階I/O與低階I/O,高階I/O在使用上提供更多的讀寫(xiě)方法,如讀寫(xiě) int、double、String的資料型態(tài),而低階的I/O大部份只提供write、read的byte[]存取,因?yàn)槌淌酱蟛糠莸馁Y料都是以字串或 其它主要型態(tài)資料來(lái)運(yùn)算,因此低階的I/O在使用上不利於程式設(shè)計(jì),所以Java將許多好用的方法全部集合成高階I/O; 換言之,低階I/O的主要工作是負(fù)責(zé)與媒體資料作存取,高階I/O類(lèi)別主要作資料型態(tài)的轉(zhuǎn)換及提供一些特殊的功能。在使用Java I/O時(shí)要謹(jǐn)記的一個(gè)重要原則是,在建立一個(gè)I/O之前必需先用低階I/O類(lèi)別來(lái)存取媒體資料(如檔案或pipe),之後再使用高階I/O來(lái)控制低階 I/O類(lèi)別的動(dòng)作,這種一層又一層的架構(gòu)稱(chēng)I/O Chain。底下為Java的I/O架構(gòu)圖,第一個(gè)為以byte為單位的I/O,第二個(gè)則是以char為單位。

2.???? File I/O:
A.???? FileInputStream & FileOutputStream
FileInputStream是讀取檔案用的類(lèi)別,其建構(gòu)式有叁個(gè):
public FileInputStream(String strFilename) throws FileNotFoundException
public FileInputStream(File fIn) throws FileNotFoundException
public FileInputStream(FileDescriptor fdObj)
?? 在這里我只講第一個(gè),這是最直覺(jué)的方式,如下的范例1,會(huì)一次從e:\test.txt讀10個(gè)bytes,將讀入的結(jié)果輸出到標(biāo)準(zhǔn)輸出設(shè)備,直到檔案結(jié) 束。在這個(gè)范例中要注意的是,available會(huì)傳回輸入串流中還有多少個(gè)bytes,read則會(huì)根據(jù)buffer的大小來(lái)決定一次讀幾個(gè) bytes,并將實(shí)際讀到的byte數(shù)傳回。
===== 范例 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是寫(xiě)入檔案用的類(lèi)別,其建構(gòu)式有四個(gè):
??????????????? 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

??????? 第四個(gè)和第一個(gè)的差別只在於當(dāng)檔案存在時(shí),第一個(gè)會(huì)將原來(lái)的檔案內(nèi)容覆蓋,第四個(gè)則可以選擇覆蓋或?qū)⑿聝?nèi)容接在原內(nèi)容後面。范例2以建構(gòu)式一講解如何寫(xiě)入 一個(gè)檔案…在這個(gè)范例中要注意的是,fIn每個(gè)讀10個(gè)bytes,但是最後一次不一定會(huì)讀10個(gè)bytes,因此,fOut在write時(shí),要指明要寫(xiě) 幾個(gè)bytes到檔案中,否則最後一次仍會(huì)寫(xiě)入10個(gè)bytes,因Java在new byte時(shí)會(huì)先將內(nèi)容先填0,所以後面的幾個(gè)bytes會(huì)是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最大不同在於,F(xiàn)ileInputStream讀取的單位是byte,F(xiàn)ileReader讀取的單位是char。另外 要注意的是,在FileInputStream中以available來(lái)判斷是否還有資料可讀取,在FileReader中是以ready來(lái)判斷,
但是,available是傳回還有多少個(gè)bytes可以讀取,ready則傳回true或false,當(dāng)傳回true時(shí)表示,下次read時(shí)保證不會(huì)停頓,當(dāng)傳回false時(shí),表示下次read時(shí)”可能”停頓,所謂可能是指不保證不會(huì)停頓。
Ps. 測(cè)試時(shí),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的最大不同也在於寫(xiě)入單位的不同,F(xiàn)ileOutputStream為byte,F(xiàn)ileWriter為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();
}
}

C.???? BufferedReader & BufferedWriter
File I/O是相當(dāng)耗時(shí)的作業(yè),通常電腦在做處理時(shí),者會(huì)建立一個(gè)緩沖區(qū),一次讀取或?qū)懭胍粋€(gè)區(qū)塊,借由減少I(mǎi)/O次數(shù),來(lái)節(jié)省時(shí)間 ,在Java中的BufferedReader和BufferedWriter就是提供這樣的緩沖功能。
在 范例5中,我們將FileReader導(dǎo)向BufferedReader,將FileWriter導(dǎo)向BufferedWriter,來(lái)達(dá)到區(qū)塊讀取、寫(xiě) 入的目的。BufferedReader提供的readLine一次可以讀取一行,當(dāng)遇到檔尾時(shí),會(huì)傳回null。BufferedWriter提供的 newLine會(huì)產(chǎn)生列尾符號(hào),這個(gè)列尾符號(hào)隨作業(yè)系統(tǒng)的不同而不同,在Windows上為\r\n,在Unix上為\n,在Mac上為\r,這個(gè)符號(hào)是 依據(jù)line.separator系統(tǒng)性質(zhì)而來(lái)的。需注意的是,如果將BufferedWriter應(yīng)用到網(wǎng)路程式時(shí),絕對(duì)不要使用newLine,因?yàn)?絕大多數(shù)的網(wǎng)路協(xié)定都是以\r\n為列尾,不會(huì)因作業(yè)系統(tǒng)不同而異。
===== 范例 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
在檔案處理方面,程式不只是要對(duì)檔案做讀、寫(xiě),有時(shí)也需要得知檔案的屬性,或刪除、移動(dòng)、更名,有時(shí)則是要找出或列出某目錄下的某些檔案,針對(duì)這些運(yùn)作,Java提供了File這個(gè)類(lèi)別。底下的范例,說(shuō)明如何使用File類(lèi)別。

a.?????? 如何得知檔案屬性:
在 范例6中需注意的是lastModified傳回的最後更改時(shí)間是自1970/1/1 00:00:00算起的時(shí)間,單位為毫秒,所以要用Date將它轉(zhuǎn)換成日期、時(shí)間; 另外getCanonicalPath和getAbsolutePath得到的值在Windows上會(huì)是一樣的,在Unix可能就會(huì)不一樣。
===== 范例 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.????? 建立、刪除、移動(dòng)、更名:
File 類(lèi)別提供了createNewFile、renameTo、delete作為建立(createNewFile)、刪除(delete)、移動(dòng)、更名 (renameTo)之用,使用方式如下: (移動(dòng)和更名都用renameTo,就如在Unix上檔案搬移和更名都用mv一樣)
===== 范例 7 =====
import java.io.*;
public class OperateFile {

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類(lèi)別提供的list和listFiles都可以列出某特定目錄里的所有檔案,其中l(wèi)ist傳回的是String[],listFiles傳回的是File[],這兩個(gè)函式都會(huì)傳回所有的檔案和目錄。
===== 范例 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對(duì)網(wǎng)路的支援只有TCP/IP和UDP/IP,提供的類(lèi)別有URL、URLConnection、Socket、ServerSocket,在這里我只打算用ServerSocket、Socket為例,來(lái)說(shuō)明Network I/O。
基本上,Java的I/O不管在任何的媒體上都是將它們視為stream,所以,網(wǎng)路I/O和檔案I/O原理也是一致的,底下的兩個(gè)程式分別為server socket及client socket。在看范例之前,可以再?gòu)?fù)習(xí)一下前面的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]);
}
}

4.???? Object Serialization:
A.???? 所謂Object Serialization就是把物件的”狀態(tài)”儲(chǔ)存成一系列的位元組,而這些位元組在稍候可用來(lái)恢復(fù)物件。更簡(jiǎn)單的說(shuō),Object Serialization是讓物件可以以物件為儲(chǔ)存單位。在Java中,任何物件要能Serialization,必須implements Serializable這個(gè)Interface,以下是一個(gè)簡(jiǎn)單的程式范例,可以將物件儲(chǔ)存到e:\point.ser,或從e:\point.ser 將物件恢復(fù)原值。
===== 范例 11 =====
import java.io.*;
public class ThreeDPoint implements Serializable
{
private double m_dblX, m_dblY, m_dblZ;

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中,一個(gè)實(shí)作某特定介面的類(lèi)別,其子類(lèi)別也因繼承的原故而被視為實(shí)作了該介面,因此,許多沒(méi)有明確宣告實(shí)作Serializable介面的類(lèi)別,事實(shí)上也是可以被Serialization的。
C.???? 并非每個(gè)實(shí)作了Serializable介面的物件都可以被Serialization,如果這個(gè)物件繼承圖上的祖先,有其中一個(gè)是不可以被Serialization,那麼這個(gè)物件就不可以被Serialization。
5.???? Formated I/O:
在Java 的I/O里,并沒(méi)有所謂的型別,不管是int、long、double…最後都是以String輸出,所以如果要讓數(shù)字以特定格式輸出,需透過(guò)Java提 供的兩個(gè)類(lèi)別java.text.NumberFormat和java.text.DecimalFormat將數(shù)字格式化後再輸出。
范例12簡(jiǎn) 要說(shuō)明NumberFormat如何使用,在開(kāi)始使用NumberFormat時(shí),應(yīng)先用getInstance取得NumberFormat的實(shí)體,范 例12中的setMaximumIntegerDigits和setMinimumFractionDigits是用來(lái)設(shè)定整數(shù)和小數(shù)的位數(shù),另外還有 setMinimumIntegerDigits和setMaximumFractionDigits也是同樣功能。這些設(shè)定如有沖突,Java以最後設(shè) 定的為準(zhǔn)。
===== 范例 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();
}
}
另 一個(gè)類(lèi)別DecimalFormat是繼承NumberFormat的子類(lèi)別,它提供了更強(qiáng)的格式化功能,透過(guò)設(shè)定pattern,可以使我們的輸出更多 樣化,至於Java提供的pattern有那些? 在API Document中有詳細(xì)說(shuō)明! 范例13僅舉其一,說(shuō)明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();
}
}


文章來(lái)源:http://x-spirit.spaces.live.com/Blog/cns!CC0B04AE126337C0!399.entry