Chinaunix首页 | 论坛 | 博客
  • 博客访问: 565590
  • 博文数量: 136
  • 博客积分: 4010
  • 博客等级: 上校
  • 技术积分: 1343
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-19 23:18
文章分类

全部博文(136)

文章存档

2011年(28)

2009年(60)

2008年(48)

我的朋友

分类: Java

2008-11-23 10:16:27

Java輸入與輸出(下)
作者:資深工程師 段維瀚先生

上期介紹了基本的 I/O 觀念,以及 non-stream I/O 之後,本期要介紹 Java I/O Stream。篇幅較長,因為作者在每一個細節都講解得非常詳盡,相信各位可以從中獲益良多。

Java I/O Stream(串流)
Stream是串流的意思,Data Stream可翻譯成資料串流,亦即資料在資料來源端(Data Source)與資料目的端(Data Sink)之間流動的概念。就像溪流有著固定的源頭、流向地及水流方向。流動的水就好比資料,水的源頭是資料來源端(Data Source),水所流向的目的地就是資料目的端(Data Sink),資料傳輸則是具方向性的。每一條溪流的源頭與目的地都不同(例如目的地不一定是大海,有可能是湖泊或是其他溪流的分支…等),因此Data Stream也會有不同的來源端(Data Source)與目的端(Data Sink)。

1. Source & Sink Stream
Data Source Stream又稱為Input stream或Reader,用途是初始資料流。Data Source Sink又稱為Output stream或Writer,作用為接收資料流。Java支援二種Stream資料型態分別是byte與character。當傳輸的資料是Byte時,使用Input stream類別與Output stream類別;傳輸的資料若為Character,則用Reader類別與Writer類別。

  Byte Streams Character Streams
Source Streams

InputStream

Reader
Sink Streams

OutputStream

Writer


【圖】Data Stream、Data Source與Data Sink之間的關係圖

‧Input Stream與Output Stream
Input Stream與Output Stream用來輸入與輸出byte資料串列(byte stream),Input Stream輸入標的可以是File、String、bytes array、pipe、internet與其他的stream;Output Stream的輸出標的則包括File、bytes array、pipe。InputStream類別與OutputStream類別分別繼承自Object。
InputStream以read()方法讀取單一byte資料或一連串bytes(a bytes array)資料。

方法名稱
傳回值
說明
read()

int

從InputStream物件中讀取一個byte,並傳回下一組位元組資料。。
read(byte[] b)

static File

將從InputStream物件中讀取某些數量的資料填到b中,並傳回已經讀取的位元組數目。

read(byte[] b, int off, int len)

static File

在InputStream物件中從off位置開始讀取len個位元組資料並填入到b中,再傳回已經讀取的位元組數目。


read()方法的傳回值若為-1,表示已到檔尾。利用read()方法可讀取InputStream物件的資料,但是InputStream物件無法做寫入的動作。
OutputStream以write()方法寫入單一byte資料或一連串bytes(a bytes array)的資料。

方法名稱
傳回值
說明
write(byte[ ] b)

void

將b中所有的資料寫入。
write(byte[ ] b, int off, int len)

void

將b中off位置開始的len個位元組的資料寫入。

write(int b)

void

寫入一個指定的byte(也就是b的位元組資料)。


利用write()方法可寫入OurputStream物件的資料,但OutputStream物件無法做讀取的動作。

‧Reader與Writer
Reader與Writer用來輸入與輸出character資料串列(character stream)。Reader類別與Writer類別也分別繼承自Object而來。

Read與Write關於讀取與寫入的方法:
Read讀取資料的方法是read()方法,可用來讀取單一character資料或者是一連串character(String)的資料。read()方法的傳回值若為-1,表示已到檔尾。

方法名稱
傳回值
說明
read()
int
從Reader物件中讀取一個字元,並傳回下一個字元。
read(char[] cbuf) int 從Reader物件中讀取些許字元填入cbuf中,並傳回已經讀取的字元數目。
read(char[] cbuf) int 在Reader物件中從off位置開始讀取len個字元資料並填入到cbuf中,並傳回已經讀取的字元數目。

