?? 0116.htm
字號(hào):
<html>
<head>
<title>新時(shí)代軟件教程:操作系統(tǒng) 主頁(yè)制作 服務(wù)器 設(shè)計(jì)軟件 網(wǎng)絡(luò)技術(shù) 編程語(yǔ)言 文字編輯</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<style>
<!--
body, table {font-size: 9pt; font-family: 宋體}
a {text-decoration:none}
a:hover {color: red;text-decoration:underline}
.1 {background-color: rgb(245,245,245)}
-->
</style>
</head>
<p align="center"><script src="../../1.js"></script></a>
<p align="center"><big><strong>第10章 Java IO系統(tǒng)</strong></big></p>
<div align="right">---(原著/Bruce Eckel 翻譯/Trans Bot)</div>
<br>
“對(duì)語(yǔ)言設(shè)計(jì)人員來(lái)說(shuō),創(chuàng)建好的輸入/輸出系統(tǒng)是一項(xiàng)特別困難的任務(wù)。”<br>
<br>
由于存在大量不同的設(shè)計(jì)方案,所以該任務(wù)的困難性是很容易證明的。其中最大的挑戰(zhàn)似乎是如何覆蓋所有可能的因素。不僅有三種不同的種類的IO需要考慮(文件、控制臺(tái)、網(wǎng)絡(luò)連接),而且需要通過(guò)大量不同的方式與它們通信(順序、隨機(jī)訪問(wèn)、二進(jìn)制、字符、按行、按字等等)。<br>
Java庫(kù)的設(shè)計(jì)者通過(guò)創(chuàng)建大量類來(lái)攻克這個(gè)難題。事實(shí)上,Java的IO系統(tǒng)采用了如此多的類,以致剛開始會(huì)產(chǎn)生不知從何處入手的感覺(具有諷刺意味的是,Java的IO設(shè)計(jì)初衷實(shí)際要求避免過(guò)多的類)。從Java
1.0升級(jí)到Java 1.1后,IO庫(kù)的設(shè)計(jì)也發(fā)生了顯著的變化。此時(shí)并非簡(jiǎn)單地用新庫(kù)替換舊庫(kù),Sun的設(shè)計(jì)人員對(duì)原來(lái)的庫(kù)進(jìn)行了大手筆的擴(kuò)展,添加了大量新的內(nèi)容。因此,我們有時(shí)不得不混合使用新庫(kù)與舊庫(kù),產(chǎn)生令人無(wú)奈的復(fù)雜代碼。<br>
本章將幫助大家理解標(biāo)準(zhǔn)Java庫(kù)內(nèi)的各種IO類,并學(xué)習(xí)如何使用它們。本章的第一部分將介紹“舊”的Java
1.0 IO流庫(kù),因?yàn)楝F(xiàn)在有大量代碼仍在使用那個(gè)庫(kù)。本章剩下的部分將為大家引入Java
1.1 IO庫(kù)的一些新特性。注意若用Java 1.1編譯器來(lái)編譯本章第一部分介紹的部分代碼,可能會(huì)得到一條“不建議使用該特性”(Deprecated
feature)警告消息。代碼仍然能夠使用;編譯器只是建議我們換用本章后面要講述的一些新特性。但我們這樣做是有價(jià)值的,因?yàn)榭梢愿宄卣J(rèn)識(shí)老方法與新方法之間的一些差異,從而加深我們的理解(并可順利閱讀為Java
1.0寫的代碼)。<br>
<br>
10.1 輸入和輸出<br>
可將Java庫(kù)的IO類分割為輸入與輸出兩個(gè)部分,這一點(diǎn)在用Web瀏覽器閱讀聯(lián)機(jī)Java類文檔時(shí)便可知道。通過(guò)繼承,從InputStream(輸入流)衍生的所有類都擁有名為read()的基本方法,用于讀取單個(gè)字節(jié)或者字節(jié)數(shù)組。類似地,從OutputStream衍生的所有類都擁有基本方法write(),用于寫入單個(gè)字節(jié)或者字節(jié)數(shù)組。然而,我們通常不會(huì)用到這些方法;它們之所以存在,是因?yàn)楦鼜?fù)雜的類可以利用它們,以便提供一個(gè)更有用的接口。因此,我們很少用單個(gè)類創(chuàng)建自己的系統(tǒng)對(duì)象。一般情況下,我們都是將多個(gè)對(duì)象重疊在一起,提供自己期望的功能。我們之所以感到Java的流庫(kù)(Stream
Library)異常復(fù)雜,正是由于為了創(chuàng)建單獨(dú)一個(gè)結(jié)果流,卻需要?jiǎng)?chuàng)建多個(gè)對(duì)象的緣故。<br>
很有必要按照功能對(duì)類進(jìn)行分類。庫(kù)的設(shè)計(jì)者首先決定與輸入有關(guān)的所有類都從InputStream繼承,而與輸出有關(guān)的所有類都從OutputStream繼承。<br>
<br>
10.1.1 InputStream的類型<br>
InputStream的作用是標(biāo)志那些從不同起源地產(chǎn)生輸入的類。這些起源地包括(每個(gè)都有一個(gè)相關(guān)的InputStream子類):<br>
(1) 字節(jié)數(shù)組<br>
(2) String對(duì)象<br>
(3) 文件<br>
(4)
“管道”,它的工作原理與現(xiàn)實(shí)生活中的管道類似:將一些東西置入一端,它們?cè)诹硪欢顺鰜?lái)。
(5) 一系列其他流,以便我們將其統(tǒng)一收集到單獨(dú)一個(gè)流內(nèi)。<br>
(6) 其他起源地,如Internet連接等(將在本書后面的部分講述)。<br>
<br>
除此以外,F(xiàn)ilterInputStream也屬于InputStream的一種類型,用它可為“破壞器”類提供一個(gè)基礎(chǔ)類,以便將屬性或者有用的接口同輸入流連接到一起。這將在以后討論。<br>
<br>
表10.1 InputStream的類型<br>
<br>
類 功能 構(gòu)建器參數(shù)/如何使用<br>
<br>
ByteArrayInputStream 允許內(nèi)存中的一個(gè)緩沖區(qū)作為InputStream使用
從中提取字節(jié)的緩沖區(qū)/作為一個(gè)數(shù)據(jù)源使用。通過(guò)將其同一個(gè)FilterInputStream對(duì)象連接,可提供一個(gè)有用的接口<br>
StringBufferInputStream 將一個(gè)String轉(zhuǎn)換成InputStream 一個(gè)String(字串)。基礎(chǔ)的實(shí)施方案實(shí)際采用一個(gè)StringBuffer(字串緩沖)/作為一個(gè)數(shù)據(jù)源使用。通過(guò)將其同一個(gè)FilterInputStream對(duì)象連接,可提供一個(gè)有用的接口<br>
FileInputStream 用于從文件讀取信息 代表文件名的一個(gè)String,或者一個(gè)File或FileDescriptor對(duì)象/作為一個(gè)數(shù)據(jù)源使用。通過(guò)將其同一個(gè)FilterInputStream對(duì)象連接,可提供一個(gè)有用的接口<br>
PipedInputString 產(chǎn)生為相關(guān)的PipedOutputStream寫的數(shù)據(jù)。實(shí)現(xiàn)了“管道化”的概念
PipedOutputStream/作為一個(gè)數(shù)據(jù)源使用。通過(guò)將其同一個(gè)FilterInputStream對(duì)象連接,可提供一個(gè)有用的接口<br>
SequenceInputStream 將兩個(gè)或更多的InputStream對(duì)象轉(zhuǎn)換成單個(gè)InputStream使用
兩個(gè)InputStream對(duì)象或者一個(gè)Enumeration,用于InputStream對(duì)象的一個(gè)容器/作為一個(gè)數(shù)據(jù)源使用。通過(guò)將其同一個(gè)FilterInputStream對(duì)象連接,可提供一個(gè)有用的接口<br>
FilterInputStream
對(duì)作為破壞器接口使用的類進(jìn)行抽象;那個(gè)破壞器為其他InputStream類提供了有用的功能。參見表10.3
參見表10.3/參見表10.3<br>
<br>
10.1.2 OutputStream的類型<br>
這一類別包括的類決定了我們的輸入往何處去:一個(gè)字節(jié)數(shù)組(但沒有String;假定我們可用字節(jié)數(shù)組創(chuàng)建一個(gè));一個(gè)文件;或者一個(gè)“管道”。<br>
除此以外,F(xiàn)ilterOutputStream為“破壞器”類提供了一個(gè)基礎(chǔ)類,它將屬性或者有用的接口同輸出流連接起來(lái)。這將在以后討論。<br>
<br>
表10.2 OutputStream的類型<br>
<br>
類 功能 構(gòu)建器參數(shù)/如何使用<br>
<br>
ByteArrayOutputStream
在內(nèi)存中創(chuàng)建一個(gè)緩沖區(qū)。我們發(fā)送給流的所有數(shù)據(jù)都會(huì)置入這個(gè)緩沖區(qū)。
可選緩沖區(qū)的初始大小/用于指出數(shù)據(jù)的目的地。若將其同F(xiàn)ilterOutputStream對(duì)象連接到一起,可提供一個(gè)有用的接口<br>
FileOutputStream 將信息發(fā)給一個(gè)文件 用一個(gè)String代表文件名,或選用一個(gè)File或FileDescriptor對(duì)象/用于指出數(shù)據(jù)的目的地。若將其同F(xiàn)ilterOutputStream對(duì)象連接到一起,可提供一個(gè)有用的接口<br>
PipedOutputStream 我們寫給它的任何信息都會(huì)自動(dòng)成為相關(guān)的PipedInputStream的輸出。實(shí)現(xiàn)了“管道化”的概念
PipedInputStream/為多線程處理指出自己數(shù)據(jù)的目的地/將其同F(xiàn)ilterOutputStream對(duì)象連接到一起,便可提供一個(gè)有用的接口<br>
FilterOutputStream
對(duì)作為破壞器接口使用的類進(jìn)行抽象處理;那個(gè)破壞器為其他OutputStream類提供了有用的功能。參見表10.4
參見表10.4/參見表10.4<br>
<br>
10.2 增添屬性和有用的接口<br>
利用層次化對(duì)象動(dòng)態(tài)和透明地添加單個(gè)對(duì)象的能力的做法叫作“裝飾器”(Decorator)方案——“方案”屬于本書第16章的主題(注釋①)。裝飾器方案規(guī)定封裝于初始化對(duì)象中的所有對(duì)象都擁有相同的接口,以便利用裝飾器的“透明”性質(zhì)——我們將相同的消息發(fā)給一個(gè)對(duì)象,無(wú)論它是否已被“裝飾”。這正是在Java
IO庫(kù)里存在“過(guò)濾器”(Filter)類的原因:抽象的“過(guò)濾器”類是所有裝飾器的基礎(chǔ)類(裝飾器必須擁有與它裝飾的那個(gè)對(duì)象相同的接口,但裝飾器亦可對(duì)接口作出擴(kuò)展,這種情況見諸于幾個(gè)特殊的“過(guò)濾器”類中)。<br>
子類處理要求大量子類對(duì)每種可能的組合提供支持時(shí),便經(jīng)常會(huì)用到裝飾器——由于組合形式太多,造成子類處理變得不切實(shí)際。Java
IO庫(kù)要求許多不同的特性組合方案,這正是裝飾器方案顯得特別有用的原因。但是,裝飾器方案也有自己的一個(gè)缺點(diǎn)。在我們寫一個(gè)程序的時(shí)候,裝飾器為我們提供了大得多的靈活性(因?yàn)榭梢苑奖愕鼗旌吓c匹配屬性),但它們也使自己的代碼變得更加復(fù)雜。原因在于Java
IO庫(kù)操作不便,我們必須創(chuàng)建許多類——“核心”IO類型加上所有裝飾器——才能得到自己希望的單個(gè)IO對(duì)象。<br>
FilterInputStream和FilterOutputStream(這兩個(gè)名字不十分直觀)提供了相應(yīng)的裝飾器接口,用于控制一個(gè)特定的輸入流(InputStream)或者輸出流(OutputStream)。它們分別是從InputStream和OutputStream衍生出來(lái)的。此外,它們都屬于抽象類,在理論上為我們與一個(gè)流的不同通信手段都提供了一個(gè)通用的接口。事實(shí)上,F(xiàn)ilterInputStream和FilterOutputStream只是簡(jiǎn)單地模仿了自己的基礎(chǔ)類,它們是一個(gè)裝飾器的基本要求。<br>
<br>
10.2.1 通過(guò)FilterInputStream從InputStream里讀入數(shù)據(jù)<br>
FilterInputStream類要完成兩件全然不同的事情。其中,DataInputStream允許我們讀取不同的基本類型數(shù)據(jù)以及String對(duì)象(所有方法都以“read”開頭,比如readByte(),readFloat()等等)。伴隨對(duì)應(yīng)的DataOutputStream,我們可通過(guò)數(shù)據(jù)“流”將基本類型的數(shù)據(jù)從一個(gè)地方搬到另一個(gè)地方。這些“地方”是由表10.1總結(jié)的那些類決定的。若讀取塊內(nèi)的數(shù)據(jù),并自己進(jìn)行解析,就不需要用到DataInputStream。但在其他許多情況下,我們一般都想用它對(duì)自己讀入的數(shù)據(jù)進(jìn)行自動(dòng)格式化。<br>
剩下的類用于修改InputStream的內(nèi)部行為方式:是否進(jìn)行緩沖,是否跟蹤自己讀入的數(shù)據(jù)行,以及是否能夠推回一個(gè)字符等等。后兩種類看起來(lái)特別象提供對(duì)構(gòu)建一個(gè)編譯器的支持(換言之,添加它們?yōu)榱酥С諮ava編譯器的構(gòu)建),所以在常規(guī)編程中一般都用不著它們。<br>
也許幾乎每次都要緩沖自己的輸入,無(wú)論連接的是哪個(gè)IO設(shè)備。所以IO庫(kù)最明智的做法就是將未緩沖輸入作為一種特殊情況處理,同時(shí)將緩沖輸入接納為標(biāo)準(zhǔn)做法。<br>
<br>
表10.3 FilterInputStream的類型<br>
<br>
類 功能 構(gòu)建器參數(shù)/如何使用<br>
<br>
DataInputStream 與DataOutputStream聯(lián)合使用,使自己能以機(jī)動(dòng)方式讀取一個(gè)流中的基本數(shù)據(jù)類型(int,char,long等等)
InputStream/包含了一個(gè)完整的接口,以便讀取基本數(shù)據(jù)類型<br>
BufferedInputStream
避免每次想要更多數(shù)據(jù)時(shí)都進(jìn)行物理性的讀取,告訴它“請(qǐng)先在緩沖區(qū)里找”
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -