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