Write寫出資料的方法是write()方法,可用來寫出單一character資料或者是一連串character(String)的資料。

方法名稱
傳回值
說明
write(char[] cbuf)
void
寫出一個名為cbuf的字元陣列cbuf。
void write(char[] cbuf, int off, int len
void
將cbuf中從第off位置開始,並寫出長度為len的字元資料
write(int c) void 寫出一個指定的字元(也就是c的16位元所表示的字元資料)。
write(String str) void 寫出一個字串(str)。
write(String str, int off, int len) void 將str中從第off位置開始,並寫出長度為len的字元資料。


2. Node Streams

node Streams是可直接連結到實體資源的Stream物件,所謂實體資源是指Files、memory與Pipe。

Node Streams列表

Byte Streams
Character Streams
用途
FileInputStream
FileOutputStream
FileReader
FileWriter
讀取/寫入檔案中的資料
ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter
讀取記憶體中buffer內的資料/將資料寫入記憶體中的buffer(Array資料型別)
  StringReader
StringWriter
讀取記憶體中buffer內的資料/將資料寫入記憶體中的buffer(String資料型別)
PipedInputStream
PipedOutputStream
PipedReader
PipedWriter
Pipe(process或thread)。利用Piped Stream能讓執行緒(threads)之間能彼此溝通,在使用上的時候必需要成對使用(有input端也有output端)。


‧FileInputStream與FileOutputStream

利用FileInputStream與FileOutputStream分別繼承自InputStream與OutputStream類別,在執行上是位元導向(byte-oriented),是用來開啟檔案以供讀取檔案內容,若檔案不存在時則會自動建立新檔。

FileInputStream建構子
FileInputStream建構子
說明
FileInputStream(File file)
建立一個FileInputStream並指定一個File類別物件file。
FileInputStream(FileDescriptor fdObj)
建立一個FileInputStream並指定一個FileDescriptor類別物件fdObj。
FileInputStream(String name) 建立一個FileInputStream並給定檔案名稱name

FileOutputStream建構子
FileInputStream建構子
說明
FileInputStream(File file)
建立一個FileInputStream並指定一個File類別物件file。
FileOutputStream(File file, Boolean append)
建立一個FileOutputStream並指定一個File類別物件file,若append變數設定為true則會將欲加入的新文字接續在原始檔案中繼有文字之後(write to the end of the file),反之若設為false則會將原始檔案中的文字清除並以新增加的文字取代。
FileOutputStream(FileDescriptor fdObj) 建立一個FileIOututStream並指定一個FileDescriptor類別物件fdObj
FileOutputStream(String name) 建立一個FileOutputStream並給定檔案名稱name
FileOutputStream(String name, boolean append) 建立一個FileOutputStream並給定檔案名稱name,若append變數設定為true則會將欲加入的新文字接續在原始檔案中繼有文字之後(write to the end of the file),反之若設為false則會將原始檔案中的文字清除並以新增加的文字取代。

FileOutputStream範例實作
利用FileOutputStream將資料寫到檔案中

1. import java.io.*;

2. public class Ex_FileOutputStream

3. {

4.  public static void main(String[] args) throws Exception

5.  {

6.   String s;

7.   s = "Java輸入與輸出(Java.io套裝模組)";

8.   byte[] newData = s.getBytes();

9.   System.out.println("將字串\"" + s + "\"寫到檔案”)

10.   System.out.println("資料長度:" + newData.length + " bytes.");

11.   FileOutputStream fo = new FileOutputStream("SampleFile2.txt", true);

12.   fo.write(newData); //直接將byte[]寫入檔案

13.   fo.close(); // 關閉檔案

14.  }

15. }

執行結果:
將字串"Java輸入與輸出(Java.io套裝模組)"寫到檔案
資料長度:31 bytes.
資料寫入前


資料寫入後

程式第7行利用getBytes()方法將s字串指派到newData變數(byte[]陣列)中。第11行利用FileOutputStream開啟SampleFile2.txt檔,並將第二個參數設定為True,使後來加入新增資料時可保存先前的資料不至於被覆蓋。第12行利用write()方法直接將newData寫入。

‧FileReader與FileWriter

FileReader與FileWriter分別是InputStreamReader與OutputStreamWriter的子類別(sub-classes)。FileReader因繼承自InputStreamReader類別,所以能合法使用InputStreamReader類別中所提供的方法。

FileReader建構子

FileReader建構子
說明
FileReader(File file) 建立一個FileReader物件,並指定一個File物件以供讀取。
FileReader(FileDescriptor fd) 建立一個FileReader物件,並指定一個FileDescriptor以供讀取。
FileReader(String fileName) 建立一個FileReader物件,並指定一個File檔名以供讀取。

FileWriter建構子
FileReader建構子
說明
FileWriter(File file) 建立一個FileWriter並指定一的File類別物件file。
FileWriter(FileDescriptor fd) 建立一個FileWriter並指定一的FileDescriptor類別物件fd。
FileWriter(String fileName) 建立一個FileWriter並給定檔案名稱
FileWriter(String fileName, boolean append) 建立一個FileWriter指定一的File類別物件與boolean值append,當append=true時表示可以將新增資料加在原始資料後面,當append=false時表示新增的資料將覆蓋/取代原始資料。

FileWriter範例實作
本範例先利用FileWriter將字串寫到指定檔案,再利用FileReader依序讀出資料。

利用FileWriter將資料寫到檔案中

1. import java.io.*;

2. public class Ex_FileWriter

3. {

4.  public static void main(String[] args) throws Exception

5.  {

6.   String s;

7.   s = "Java輸入與輸出(Java.io套裝模組)";

8.   System.out.println("利用FileWriter將資料寫到檔案!");

9.   System.out.println("將字串\"" + s + "\"寫到檔案\n資料長度:" +

10.   s.length() + " bytes.");

11.   FileWriter fw = new FileWriter("SampleFile2.txt");

12.   fw.write(s, 0, s.length()); //直接將String寫入檔案

13.   fw.close(); // 關閉檔案

14.   System.out.println("\n利用FileWriter將資料從檔案裡讀出!");

15.   FileReader fr = new FileReader("SampleFile2.txt");

16.   char[] buf = new char[1];

17.   int total_chars;

18.   total_chars = fr.read(buf);

19.   System.out.println("讀取到的SampleFile2.txt檔案內容如下");

20.   System.out.println("----------------------------------");

21.   while (total_chars != -1)

22.   {

23.    System.out.print(new String(buf, 0, total_chars));

24.    total_chars = fr.read(buf);

25.   }

26.   fr.close();

27.  }

28. }

執行結果:

利用FileWriter將資料寫到檔案!
將字串"Java輸入與輸出(Java.io套裝模組)"寫到檔案
資料長度:22 bytes.
利用FileWriter將資料從檔案裡讀出!
讀取到的SampleFile2.txt檔案內容如下----------------------------------
Java輸入與輸出(Java.io套裝模組)


【利用FileWriter將資料寫到檔案之後SampleFile2.txt的內容】

程式第12行fw.write(s, 0, s.length());直接利用writer將String寫入,s.length為字串長度。


3. Processing Streams

Processing Streams是在程式中暫存或執行資料處理時的Stream物件。

Processing Streams列表
Byte Streams
Character Streams
用途
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
暫存資料串流,直接從記憶體中讀取資料以增加執行上的效能。
FilterInputStream
FilterOutputStream
FilterReader
FilterWriter
是用來轉換資料型態的(不過不是他自己做而是由他的子類別來實作),資料流Stream可以經過filter過濾來做資料轉換的動作,值得注意的是FilterInputStream、FilterOutputStream、FilterReader與FilterWriter實際上並沒有提供任何的功能,他的實作方法都是由子類別所提供。
  InputStreamReader
OutputStreamWriter
可將byte的資料轉成character的資料型態,並且可以指定要用哪一種編碼方式來讀取資料。
DataInputStream
DataOutputStream
  利用DataInputStream可以讀取不同類型的資料。利用DataInputStream可以寫入不同類型的資料
ObjectInputStream
ObjectOutputStream
  物件序列化,把物件資訊紀錄到檔案中。
LineNumberInputStream LineNumberReader 用來追蹤目前的行號,並利用getLineNumber()方法來取得行號(此類別於Java2中已經不建議被使用)
PushbackInputStream PushbackReader 將目前所讀到的資料(byte或character)往後退一格,以便再次重新讀取資料(當作甚麼事都沒發生過一樣)
PrintStream PrintWriter 將輸入的資料顯示於螢幕上,其資料輸入來源是Stream。

FilterInputStream是InputStream的子類別。FilterInputStream建構子的存取權限被設定為protected,所以只有它的父類別InputStream才可以使用,無法在一般程式中呼叫使用。在實作上,只有java.io函式庫中的類別才可以呼叫FilterInputStream建構子,因此在處理上必須將資料包裝在InputStream的封包中。

‧FilterInputStream與FilterOutputStream
FilterInputStream建構子
FileReader建構子
說明
FilterOutputStream(OutputStream out) 藉由所傳入的OutputStream物件建立一個FilterOutputStream。注意:所傳入的out是指OutputStream下所有的子類別皆可傳入並建立FilterOutputStream物件。


‧FilterReader與FilterWriter
FilterReader建構子

FileReader建構子
說明
FilterReader(Reader in) 藉由所傳入的Reader物件建立一個FilterReader。注意:FilterReader建構子的存取權限設定是protected。

FilterWriter建構子

FileReader建構子
說明
FilterWriter (Writer out) 藉由所傳入的Writer物件建立一個Filter Writer。注意:Filter Writer建構子的存取權限設定也是protected。

‧DataInput與DataOutput介面
實作DataInput或DataOutput介面的類別將實作出這二個介面提供的所有方法,使其可以讀取或寫入各種型態的資料(資料類型為java primitive types與UTF-8 formate),而DataInputStream、DataOutputStream與RandomAccessFile也實作了此介面並提供了介面中所有的方法。

DataInput介面所提供的方法
DataInput類別介面提供了15種方法,除了skipBytes()方法外,DataInput提供的方法名稱全是以 “read”為字首。

方法名稱
傳回值
說明
readBoolean()
boolean
若讀取的byte(位元組)若為0則回傳值為false,反之則回傳true。
readByte() byte 讀取一個byte。
readChar() char 讀取一個character(字元)。
readDouble() double 讀取double數值(8-bytes)。
readFloat() float 讀取float數值(4-bytes)。
readInt() int 讀取int數值(4-bytes)。
readLong() long 讀取long數值(8-bytes)。
readShort() short 讀取short數值(2-bytes)。
readUnsignedByte() int 讀取1個Unsigned位元組資料,並傳回int型態的資料(0~255)。
readUnsignedShort() int 讀取Unsigned short資料,並傳回int型態的資料(0~65536)。
readUTF() String 讀取UFT-8格式的資料字串。
readFully(byte[] b) void 將從Stream中讀取到的資料放入b中(b為緩衝區位元陣列)
readFully(byte[] b, int off, int, len) void 於Stream中讀取到的資料中從off位置開始讀取len個位元組資料並填入到b中。
readLine() String 讀取Stream中下一行的文字
skipBytes(int n) int 讀取第n個位置之後的位元組資料。

DataInputStream與RandomAccessFile類別必須實作DataInput類別介面中所有的方法。

‧DataOutput介面所提供的方法
DataOutput類別介面提供了14種方法,方法名稱全是以 “write”為字首且傳回值都是void(也就是沒有傳回值)。

方法名稱
傳回值
說明
write(byte[] b)
void
將緩衝區的位元組陣列資料b寫到輸出資料流output stream。
write(byte[] b, int off, int len) void 將緩衝區的位元組陣列資料b中從off位置開始寫入len個位元組資料到output stream。
write(int b) void 將int位元資料(8個低階位元- eight low-order)寫到output stream。請注意寫入的不是b的數值資料而是b的位元資料。
writeBoolean(Boolean b) void 將b的布林值寫入output stream。
writeByte(int v) void 將int位元資料(8個低階位元- eight low-order)寫到output stream。
writeBytes(String s) void 將s字串資料寫入output stream。
writeChar(int v) void 將int位元組資料寫到output stream。也就是寫入字元的資料型態。
writeChars(String s) void 依序將s字串中的每一個字元資料寫到output stream(每1個char是2個bytes)
writeDouble(double v) void 將double數值資料寫入output stream(8-bytes)。
writeFloat(float f) void 將float數值資料寫入output stream(4-bytes)。
writeInt(int v) void 將int數值資料寫入output stream(4-bytes)。
writeLong(long v) void 將long數值資料寫入output stream(8-bytes)。
writeShort(int v) void 將short數值資料寫入output stream(2-bytes)。
writeUTF(String str) void 將str字串資料中的每一個字元用2個bytes寫到output stream,而每一個字元的編碼方式是:Java-modifirf UTF

DataOutputStream與RandomAccessFile類別必須實作DataOutput類別介面中所有的方法。

‧Java I/O 資料串流鏈結
實作上撰寫Java I/O程式時,為求效能與彈性,通常不會只用單一I/O物件來存取Source與Sink端中的資料(例如只使用FileReader與FileWriter),而會搭配不同I/O物件個別特性與彼此間的關係來達到目的,這種使用多種I/O物件之間彼此資料交換的行為我們稱之為 “資料串流鏈結”,同樣的也分為2種鏈結模式分別是InputStream鏈結模式與OutputStream鏈結模式。

InputStream鏈結模式:將資料自來源端接收後傳入記憶體中;
DataSource(Source) a Memory/Program(Sink)
OutputStream鏈結模式:將資料自來源端接收後傳入記憶體中;
Memory/Program(Source) a DataSink(Sink)
有關NodeStream與ProcessStream需求量的多寡會依照實際開發的需求而有所不同。

‧BufferedReader與BufferedWriter
利用資料緩衝區(Buffer)可大量降低檔案操作上的次數以增加程式執行上的效率。BufferedReader與Bufferedwriter是字元導向(char-oriented),讀取資料時不需逐字讀取,可利用readLine()作逐行讀取以提升資料讀取的效率。另外還有一組BufferedInputStream與BufferedOutputStream是位元導向(byte-oriented),資料讀取大致上與BufferedReader與Bufferedwriter相同,通常在input是一個stream且output也是一個stream時才比較容易使用到。以下針對BufferedReader與Bufferedwriter作詳盡說明。

BufferedReader建構子

FileReader建構子
說明
BufferedReader(Reader in) 建立一個BufferReader物件,其參數in必須屬於Reader物件
BufferedReader(Reader in, int sz) 建立一個BufferReader物件,其參數in必須屬於Reader物件。sz為設定buffer大小的參數,一般來說sz都會大於0,這樣的設定才有意義;若sz<=0系統便會丟出IllegalArgumentException例外

BufferedReader常用方法

方法名稱
傳回值
說明
close()

void

關閉BufferedrReader物件的方法
mark(int readAheadLimit)

void

標示目前所讀取到的位置,readAheadLimit表示標示後到reset前的長度

markSupported()

boolean

判斷所輸入的Stream是否支援mark與reset:支援傳回true,反之則傳回false.

read() int 讀取一個字元(character)資料
read(char[] cbuf, int off, int len) int 將所指定位置與長度的資料讀入到cbuf緩衝器中。off:指定資料位置(並由此開始取資料),len:資料長度
readLine() String 讀取一行文字資料(a line of text)
ready() boolean 判斷BufferedReader已經準備好可以讀取資料了,可以傳回true,反之則傳回false
reset() void 讀取到最近一次利用mark()方法所設定的位置
skip(long n) long 從目前讀取的資料位置跳過n個字元,並將跳過後的資料位置為新的讀取位置

BufferedWriter建構子

BufferedWriter建構子
說明
BufferedWriter(Writer out) 建立一個BufferWriter物件,其參數out須屬於Writer物件
BufferedReader(Reader in, int sz)BufferedWriter(Writer out, int sz) 建立一個BufferWriter物件,其參數out必須屬於Reader物件,sz為設定buffer大小的參數

‧BufferedWriter常用方法

方法名稱
傳回值
說明
close() void 關閉BufferedWriter物件的方法
flush()

void

強制將Buffer(緩衝器)內的資料寫入BufferedWriter物件
newLine() void 加入新的一行(Write a line separator)
write(char[] cbuf, int off, int len) void 將所指定位置與長度的資料寫到cbuf緩衝器中。off:指定資料位置(並由此開始取資料),len:資料長度
write(int c) void 將資料寫到BufferedWriter物件中
write(String s, int off, int len) void 將所指定位置與長度的資料寫到BufferedWriter物件中

BufferedReader與BufferedWriter範例程式

BufferedReader與BufferedWriter範例程式

1. import java.io.*;

2. public class Ex_BufferedRW

3. {

4.  public static void main(String[] args) throws Exception

5.  {

6.   // 利用BufferedReader讀取SampleFile.txt的原始資料

7.   FileReader fr1 = new FileReader("SampleFile.txt");

8.   BufferedReader buf_fr1 = new BufferedReader(fr1);

9.   String strReadLine;

10.   System.out.println("利用BufferedReader讀取SampleFile.txt的原始資料如下");

11.   System.out.println("----------------------------------");

12.   strReadLine = buf_fr1.readLine(); // 一次讀取一行

13.   while (strReadLine != null) // 判斷是否有抓到資料

14.   {

15.    System.out.println(strReadLine);

16.    strReadLine = buf_fr1.readLine();

17.   }

18.   buf_fr1.close(); //只要關閉Buffer物件即可,因為其他與之相關聯的資源也會一起被關閉

19.   // 利用BufferedWriter將指定字串寫到SampleFile.txt

20.   int i = 0;

21.   String[] strWriteLine = new String[2];

22.   strWriteLine[0] = "Howard Tuan";

23.   strWriteLine[1] = "Baby Tuan";

24.   FileWriter fw = new FileWriter("SampleFile.txt", true);

25.   BufferedWriter buf_fw = new BufferedWriter(fw);

26.   for(i=0;i

27.   {

28.    buf_fw.write(strWriteLine[i], 0, strWriteLine[i].length());

29.    buf_fw.newLine();

30.   }

31.   buf_fw.close();

32.   // 再利用BufferedReader讀取修改過後SampleFile.txt的資料

33.   FileReader fr2 = new FileReader("SampleFile.txt");

34.   BufferedReader buf_fr2 = new BufferedReader(fr2);

35.   System.out.println("\n再利用BufferedReader讀取修改過後的資料如下 ");

36.   System.out.println("----------------------------------");

37.   strReadLine = buf_fr2.readLine(); // 一次讀取一行

38.   while (strReadLine != null) // 判斷是否有抓到資料

39.   {

40.    System.out.println(strReadLine);

41.    strReadLine = buf_fr2.readLine();

42.   }

43.   buf_fr2.close();

44.  }

45. }

執行結果:

利用BufferedReader讀取SampleFile.txt的原始資料如下
----------------------------------


4. RandomAccessFile

RandomAccessFile是唯一可以同時讀取(r)與寫入(rw)資料的類別,並且可利用指標(這裡所說的指標是檔案指標file pointer)來指定所要讀取或寫入的位置,若開啟的檔案不存在,則系統會自動建立一個新檔,其檔案指標會指向0的位置(預設為0)。

‧RandomAccessFile建構子
BufferedWriter建構子
說明
RandomAccessFile(File file, String mode) 根據所指定的file物件來建立一個RandomAccessFile物件,並設定其存取模式,若mode = r表示可讀不可寫(唯讀),mode = rw則表示可讀可寫。
RandomAccessFile(String name, String mode) 根據所指定的檔案名稱name來建立一個RandomAccessFile物件,並設定其存取模式。

RandomAccessFile常用方法
RandomAccessFile實作了DataInput與DataOutput,擁有檔案的資料讀取與寫入功能,因此必須實作這二個介面類別中所有的方法。以下便介紹RandomAccessFile的檔案指標存取方法。
方法名稱
傳回值
說明
getFilePointer() long 讀取目前的檔案指標(也就是目前在檔案中的位置)
seek(long pos)

void

將檔案指標指向指定位置(pos),後續的讀取或寫入的動作將從這個位置開始。

RandomAccessFile範例程式
範例Part I簡單利用了RandomAccessFile類別中所提供的write()方法將資料寫到檔案中,再以readLine()方法逐行讀出資料。請注意程式中二個RandomAccessFile()類別建構子的參數設定。
RandomAccessFile範例程式 – Part I

1.           import java.io.*;

2.           public class Ex_RandomAccessFile

3.           {

4.            public static void main(String[] args) throws Exception

5.            {

6.             String s;

7.             s = "Java SCJP\nJDK 1.3.1";

8.             byte[] newData = s.getBytes();

9.            RandomAccessFile rf1 = new RandomAccessFile("SampleFile.txt", "rw");

10.         System.out.println("利用RandomAccessFile將資料寫到檔案!");

11.         System.out.println("將字串\"" + s + "\"寫到檔案\n資料長度:" +

12.         s.length() + " bytes.");

13.         rf1.write(newData);

14.         rf1.close();

15.        RandomAccessFile rf2 = new RandomAccessFile("SampleFile.txt", "r");

16.         System.out.println("\n利用RandomAccessFile讀取到的" +

17.         "SampleFile.txt檔案內容如下");

18.         System.out.println("----------------------------------");

19.         while ((s = rf2.readLine()) != null )

20.         System.out.println(s);

21.         rf2.close();

22.        }

23.       }

執行結果:

利用RandomAccessFile將資料寫到檔案!

將字串"Java SCJP

JDK 1.3.1"寫到檔案

資料長度:19 bytes.

 

利用RandomAccessFile讀取到的SampleFile.txt檔案內容如下

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

Java SCJP

JDK 1.3.1


程式第9行宣告RandomAccessFile類別的存取模式是rw(可讀寫),第15行只用到r(意即唯讀),因後續動作只是讀取與顯示資料,不需寫入資料,所以只要有唯讀的權限就夠了。
範例Part II則利用檔案指標(file pointer)所指定的位置來作讀取和寫入資料。
RandomAccessFile範例程式 – Part II

1.           import java.io.*;

2.           public class Ex_RandomAccessFile2

3.           {

4.            public static void main(String[] args) throws Exception

5.            {

6.             String s;

7.            RandomAccessFile rf = new RandomAccessFile("Buffer.txt", "rw");

8.             // RandomAccessFile物件建立之初時的指標位置

9.            System.out.println("利用getFilePointer()方法傳回目前的檔案指標位置:" + 
                          rf.getFilePointer());

10.         // -- Insert Data

11.        rf.writeUTF("My name is ");

12.        long fpointer = rf.getFilePointer();

13.         System.out.println("加入UTF字串(\"My name is \")後的檔案指標位置:" + fpointer);

14.        rf.writeUTF("Vincent");

15.         System.out.println("加入UTF字串(\"Vincent\")後的檔案指標位置:" +
                        rf.getFilePointer());

16.        rf.seek(0);

17.         System.out.println("將所加入的2UTF字串資料秀出:" + rf.readUTF() +
                        rf.readUTF());

18.         // -- Modify Data

19.         rf.seek(fpointer);

20.         System.out.println("\n將指標指向" + fpointer + "並加入UTF字串(\"Anita\")");

21.         rf.writeUTF("Anita");

22.         rf.seek(0);

23.         System.out.println("最後將變更後的UTF字串資料秀出:" + rf.readUTF() +
                        rf.readUTF());

24.         rf.close();

25.        }

26.       }

執行結果:

利用getFilePointer()方法傳回目前的檔案指標位置:0

加入UTF字串("My name is ")後的檔案指標位置:13

加入UTF字串("Vincent")後的檔案指標位置:22

將所加入的2UTF字串資料秀出:My name is Vincent

將指標指向13並加入UTF字串("Anita")

最後將變更後的UTF字串資料秀出:My name is Anita



程式第7行所宣告RandomAccessFile類別的存取模式是rw(可讀寫),第9行利用getFilePointer()方法取得目前在檔案中的位置。
由於RandomAccessFile物件是初始建立,因此傳回檔案指標值為0(file pointer=0)。第11行利用writeUFT()方法將”My name is ”以Unicode編碼方式寫入檔案。第12行再利用getFilePointer()方法取得目前在檔案中的位置,此時的檔案指標是在寫入字串之後(亦即程式第11行執行完畢後)的位置(file pointer=13),所取得的檔案指標位置將指派給fpointer變數。第14行利用writeUFT()方法將”Vincent ”以Unicode編碼方式寫入檔案。第15行即利用getFilePointer()方法取得目前在檔案中的位置,並顯示在螢幕上。

第17行將所輸入的Unicode字串顯示在螢幕上,由於檔案指標位置已指向檔尾,必須先將指標移向檔頭(seek(0))後才能利用readUFT()方法將Unicode字串印出,否則會出現Exception(因指標指向檔尾,指標後已無任何資料可供readUTF()方法讀取)。
請注意,第17行呼叫了兩次readUFT()方法,是因為在程式第11與第14行各使用了writeUFT()方法一次,一個writeUTF()會依序對應一個readUTF(),因此第17行才呼叫兩次readUFT()方法。

第19行我們再用seek()方法將檔案指標內容值指向先前的fpointer變數(file pointer=13)。第25行利用writeUFT()方法將 “Anita ”以Unicode編碼方式寫入檔案,從檔案指標13開始,在檔案指標之後的資料將會被新加入的Unicode字串所覆蓋。第23行在螢幕上顯示變更後的Unicode字串。
圖解RandomAccessFile程式範例Part II:
程式第11行:


程式第19~23行:
將Unicode字串 “Anita”從檔案指標第13的位置插入,並覆蓋指標後的字串資料。


程式第23行:
變更後的UTF字串資料


5. 資料編碼轉換- InputStreamReader與OutputStreamWriter

作業系統會根據不同的編碼方式來儲存字元,有些編碼方式以1個位元組(1 bytes)表示字元(1 char)資料,有些則以2個位元組(2 bytes)來表示。Java本身字元集的編碼方式為Unicode ,並且提供了不同類型的字元集以因應各種作業系統的編碼方式。

資料編碼轉換常應用於透過網路存取資料,資料的來源端與目的端可能是不同的機器,資料的編碼方式也不一樣。例如:在Window系統中所使用的字元集是ISO 8859-1(ANSI),而在Macintosh中所使用的字元集則是Macintosh Latin-2,因此輸入資料時就必須利用InputStreamReader作資料編碼的轉換(decode),以便後續程式運作。

InputStreamReader是將byte streams的資料轉換為character streams的橋樑,可利用指定的字元集將byte解碼(decode)至character中讀取。InputStreamReader建構子為InputStreamReader(InputStream in, String charsetName),其中in是資料來源端InputStream物件,charsetName是字元集名稱(charset name)。

OutputStreamWriter是將character streams的資料轉換為byte streams的橋樑,可利用指定的字元集並利用write()方法將character編碼(encoded)到bytes中。OutputStreamWrite建構子為OutputStreamWriter(OutputStream out, String charsetName),其中out是資料輸出端OutputStream物件,charsetName為字元集名稱(charset name)。

OutputStreamWrite程式範例
OutputStreamWrite資料輸出編碼(encoded)程式範例

1. … // Block of code

2. …

3. FileOutputStream fo = new FileOutputStream (“sample.txt”);

4. OutputStreamWriter OutWriter = new OutputStreamWriter (fo, “ISO2022CN”);

5. …

6. … // Block of code


程式第4行利用 “ISO2022CN”為output的資料進行編碼( “ISO2022CN”是描述中文的字元集)。

getEncoding()方法
方法名稱
傳回值
說明
getFilePointer() long 讀取目前的檔案指標(也就是目前在檔案中的位置)
seek(long pos)

void

將檔案指標指向指定位置(pos),後續的讀取或寫入的動作將從這個位置開始。

阅读(3910) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~