一:從數據流開始 java
首先先有一個結構圖看一下整個數據流中的API結構和對象繼承關係信息: 數據庫
其餘經常使用與流有關的對象: 數組
首先從字符流開始 網絡
一、字符流的由來: app
由於文件編碼的不一樣,而有了對字符進行高效操做的字符流對象。 jvm
原理:其實就是基於字節流讀取字節時,去查了指定的碼錶。 函數
字節流和字符流的區別: ui
1,字節流讀取的時候,讀到一個字節就返回一個字節。字符流使用了字節流讀到一個或多個字節(中文對應的字節數是兩個,UTF-8碼錶中是3個字節)時。先去查指定的編碼表,將查到的字符返回。 this
2,字節流能夠處理全部類型數據,如圖片,mp3,avi。而字符流只能處理字符數據。 編碼
結論:只要是處理純文本數據,就要優先考慮使用字符流。除此以外都用
節流。
基本的讀寫操做方式:
由於數據一般都以文件形式存在。
因此就要找到IO體系中能夠用於操做文件的流對象。
經過名稱能夠更容易獲取該對象。
由於IO體系中的子類名後綴絕大部分是父類名稱。而前綴都是體現子類功能的名字。
Reader
|--InputStreamReader
|--FileReader:專門用於處理文件的字符讀取流對象。
Writer
|--OutputStreamWriter
|--FileWriter:專門用於處理文件的字符寫入流對象。
Reader中的常見的方法:
1,int read():讀取一個字符。返回的是讀到的那個字符。若是讀到流的末尾,返回-1.
2,int read(char[]):將讀到的字符存入指定的數組中,返回的是讀到的字符個數,也就是往數組裏裝的元素的個數。若是讀到流的末尾,返回-1.
3,close():讀取字符其實用的是window系統的功能,就但願使用完畢後,進行資源的釋放
Writer中的常見的方法:
1,write(ch): 將一個字符寫入到流中。
2,write(char[]): 將一個字符數組寫入到流中。
3,write(String): 將一個字符串寫入到流中。
4,flush():刷新流,將流中的數據刷新到目的地中,流還存在。
5,close():關閉資源:在關閉前會先調用flush(),刷新流中的數據去目的地。然流關閉。
FileWriter:該類沒有特有的方法只有本身的構造函數。該類特色在於
1,用於處理文本文件。
2,該類中有默認的編碼表,
3,該類中有臨時緩衝。
構造函數:在寫入流對象初始化時,必需要有一個存儲數據的目的地。
對於讀取或者寫入流對象的構造函數,以及讀寫方法,還有刷新關閉功能都會拋出IOException或其子類。因此都要進行處理。或者throws拋出,或者try catch處理
另外一個小細節:
當指定絕對路徑時,定義目錄分隔符有兩種方式:
1,反斜線可是必定要寫兩個。\\new FileWriter("c:\\demo.txt");
2,斜線/ 寫一個便可。new FileWriter("c:/demo.txt");
一個讀取文本文件的經典例子:
字符流的緩衝區:緩衝區的出現提升了對流的操做效率。
原理:其實就是將數組進行封裝。
對應的對象:
BufferedWriter:特有方法:newLine():跨平臺的換行符。
BufferedReader:特有方法:readLine():一次讀一行,到行標記時,將行標記以前的字符數據做爲字符串返回。當讀到末尾時,返回null。
在使用緩衝區對象時,要明確,緩衝的存在是爲了加強流的功能而存在,
因此在創建緩衝區對象時,要先有流對象存在。
其實緩衝內部就是在使用流對象的方法,只不過加入了數組對數據進行了臨時存儲。爲了提升操做數據的效率。
代碼上的體現:
寫入緩衝區對象。
//創建緩衝區對象必須把流對象做爲參數傳遞給緩衝區的構造函數。
BufferedWriter bufw = new BufferedWriter(new FileWriter("buf.txt"));
bufw.write("abce");//將數據寫入到了緩衝區。
bufw.flush();//對緩衝區的數據進行刷新。將數據刷到目的地中。
bufw.close();//關閉緩衝區,其實關閉的是被包裝在內部的流對象。
讀取緩衝區對象。
BufferedReader bufr = new BufferedReader(new FileReader("buf.txt"));
String line = null;
//按照行的形式取出數據。取出的每個行數據不包含回車符。
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
readLine():方法的原理:
其實緩衝區中的該方法,用的仍是與緩衝區關聯的流對象的read方法。只不過,每一次讀到一個字符,先不進行具體操做,先進行臨時存儲。當讀取到回車標記時,將臨時容器中存儲的數據一次性返回。
既然明確了原理,咱們也能夠實現一個相似功能的方法。
而後說一下字節流:
抽象基類:InputStream,OutputStream。
字節流能夠操做任何數據。
注意:字符流使用的數組是字符數組。char [] chs字節流使用的數組是字節數組。byte [] bt
FileOutputStream fos = new FileOutputStream("a.txt");
fos.write("abcde");//直接將數據寫入到了目的地。
fos.close();//只關閉資源。
FileInputStream fis = new FileInputStream("a.txt");
//fis.available();//獲取關聯的文件的字節數。
//若是文件體積不是很大。
//能夠這樣操做。
byte[] buf = new byte[fis.available()];//建立一個剛恰好的緩衝區。
//可是這有一個弊端,就是文件過大,大小超出jvm的內容空間時,會內存溢出。
fis.read(buf);
一個小問題:
字節流的read()方法讀取一個字節。爲何返回的不是byte類型,而是int類型呢?
由於read方法讀到末尾時返回的是-1,而在所操做的數據中的很容易出現連續多個1的狀況,而連續讀到8個1,就是-1,致使讀取會提早中止。因此將讀到的一個字節給提高爲一個int類型的數值,可是隻保留原字節,並在剩餘二進制位補0.
對於write方法,能夠一次寫入一個字節,但接收的是一個int類型數值。只寫入該int類型的數值的最低一個字節(8位)。
簡單說:read方法對讀到的數據進行提高。write對操做的數據進行轉換。這是神馬意思???
轉換流:
特色:
1,是字節流和字符流之間的橋樑。
2,該流對象中能夠對讀取到的字節數據進行指定編碼表的編碼轉換。
何時使用呢?
1,當字節和字符之間有轉換動做時。
2,流操做的數據須要進行編碼表的指定時。
具體的對象體現:
1,InputStreamReader:字節到字符的橋樑。
2,OutputStreamWriter:字符到字節的橋樑。
這兩個流對象是字符流體系中的成員。
那麼它們有轉換做用,而自己又是字符流。因此在構造的時候,須要傳入字節流對象進來。
構造函數:
InputStreamReader(InputStream):經過該構造函數初始化,使用的是本系統默認的編碼表GBK。
InputStreamReader(InputStream,String charSet):經過該構造函數初始化,能夠指定編碼表。
OutputStreamWriter(OutputStream):經過該構造函數初始化,使用的是本系統默認的編碼表GBK。
OutputStreamWriter(OutputStream,String charSet):經過該構造函數初始化,能夠指定編碼表。
能夠和流相關聯的集合對象Properties.
Map
|--Hashtable
|--Properties
Properties:該集合不須要泛型,由於該集合中的鍵值對都是String類型。
1,存入鍵值對:setProperty(key,value);
2,獲取指定鍵對應的值:value getProperty(key);
3,獲取集合中全部鍵元素:
Enumeration propertyNames();
在jdk1.6版本給該類提供一個新的方法。
Set<String> stringPropertyNames();
4,列出該集合中的全部鍵值對,能夠經過參數打印流指定列出到的目的地。
list(PrintStream);
list(PrintWriter);
例:list(System.out):將集合中的鍵值對打印到控制檯。
list(new PrintStream("prop.txt")):將集合中的鍵值對存儲到prop.txt文件中。
5,能夠將流中的規則數據加載進行集合,並稱爲鍵值對。
load(InputStream):
jdk1.6版本。提供了新的方法。
load(Reader):
注意:流中的數據要是"鍵=值" 的規則數據。
6,能夠將集合中的數據進行指定目的的存儲。
store(OutputStram,String comment)方法。
jdk1.6版本。提供了新的方法。
store(Writer ,String comment):
使用該方法存儲時,會帶着當時存儲的時間。
File類:
該類的出現是對文件系統的中的文件以及文件夾進行對象的封裝。
能夠經過對象的思想來操做文件以及文件夾。
1,構造函數:
File(String filename):將一個字符串路徑(相對或者絕對)封裝成File對象,該路徑是可存在的,也能夠是不存在。
File(String parent,String child);
File(File parent,String child);
2,特別的字段:separator:跨平臺的目錄分隔符。
如:File file = new File("c:"+File.separator+"abc"+File.separator+"a.txt");
3,常見方法:
1,建立:
boolean createNewFile()throws IOException:建立文件,若是被建立的文件已經存在,則不建立。
boolean mkdir(): 建立文件夾。
boolean mkdirs(): 建立多級文件夾。
2,刪除:
boolean delete():可用於刪除文件或者文件夾。
注意:對於文件夾只能刪除不帶內容的空文件夾,
對於帶有內容的文件夾,不能夠直接刪除,必需要從裏往外刪除。
void deleteOnExit(): 刪除動做交給系統完成。不管是否反生異常,系統在退出時執行刪除動做。
3,判斷:
boolean canExecute():
boolean canWrite():
boolean canRead();
boolean exists():判斷文件或者文件夾是否存在。
boolean isFile(): 判斷File對象中封裝的是不是文件。
boolean isDirectory():判斷File對象中封裝的是不是文件夾。
boolean isHidden():判斷文件或者文件夾是否隱藏。在獲取硬盤文件或者文件夾時,
對於系統目錄中的文件,java是沒法訪問的,因此在遍歷,能夠避免遍歷隱藏文件。
4,獲取:
getName():獲取文件或者文件夾的名稱。
getPath():File對象中封裝的路徑是什麼,獲取的就是什麼。
getAbsolutePath():不管File對象中封裝的路徑是什麼,獲取的都是絕對路徑。
getParent(): 獲取File對象封裝文件或者文件夾的父目錄。
注意:若是封裝的是相對路徑,那麼返回的是null.
long length():獲取文件大小。
longlastModified():獲取文件或者文件最後一次修改的時間。
static File[] listRoots():獲取的是被系統中有效的盤符。
String[] list():獲取指定目錄下當前的文件以及文件夾名稱。
String[] list(Filenamefilter): 能夠根據指定的過濾器,過濾後的文件及文件夾名稱。
File[] listFiles():獲取指定目錄下的文件以及文件夾對象。
5,重命名:
renameTo(File):
File f1 = new File("c:\\a.txt");
File f2 = new File("c:\\b.txt");
f1.renameTo(f2);//將c盤下的a.txt文件更名爲b.txt文件。
對象的序列化。
ObjectInputStream
ObjectOutputStream
能夠經過這兩個流對象直接操做已有對象並將對象進行本地持久化存儲。
存儲後的對象能夠進行網絡傳輸。
Serializable:該接口其實就是一個沒有方法的標記接口。
用於給類指定一個UID。該UID是經過類中的可序列化成員的數字簽名運算出來的一個long型的值。
只要是這些成員沒有變化,那麼該值每次運算都同樣。
該值用於判斷被序列化的對象和類文件是否兼容。
若是被序列化的對象須要被不一樣的類版本所兼容。能夠在類中自定義UID。
定義方式:static final long serialVersionUID = 42L;
注意:對應靜態的成員變量,不會被序列化。
對應非靜態也不想被序列化的成員而言,能夠經過transient關鍵字修飾。
一般,這兩個對象成對使用。
————————————————————————————————————
其餘的數據操做流
操做基本數據類型的流對象。
DataInputStream
DataInputStream(InputStream);
操做基本數據類型的方法:
int readInt():一次讀取四個字節,並將其轉成int值。
boolean readBoolean():一次讀取一個字節。
short readShort();
long readLong();
剩下的數據類型同樣。
String readUTF():按照utf-8修改版讀取字符。注意,它只能讀writeUTF()寫入的字符數據。
DataOutputStream
DataOutputStream(OutputStream):
操做基本數據類型的方法:
writeInt(int):一次寫入四個字節。
注意和write(int)不一樣。write(int)只將該整數的最低一個8位寫入。剩餘三個8位丟棄。
writeBoolean(boolean);
writeShort(short);
writeLong(long);
剩下是數據類型也也同樣。
writeUTF(String):按照utf-8修改版將字符數據進行存儲。只能經過readUTF讀取。
一般只要操做基本數據類型的數據。就須要經過DataStram進行包裝。
一般成對使用。
————————————————————————————————————
操做數組的流對象。
1,操做字節數組
ByteArrayInputStream
ByteArrayOutputStream
toByteArray();
toString();
writeTo(OutputStream);
2,操做字符數組。
CharArrayReader
CharArrayWriter
對於這些流,源是內存。目的也是內存。
並且這些流並未調用系統資源。使用的就是內存中的數組。
因此這些在使用的時候不須要close。
操做數組的讀取流在構造時,必需要明確一個數據源。因此要傳入相對應的數組。
對於操做數組的寫入流,在構造函數可使用空參數。由於它內置了一個可變長度數組做爲緩衝區。