IO流(重點理解)
用於處理設備上數據。
流:能夠理解數據的流動,就是一個數據流。IO流最終要以對象來體現,對象都存在IO包中。
流也進行分類:
1:輸入流(讀)和輸出流(寫)。
2:由於處理的數據不一樣,分爲字節流和字符流。java
字節流:處理字節數據的流對象。設備上的數據不管是圖片或者dvd,文字,它們都以二進制存儲的。二進制的最終都是以一個8位爲數據單元進行體現,因此計算機中的最小數據單元就是字節。意味着,字節流能夠處理設備上的全部數據,因此字節流同樣能夠處理字符數據。linux
那麼爲何要有字符流呢?由於字符每一個國家都不同,因此涉及到了字符編碼問題,那麼GBK編碼的中文用unicode編碼解析是有問題的,因此須要獲取中文字節數據的同時+ 指定的編碼表才能夠解析正確數據。爲了方便於文字的解析,因此將字節流和編碼表封裝成對象,這個對象就是字符流。只要操做字符數據,優先考慮使用字符流體系。windows
注意:流的操做只有兩種:讀和寫。設計模式
流的體系由於功能不一樣,可是有共性內容,不斷抽取,造成繼承體系。該體系一共有四個基類,並且都是抽象類。數組
字節流:InputStream OutputStream
字符流:Reader Writer多線程
public static void main(String[] args) throws IOException { //讀、寫都會發生IO異常
/*
1:建立一個字符輸出流對象,用於操做文件。該對象一創建,就必須明確數據存儲位置,是一個文件。
2:對象產生後,會在堆內存中有一個實體,同時也調用了系統底層資源,在指定的位置建立了一個存儲數據的文件。
3:若是指定位置,出現了同名文件,文件會被覆蓋。
*/
FileWriter fw = new FileWriter("demo.txt"); // FileNotFoundException
/*
調用Writer類中的write方法寫入字符串。字符串並未直接寫入到目的地中,而是寫入到了流中,(實際上是寫入到內存緩衝區中)。怎麼把數據弄到文件中?
*/
fw.write("abcde");
fw.flush(); // 刷新緩衝區,將緩衝區中的數據刷到目的地文件中。
fw.close(); // 關閉流,其實關閉的就是java調用的系統底層資源。在關閉前,會先刷新該流。
}dom
close()和flush()的區別:
flush():將緩衝區的數據刷到目的地中後,流可使用。jvm
io異常的處理方式:io必定要寫finally;函數
FileWriter寫入數據的細節:
1:window中的換行符:rn兩個符號組成。 linux:n。
2:續寫數據,只要在構造函數中傳入新的參數true。
3:目錄分割符:window \ /測試
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt",true);
fw.write("abcde");
}
catch (IOException e ){
System.out.println(e.toString()+"....");
}
finally{
if(fw!=null)
try{
fw.close();
}
catch (IOException e){
System.out.println("close:"+e.toString());
}
}
FileReader:使用Reader體系,讀取一個文本文件中的數據。返回 -1 ,標誌讀到結尾。
import java.io.*;
class FileReaderDemo {
public static void main(String[] args) throws IOException {
/*
建立能夠讀取文本文件的流對象,FileReader讓建立好的流對象和指定的文件相關聯。
*/
FileReader fr = new FileReader("demo.txt");
int ch = 0;
while((ch = fr.read())!= -1) { //條件是沒有讀到結尾
System.out.println((char)ch); //調用讀取流的read方法,讀取一個字符。
}
fr.close();
}
讀取數據的第二種方式:第二種方式較爲高效,自定義緩衝區。
import java.io.*;
class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt"); //建立讀取流對象和指定文件關聯。
//由於要使用read(char[])方法,將讀取到字符存入數組。因此要建立一個字符數組,通常數組的長度都是1024的整數倍。
char[] buf = new char[1024];
int len = 0;
while(( len=fr.read(buf)) != -1) {
System.out.println(new String(buf,0,len));
}
fr.close();
}
IO中的使用到了一個設計模式:裝飾設計模式。
裝飾設計模式解決:對一組類進行功能的加強。
包裝:寫一個類(包裝類)對被包裝對象進行包裝;
字符流:
Reader:用於讀取字符流的抽象類。子類必須實現的方法只有 read(char[], int, int) 和 close()。
|---BufferedReader:從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。 能夠指定緩衝區的大小,或者可以使用默認的大小。大多數狀況下,默認值就足夠大了。 |---LineNumberReader:跟蹤行號的緩衝字符輸入流。此類定義了方法 setLineNumber(int) 和 getLineNumber(),它們可分別用於設置和獲取當前行號。 |---InputStreamReader:是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。它使用的字符集能夠由名稱指定或顯式給定,或者能夠接受平臺默認的字符集。 |---FileReader:用來讀取字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩衝區大小都是適當的。要本身指定這些值,能夠先在 FileInputStream 上構造一個 InputStreamReader。 |---CharArrayReader: |---StringReader:
Writer:寫入字符流的抽象類。子類必須實現的方法僅有 write(char[], int, int)、flush() 和 close()。
|---BufferedWriter:將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。 |---OutputStreamWriter:是字符流通向字節流的橋樑:可以使用指定的 charset 將要寫入流中的字符編碼成字節。它使用的字符集能夠由名稱指定或顯式給定,不然將接受平臺默認的字符集。 |---FileWriter:用來寫入字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩衝區大小都是可接受的。要本身指定這些值,能夠先在 FileOutputStream 上構造一個 OutputStreamWriter。 |---PrintWriter: |---CharArrayWriter: |---StringWriter:
字節流:
InputStream:是表示字節輸入流的全部類的超類。
|--- FileInputStream:從文件系統中的某個文件中得到輸入字節。哪些文件可用取決於主機環境。FileInputStream 用於讀取諸如圖像數據之類的原始字節流。要讀取字符流,請考慮使用 FileReader。 |--- FilterInputStream:包含其餘一些輸入流,它將這些流用做其基本數據源,它能夠直接傳輸數據或提供一些額外的功能。 |--- BufferedInputStream:該類實現緩衝的輸入流。 |--- Stream: |--- ObjectInputStream: |--- PipedInputStream:
OutputStream:此抽象類是表示輸出字節流的全部類的超類。
|--- FileOutputStream:文件輸出流是用於將數據寫入 File 或 FileDescriptor 的輸出流。 |--- FilterOutputStream:此類是過濾輸出流的全部類的超類。 |--- BufferedOutputStream:該類實現緩衝的輸出流。 |--- PrintStream: |--- DataOutputStream: |--- ObjectOutputStream: |--- PipedOutputStream:
緩衝區是提升效率用的,給誰提升呢?
BufferedWriter:是給字符輸出流提升效率用的,那就意味着,緩衝區對象創建時,必需要先有流對象。明確要提升具體的流對象的效率。
FileWriter fw = new FileWriter("bufdemo.txt");
BufferedWriter bufw = new BufferedWriter(fw);//讓緩衝區和指定流相關聯。
for(int x=0; x<4; x++){
bufw.write(x+"abc");
bufw.newLine(); //寫入一個換行符,這個換行符能夠依據平臺的不一樣寫入不一樣的換行符。
bufw.flush();//對緩衝區進行刷新,可讓數據到目的地中。
}
BufferedReader:
FileReader fr = new FileReader("bufdemo.txt");
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line=bufr.readLine())!=null){ //readLine方法返回的時候是不帶換行符的。
System.out.println(line);
}
//記住,只要一讀取鍵盤錄入,就用這句話。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));//輸出到控制檯
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());//將輸入的字符轉成大寫字符輸出
bufw.newLine();
bufw.flush();
}
bufw.close();
流對象:其實很簡單,就是讀取和寫入。可是由於功能的不一樣,流的體系中提供N多的對象。那麼開始時,到底該用哪一個對象更爲合適呢?這就須要明確流的操做規律。
流的操做規律:
1,明確源和目的。
數據源:就是須要讀取,可使用兩個體系:InputStream、Reader;
數據匯:就是須要寫入,可使用兩個體系:OutputStream、Writer;
2,操做的數據是不是純文本數據?
若是是:數據源:Reader
數據匯:Writer
若是不是:數據源:InputStream
數據匯:OutputStream
3,雖然肯定了一個體系,可是該體系中有太多的對象,到底用哪一個呢?
明確操做的數據設備。
數據源對應的設備:硬盤(File),內存(數組),鍵盤(System.in)
數據匯對應的設備:硬盤(File),內存(數組),控制檯(System.out)。
4,須要在基本操做上附加其餘功能嗎?好比緩衝。
若是須要就進行裝飾。
轉換流特有功能:轉換流能夠將字節轉成字符,緣由在於,將獲取到的字節經過查編碼表獲取到指定對應字符。
轉換流的最強功能就是基於 字節流 + 編碼表 。沒有轉換,沒有字符流。
發現轉換流有一個子類就是操做文件的字符流對象:
InputStreamReader
|--FileReader
OutputStreamWriter
|--FileWrier
想要操做文本文件,必需要進行編碼轉換,而編碼轉換動做轉換流都完成了。因此操做文件的流對象只要繼承自轉換流就能夠讀取一個字符了。
可是子類有一個侷限性,就是子類中使用的編碼是固定的,是本機默認的編碼表,對於簡體中文版的系統默認碼錶是GBK。
FileReader fr = new FileReader("a.txt");
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"gbk");
以上兩句代碼功能一致,
若是僅僅使用平臺默認碼錶,就使用FileReader fr = new FileReader("a.txt"); //由於簡化。
若是須要制定碼錶,必須用轉換流。
轉換流 = 字節流+編碼表。
轉換流的子類File = 字節流 + 默認編碼表。
File類:將文件系統中的文件和文件夾封裝成了對象。提供了更多的屬性和行爲能夠對這些文件和文件夾進行操做。這些是流對象辦不到的,由於流只操做數據。
File類常見方法:
1:建立。
boolean createNewFile():在指定目錄下建立文件,若是該文件已存在,則不建立。而對操做文件的輸出流而言,輸出流對象已創建,就會建立文件,若是文件已存在,會覆蓋。除非續寫。
boolean mkdir():建立此抽象路徑名指定的目錄。
boolean mkdirs():建立多級目錄。
2:刪除。
boolean delete():刪除此抽象路徑名錶示的文件或目錄。
void deleteOnExit():在虛擬機退出時刪除。
注意:在刪除文件夾時,必須保證這個文件夾中沒有任何內容,才能夠將該文件夾用delete刪除。
window的刪除動做,是從裏往外刪。注意:java刪除文件不走回收站。要慎用。
3:獲取.
long length():獲取文件大小。
String getName():返回由此抽象路徑名錶示的文件或目錄的名稱。
String getPath():將此抽象路徑名轉換爲一個路徑名字符串。
String getAbsolutePath():返回此抽象路徑名的絕對路徑名字符串。
String getParent():返回此抽象路徑名父目錄的抽象路徑名,若是此路徑名沒有指定父目錄,則返回 null。
long lastModified():返回此抽象路徑名錶示的文件最後一次被修改的時間。
File.pathSeparator:返回當前系統默認的路徑分隔符,windows默認爲 「;」。
File.Separator:返回當前系統默認的目錄分隔符,windows默認爲 「」。
4:判斷:
boolean exists():判斷文件或者文件夾是否存在。
boolean isDirectory():測試此抽象路徑名錶示的文件是不是一個目錄。
boolean isFile():測試此抽象路徑名錶示的文件是不是一個標準文件。
boolean isHidden():測試此抽象路徑名指定的文件是不是一個隱藏文件。
boolean isAbsolute():測試此抽象路徑名是否爲絕對路徑名。
5:重命名。
boolean renameTo(File dest):能夠實現移動的效果。剪切+重命名。
String[] list():列出指定目錄下的當前的文件和文件夾的名稱。包含隱藏文件。
遞歸:就是函數自身調用自身。
何時用遞歸呢?
當一個功能被重複使用,而每一次使用該功能時的參數不肯定,都由上次的功能元素結果來肯定。
簡單說:功能內部又用到該功能,可是傳遞的參數值不肯定。(每次功能參與運算的未知內容不肯定)。
遞歸的注意事項:
1:必定要定義遞歸的條件。
2:遞歸的次數不要過多。容易出現 StackOverflowError 棧內存溢出錯誤。
Java.util.Properties:一個能夠將鍵值進行持久化存儲的對象。Map--Hashtable的子類。
Map
|--Hashtable
|--Properties:用於屬性配置文件,鍵和值都是字符串類型。
特色:1:能夠持久化存儲數據。2:鍵值都是字符串。3:通常用於配置文件。
|-- load():將流中的數據加載進集合。
原理:其實就是將讀取流和指定文件相關聯,並讀取一行數據,由於數據是規則的key=value,因此獲取一行後,經過 = 對該行數據進行切割,左邊就是鍵,右邊就是值,將鍵、值存儲到properties集合中。
|-- store():寫入各個項後,刷新輸出流。
如下介紹IO包中擴展功能的流對象:基本都是裝飾設計模式。
Java.io.outputstream.PrintStream:打印流
1:提供了更多的功能,好比打印方法。能夠直接打印任意類型的數據。
2:它有一個自動刷新機制,建立該對象,指定參數,對於指定方法能夠自動刷新。
3:它使用的本機默認的字符編碼.
4:該流的print方法不拋出IOException。
該對象的構造函數。
PrintStream(File file) :建立具備指定文件且不帶自動行刷新的新打印流。
PrintStream(File file, String csn) :建立具備指定文件名稱和字符集且不帶自動行刷新的新打印流。
PrintStream(OutputStream out) :建立新的打印流。
PrintStream(OutputStream out, boolean autoFlush) :建立新的打印流。
PrintStream(OutputStream out, boolean autoFlush, String encoding) :建立新的打印流。
PrintStream(String fileName) :建立具備指定文件名稱且不帶自動行刷新的新打印流。
PrintStream(String fileName, String csn)
PrintStream能夠操做目的:1:File對象。2:字符串路徑。3:字節輸出流。
前兩個都JDK1.5版本纔出現。並且在操做文本文件時,可指定字符編碼了。
當目的是一個字節輸出流時,若是使用的println方法,能夠在printStream對象上加入一個true參數。這樣對於println方法能夠進行自動的刷新,而不是等待緩衝區滿了再刷新。最終print方法都將具體的數據轉成字符串,並且都對IO異常進行了內部處理。
PrintWriter:具有了PrintStream的特色同時,還有自身特色:
該對象的目的地有四個:1:File對象。2:字符串路徑。3:字節輸出流。4:字符輸出流。
開發時儘可能使用PrintWriter。
方法中直接操做文件的第二參數是編碼表。
直接操做輸出流的,第二參數是自動刷新。
//讀取鍵盤錄入將數據轉成大寫顯示在控制檯.
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));//源:鍵盤輸入
//目的:把數據寫到文件中,還想自動刷新。
PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);//設置true後自動刷新
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
out.println(line.toUpperCase());//轉大寫輸出
}
//注意:System.in,System.out這兩個標準的輸入輸出流,在jvm啓動時已經存在了。隨時可使用。當jvm結束了,這兩個流就結束了。可是,當使用了顯示的close方法關閉時,這兩個流在提早結束了。
out.close();
SequenceInputStream:序列流,做用就是將多個讀取流合併成一個讀取流。實現數據合併。
表示其餘輸入流的邏輯串聯。它從輸入流的有序集合開始,並從第一個輸入流開始讀取,直到到達文件末尾,接着從第二個輸入流讀取,依次類推,直到到達包含的最後一個輸入流的文件末尾爲止。
這樣作,能夠更方便的操做多個讀取流,其實這個序列流內部會有一個有序的集合容器,用於存儲多個讀取流對象。
該對象的構造函數參數是枚舉,想要獲取枚舉,須要有Vector集合,但不高效。需用ArrayList,但ArrayList中沒有枚舉,只有本身去建立枚舉對象。
可是方法怎麼實現呢?由於枚舉操做的是具體集合中的元素,因此沒法具體實現,可是枚舉和迭代器是功能同樣的,因此,能夠用迭代替代枚舉。
合併原理:多個讀取流對應一個輸出流。
切割原理:一個讀取流對應多個輸出流。
import java.io.*;
import java.util.*;
class SplitFileDemo{
private static final String CFG = ".properties";
private static final String SP = ".part";
public static void main(String[] args) throws IOException{
File file = new File("c:\0.bmp");
File dir = new File("c:\partfiles");
meger(dir);
}
//數據的合併。
public static void meger(File dir)throws IOException{
if(!(dir.exists() && dir.isDirectory()))
throw new RuntimeException("指定的目錄不存在,或者不是正確的目錄");
File[] files = dir.listFiles(new SuffixFilter(CFG));
if(files.length==0)
throw new RuntimeException("擴展名.proerpties的文件不存在");
//獲取到配置文件
File config = files[0];
//獲取配置文件的信息。
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(config);
prop.load(fis);
String fileName = prop.getProperty("filename");
int partcount = Integer.parseInt(prop.getProperty("partcount"));
//--------------------------
File[] partFiles = dir.listFiles(new SuffixFilter(SP));
if(partFiles.length!=partcount)
throw new RuntimeException("缺乏碎片文件");
//---------------------
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=0; x<partcount; x++){
al.add(new FileInputStream(new File(dir,x+SP)));
}
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
File file = new File(dir,fileName);
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
//帶有配置信息的數據切割。
public static void splitFile(File file)throws IOException{
//用一個讀取流和文件關聯。
FileInputStream fis = new FileInputStream(file);
//建立目的地。由於有多個。因此先建立引用。
FileOutputStream fos = null;
//指定碎片的位置。
File dir = new File("c:\partfiles");
if(!dir.exists())
dir.mkdir();
//碎片文件大小引用。
File f = null;
byte[] buf = new byte[1024*1024];
//由於切割完的文件一般都有規律的。爲了簡單標記規律使用計數器。
int count = 0;
int len = 0;
while((len=fis.read(buf))!=-1){
f = new File(dir,(count++)+".part");
fos = new FileOutputStream(f);
fos.write(buf,0,len);
fos.close();
}
//碎片文件生成後,還須要定義配置文件記錄生成的碎片文件個數。以及被切割文件的名稱。
//定義簡單的鍵值信息,但是用Properties。
String filename = file.getName();
Properties prop = new Properties();
prop.setProperty("filename",filename);
prop.setProperty("partcount",count+"");
File config = new File(dir,count+".properties");
fos = new FileOutputStream(config);
prop.store(fos,"");
fos.close();
fis.close();
}
}
class SuffixFilter implements FileFilter{
private String suffix;
SuffixFilter(String suffix){
this.suffix = suffix;
}
public boolean accept(File file){
return file.getName().endsWith(suffix);
}
RandomAccessFile:
特色:
1:該對象便可讀取,又可寫入。
2:該對象中的定義了一個大型的byte數組,經過定義指針來操做這個數組。
3:能夠經過該對象的getFilePointer()獲取指針的位置,經過seek()方法設置指針的位置。
4:該對象操做的源和目的必須是文件。
5:其實該對象內部封裝了字節讀取流和字節寫入流。
注意:實現隨機訪問,最好是數據有規律。
class RandomAccessFileDemo{
public static void main(String[] args) throws IOException{
write();
read();
randomWrite();
}
//隨機寫入數據,能夠實現已有數據的修改。
public static void randomWrite()throws IOException{
RandomAccessFile raf = new RandomAccessFile("random.txt","rw");
raf.seek(8*4);
System.out.println("pos :"+raf.getFilePointer());
raf.write("王武".getBytes());
raf.writeInt(102);
raf.close();
}
public static void read()throws IOException{
RandomAccessFile raf = new RandomAccessFile("random.txt","r");//只讀模式。
//指定指針的位置。
raf.seek(8*1);//實現隨機讀取文件中的數據。注意:數據最好有規律。
System.out.println("pos1 :"+raf.getFilePointer());
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println(name+"::"+age);
System.out.println("pos2 :"+raf.getFilePointer());
raf.close();
}
public static void write()throws IOException{
//rw:當這個文件不存在,會建立該文件。當文件已存在,不會建立。因此不會像輸出流同樣覆蓋。
RandomAccessFile raf = new RandomAccessFile("random.txt","rw");//rw讀寫模式
//往文件中寫入人的基本信息,姓名,年齡。
raf.write("張三".getBytes());
raf.writeInt(97);
raf.close();
}
管道流:管道讀取流和管道寫入流能夠像管道同樣對接上,管道讀取流就能夠讀取管道寫入流寫入的數據。
注意:須要加入多線程技術,由於單線程,先執行read,會發生死鎖,由於read方法是阻塞式的,沒有數據的read方法會讓線程等待。
public static void main(String[] args) throws IOException{
PipedInputStream pipin = new PipedInputStream();
PipedOutputStream pipout = new PipedOutputStream();
pipin.connect(pipout);
new Thread(new Input(pipin)).start();
new Thread(new Output(pipout)).start();
對象的序列化:目的:將一個具體的對象進行持久化,寫入到硬盤上。
注意:靜態數據不能被序列化,由於靜態數據不在堆內存中,是存儲在靜態方法區中。
如何將非靜態的數據不進行序列化?用transient 關鍵字修飾此變量便可。
Serializable:用於啓動對象的序列化功能,能夠強制讓指定類具有序列化功能,該接口中沒有成員,這是一個標記接口。這個標記接口用於給序列化類提供UID。這個uid是依據類中的成員的數字簽名進行運行獲取的。若是不須要自動獲取一個uid,能夠在類中,手動指定一個名稱爲serialVersionUID id號。依據編譯器的不一樣,或者對信息的高度敏感性。最好每個序列化的類都進行手動顯示的UID的指定。
import java.io.*;
class ObjectStreamDemo {
public static void main(String[] args) throws Exception{
writeObj();
readObj();
}
public static void readObj()throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
Object obj = ois.readObject();//讀取一個對象。
System.out.println(obj.toString());
}
public static void writeObj()throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",25)); //寫入一個對象。
oos.close();
}
}
class Person implements Serializable{
private static final long serialVersionUID = 42L;
private transient String name;//用transient修飾後name將不會進行序列化
public int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name+"::"+age;
}
DataOutputStream、DataInputStream:專門用於操做基本數據類型數據的對象。
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(256);
dos.close();
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int num = dis.readInt();
System.out.println(num);
ByteArrayInputStream:源:內存
ByteArrayOutputStream:目的:內存。
這兩個流對象不涉及底層資源調用,操做的都是內存中數組,因此不須要關閉。
直接操做字節數組就能夠了,爲何還要把數組封裝到流對象中呢?由於數組自己沒有方法,只有一個length屬性。爲了便於數組的操做,將數組進行封裝,對外提供方法操做數組中的元素。
對於數組元素操做無非兩種操做:設置(寫)和獲取(讀),而這兩操做正好對應流的讀寫操做。這兩個對象就是使用了流的讀寫思想來操做數組。
//建立源:
ByteArrayInputStream bis = new ByteArrayInputStream("abcdef".getBytes());
//建立目的:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch = 0;
while((ch=bis.read())!=-1){
bos.write(ch);
}