Java語言的輸入輸出功能是十分強大而靈活的
美中不足的是看上去輸入輸出的代碼並不是很簡潔
因為你往往需要包裝許多不同的對象
在Java類庫中
IO部分的內容是很龐大的
因為它涉及的領域很廣泛
標准輸入輸出
文件的操作
網絡上的數據流
字符串流
對象流
zip文件流…本文的目的是為大家做一個簡要的介紹
流是一個很形象的概念
當程序需要讀取數據的時候
就會開啟一個通向數據源的流
這個數據源可以是文件
內存
或是網絡連接
類似的
當程序需要寫入數據的時候
就會開啟一個通向目的地的流
這時候你就可以想象數據好像在這其中
流
動一樣
Java中的流分為兩種
一種是字節流
另一種是字符流
分別由四個抽象類來表示(每種流包括輸入和輸出兩種所以一共四個)
InputStream
OutputStream
Reader
Writer
Java中其他多種多樣變化的流均是由它們派生出來的
在這其中InputStream和OutputStream在早期的Java版本中就已經存在了
它們是基於字節流的
而基於字符流的Reader和Writer是後來加入作為補充的
以上的層次圖是Java類庫中的一個基本的層次體系
在這四個抽象類中
InputStream和Reader定義了完全相同的接口
int read()
int read(char cbuf[])
int read(char cbuf[]
int offset
int length)
而OutputStream和Writer也是如此
int write(int c)
int write(char cbuf[])
int write(char cbuf[]
int offset
int length)
這六個方法都是最基本的
read()和write()通過方法的重載來讀寫一個字節
或者一個字節數組
更多靈活多變的功能是由它們的子類來擴充完成的
知道了Java輸入輸出的基本層次結構以後
本文在這裡想給大家一些以後可以反復應用例子
對於所有子類的細節及其功能並不詳細討論
import java
io
*;
public class IOStreamDemo {
public void samples() throws IOException {
//
這是從鍵盤讀入一行數據
返回的是一個字符串
BufferedReader stdin =new BufferedReader(new InputStreamReader(System
in))
System
out
print(
Enter a line:
)
System
out
println(stdin
readLine())
//
這是從文件中逐行讀入數據
BufferedReader in = new BufferedReader(new FileReader(
IOStreamDemo
java
))
String s
s
= new String()
while((s = in
readLine())!= null)
s
+= s +
\n
;
in
close()
//
這是從一個字符串中逐個讀入字節
StringReader in
= new StringReader(s
)
int c;
while((c = in
read()) !=
)
System
out
print((char)c)
//
這是將一個字符串寫入文件
try {
BufferedReader in
= new BufferedReader(new StringReader(s
))
PrintWriter out
= new PrintWriter(new BufferedWriter(new FileWriter(
IODemo
out
)))
int lineCount =
;
while((s = in
readLine()) != null )
out
println(lineCount++ +
:
+ s)
out
close()
} catch(EOFException e) {
System
err
println(
End of stream
)
}
}
}
對於上面的例子
需要說明的有以下幾點
BufferedReader是Reader的一個子類
它具有緩沖的作用
避免了頻繁的從物理設備中讀取信息
它有以下兩個構造函數
BufferedReader(Reader in) BufferedReader(Reader in
int sz)
這裡的sz是指定緩沖區的大小
它的基本方法
void close() //關閉流 void mark(int readAheadLimit) //標記當前位置 boolean markSupported() //是否支持標記 int read() //繼承自Reader的基本方法 int read(char[] cbuf
int off
int len) //繼承自Reader的基本方法 String readLine() //讀取一行內容並以字符串形式返回 boolean ready() //判斷流是否已經做好讀入的准備 void reset() //重設到最近的一個標記 long skip(long n) //跳過指定個數的字符讀取
InputStreamReader是InputStream和Reader之間的橋梁
由於System
in是字節流
需要用它來包裝之後變為字符流供給 BufferedReader使用
PrintWriter out
= new PrintWriter(new BufferedWriter(new FileWriter(
IODemo
out
)))
這句話體現了Java輸入輸出系統的一個特點
為了達到某個目的
需要包裝好幾層
首先
輸出目的地是文件IODemo
out
所以最內層包裝的是FileWriter
建立一個輸出文件流
接下來
我們希望這個流是緩沖的
所以用BufferedWriter來包裝它以達到目的
最後
我們需要格式化輸出結果
於是將PrintWriter包在最外層
Java提供了這樣一個功能
將標准的輸入輸出流轉向
也就是說
我們可以將某個其他的流設為標准輸入或輸出流
看下面這個例子
import java
io
*;
public class Redirecting {
public static void main(String[] args) throws IOException {
PrintStream console = System
out;
BufferedInputStream in = new BufferedInputStream( new FileInputStream(
Redirecting
java
))
PrintStream out = new PrintStream( new BufferedOutputStream( new FileOutputStream(
test
out
)))
System
setIn(in)
System
setOut(out)
BufferedReader br = new BufferedReader( new InputStreamReader(System
in))
String s;
while((s = br
readLine()) != null)
System
out
println(s)
out
close()
System
setOut(console)
}
}
在這裡java
lang
System的靜態方法
static void setIn(InputStream in) static void setOut(PrintStream out)
提供了重新定義標准輸入輸出流的方法
這樣做是很方便的
比如一個程序的結果有很多
有時候甚至要翻頁顯示
這樣不便於觀看結果
這是你就可以將標准輸出流定義為一個文件流
程序運行完之後打開相應的文件觀看結果
就直觀了許多
Java流有著另一個重要的用途
那就是利用對象流對對象進行序列化
下面將開始介紹這方面的問題
在一個程序運行的時候
其中的變量數據是保存在內存中的
一旦程序結束這些數據將不會被保存
一種解決的辦法是將數據寫入文件
而Java中提供了一種機制
它可以將程序中的對象寫入文件
之後再從文件中把對象讀出來重新建立
這就是所謂的對象序列化Java中引入它主要是為了RMI(Remote Method Invocation)和Java Bean所用
不過在平時應用中
它也是很有用的一種技術
所有需要實現對象序列化的對象必須首先實現Serializable接口
下面看一個例子
import java
io
*;
import java
util
*;
public class Logon implements Serializable {
private Date date = new Date()
private String username;
private transient String password;
Logon(String name
String pwd) {
username = name;
password = pwd;
}
public String toString() {
String pwd = (password == null) ?
(n/a)
: password;
return
logon info: \n
+
username:
+ username +
\n date:
+ date +
\n password:
+ pwd;
}
public static void main(String[] args) throws IOException
ClassNotFoundException {
Logon a = new Logon(
Morgan
morgan
)
System
out
println(
logon a =
+ a)
ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream(
Logon
out
))
o
writeObject(a)
o
close()
int seconds =
;
long t = System
currentTimeMillis() + seconds *
;
while(System
currentTimeMillis() < t) ;
ObjectInputStream in = new ObjectInputStream( new FileInputStream(
Logon
out
))
System
out
println(
Recovering object at
+ new Date())
a = (Logon)in
readObject()
System
out
println(
logon a =
+ a)
}
}
類Logon是一個記錄登錄信息的類
包括用戶名和密碼
首先它實現了接口Serializable
這就標志著它可以被序列化
之後再main方法裡ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream(
Logon
out
))
新建一個對象輸出流包裝一個文件流
表示對象序列化的目的地是文件Logon
out
然後用方法writeObject開始寫入
想要還原的時候也很簡單ObjectInputStream in = new ObjectInputStream( new FileInputStream(
Logon
out
))
新建一個對象輸入流以文件流Logon
out為參數
之後調用readObject方法就可以了
需要說明一點
對象序列化有一個神奇之處就是
它建立了一張對象網
將當前要序列化的對象中所持有的引用指向的對象都包含起來一起寫入到文件
更為奇妙的是
如果你一次序列化了好幾個對象
它們中相同的內容將會被共享寫入
這的確是一個非常好的機制
它可以用來實現深層拷貝
關鍵字transient在這裡表示當前內容將不被序列化
比如例子中的密碼
需要保密
所以沒有被寫入文件
對Java的輸入輸出功能
就淺淺的介紹到這裡
本文的目的只是開一個好頭
希望能讓大家對Java輸入輸出流有個基本的認識
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26457.html