IO 是什么?其實(shí)就是Java中的一種輸入和輸出功能,也可以理解為對(duì)文件的寫入和讀出的操作,只不過Java中對(duì)這種操作叫做對(duì)流的操作。而流不只是對(duì)文件進(jìn)行讀寫,還可以對(duì)內(nèi)存,網(wǎng)絡(luò),程度操作。
一、字節(jié)與字符
在Java中有輸入、輸出兩種IO流,每種輸入、輸出流又分為字節(jié)流和字符流兩大類。
- 關(guān)于字節(jié),每個(gè)字節(jié)(byte)有8bit組成。
- 關(guān)于字符,我們可能知道代表一個(gè)漢字或者英文字母。
字節(jié)與字符之間的關(guān)系
Java采用unicode編碼,通講,2個(gè)字節(jié)來表示一個(gè)字符。
在0~127整數(shù)之間的字符映射,unicode向下兼容ASCII,也就是1個(gè)字節(jié)表示一個(gè)字符。
一個(gè)中文或英文字符的unicode編碼都占2個(gè)字節(jié)。
| 編碼方式 | 英文字符 | 中文字符 |
|---|---|---|
| GB 2312、GBK | 1 | 2 |
| UTF-8 | 1 | 3-4 |
| UTF-16 | 2 | 3-4 |
| UTF-32 | 4 | 4 |
二、File
文件和文件夾的操作都可以用File來完成。
文件的獲取

//構(gòu)造函數(shù)File(String pathname)
File f1 =new File("c:\\abc\\1.txt");
//File(String parent,String child)
File f2 =new File("c:\\abc","2.txt");
//File(File parent,String child)
File f3 =new File("c:"+File.separator+"abc");//separator 跨平臺(tái)分隔符
File f4 =new File(f3,"3.txt");
System.out.println(f1);//c:\abc\1.txt
文件的創(chuàng)建以及刪除
//如果文件存在返回false,否則返回true并且創(chuàng)建文件
boolean createNewFile();
//創(chuàng)建一個(gè)File對(duì)象所對(duì)應(yīng)的目錄,成功返回true,否則false。且File對(duì)象必須為路徑而不是文件。只會(huì)創(chuàng)建最后一級(jí)目錄,如果上級(jí)目錄不存在就拋異常。
boolean mkdir();
//創(chuàng)建一個(gè)File對(duì)象所對(duì)應(yīng)的目錄,成功返回true,否則false。且File對(duì)象必須為路徑而不是文件。創(chuàng)建多級(jí)目錄,創(chuàng)建路徑中所有不存在的目錄
boolean mkdirs() ;
//如果文件存在返回true并且刪除文件,否則返回false
boolean delete();
//在虛擬機(jī)終止時(shí),刪除File對(duì)象所表示的文件或目錄。
void deleteOnExit();
判斷方法
boolean canExecute() ;//判斷文件是否可執(zhí)行
boolean canRead();//判斷文件是否可讀
boolean canWrite();//判斷文件是否可寫
boolean exists();//判斷文件是否存在
boolean isDirectory();//判斷是否是目錄
boolean isFile();//判斷是否是文件
boolean isHidden();//判斷是否是隱藏文件或隱藏目錄
boolean isAbsolute();//判斷是否是絕對(duì)路徑 文件不存在也能判斷
作者:Ruheng
鏈接:http://www.itdecent.cn/p/c58ed5ec7e4a
來源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
獲取參數(shù)方法
String getName();//返回文件或者是目錄的名稱
String getPath();//返回路徑
String getAbsolutePath();//返回絕對(duì)路徑
String getParent();//返回父目錄,如果沒有父目錄則返回null
long lastModified();//返回最后一次修改的時(shí)間
long length();//返回文件的長(zhǎng)度
File[] listRoots();// 列出所有的根目錄(Window中就是所有系統(tǒng)的盤符)
String[] list() ;//返回一個(gè)字符串?dāng)?shù)組,給定路徑下的文件或目錄名稱字符串
String[] list(FilenameFilter filter);//返回滿足過濾器要求的一個(gè)字符串?dāng)?shù)組
File[] listFiles();//返回一個(gè)文件對(duì)象數(shù)組,給定路徑下文件或目錄
File[] listFiles(FilenameFilter filter);//返回滿足過濾器要求的一個(gè)文件對(duì)象數(shù)組
其中FilenameFileter 是一個(gè)文件過濾器。找到所有png圖片。
file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".png");
}
});
三、IO流
Java的IO流是實(shí)現(xiàn)輸入/輸出的基礎(chǔ),它可以方便地實(shí)現(xiàn)數(shù)據(jù)的輸入/輸出操作,在Java中把不同的輸入/輸出源抽象表述為"流"。
流是一組有順序的字節(jié)集合,是對(duì)數(shù)據(jù)傳輸?shù)目偡Q或抽象。
流有輸入和輸出,輸入時(shí)是流從數(shù)據(jù)源流向程序。輸出時(shí)是流從程序傳向數(shù)據(jù)源,而數(shù)據(jù)源可以是內(nèi)存,文件,網(wǎng)絡(luò)或程序等。
四、分類
- 按照流向不同,分為 輸入流、輸出流
- 按照流對(duì)象不同,分為 字節(jié)流、字符流
字節(jié)流可以處理任意類型的數(shù)據(jù),而字符只能處理字符類型的數(shù)據(jù)
- 按照處理過程不同,分為 節(jié)點(diǎn)流、處理流(一種典型的裝飾器模式)
五、4中基本方式的講解 和 實(shí)例

- inputStream
- outputStream
- Reader
- Write
四大抽象基類,其中inputStream,outputStream是字節(jié)流的基類,Reader,Write是字符流的基類。不能創(chuàng)建實(shí)例,但是為所有實(shí)現(xiàn)類提供了基礎(chǔ)的模板。
inputStream

outputStream

Reader

Write

總結(jié):
從上面的方法中我可以看出。inputStream和reader,outputStream與write的函數(shù)都很相似,并且每次進(jìn)行了IO操作,要記得close,因?yàn)镮O資源并不屬于內(nèi)存資源,并不會(huì)被GC回收。所以需要顯示的 手動(dòng)的回收資源。對(duì)于輸出操作,close還會(huì)自動(dòng)flush。
六、RandomAccessFile的使用與簡(jiǎn)介
RandomAccessFile簡(jiǎn)介
我們?cè)趯?duì)文件的操作過程中,除了使用字節(jié)流和字符流的方式之外,我們還可以使用RandomAcessFile這個(gè)工具類來實(shí)現(xiàn)。
RandomAccessFile可以實(shí)現(xiàn)對(duì)文件的讀 和 寫,但是他并不是繼承于以上4中基本虛擬類。
而且在對(duì)文件的操作中,RandomAccessFile有一個(gè)巨大的優(yōu)勢(shì),他可以支持文件的隨機(jī)訪問,程序快可以直接跳轉(zhuǎn)到文件的任意地方來讀寫數(shù)據(jù)。所以如果需要訪問文件的部分內(nèi)容,而不是把文件從頭讀到尾,使用RandomAccessFile將是更好的選擇。
RandomAccessFile的方法雖然多,但它有一個(gè)最大的局限,就是只能讀寫文件,不能讀寫其他IO節(jié)點(diǎn)。
RandomAccessFile的一個(gè)重要使用場(chǎng)景就是網(wǎng)絡(luò)請(qǐng)求中的多線程下載及斷點(diǎn)續(xù)傳。
構(gòu)造方法以及參數(shù)

mode中,有4中啟動(dòng)的方式
"r" 以只讀方式打開。調(diào)用結(jié)果對(duì)象的任何 write 方法都將導(dǎo)致拋出 IOException。
"rw" 打開以便讀取和寫入。如果該文件尚不存在,則嘗試創(chuàng)建該文件。
"rws" 打開以便讀取和寫入,對(duì)于 "rw",還要求對(duì)文件的內(nèi)容或元數(shù)據(jù)的每個(gè)更新都同步寫入到底層存儲(chǔ)設(shè)備。
"rwd" 打開以便讀取和寫入,對(duì)于 "rw",還要求對(duì)文件內(nèi)容的每個(gè)更新都同步寫入到底層存儲(chǔ)設(shè)備。
RandomAccessFile使用
讀取文件內(nèi)容
RandomAccessFile raf = new RandomAccessFile(file,"r");
String s = null;
while ((s = raf.readLine())!=null){
System.out.println(s);
}
raf.close();
寫入文件內(nèi)容
String text = "寫入的內(nèi)容 \n";
RandomAccessFile raf = new RandomAccessFile(file,"rw");
raf.seek(12); //改變寫入偏移的位置,從地12個(gè)字節(jié)的位置開始寫入
raf.write(text.getBytes());
raf.close();
注意:RandomAccessFile雖然可以設(shè)置了偏移的方法,但他不能實(shí)現(xiàn)中間插入的效果,如果你需要實(shí)現(xiàn)文本中間插入的話,要先將后面的文件內(nèi)容拷貝,然后寫入,最后在寫入的寫一行,將拷貝的東西復(fù)制回來。
七、對(duì)象的序列化與反序列化
什么是序列化和反序列化呢?這是針對(duì)對(duì)象來說的,因?yàn)槲覀冊(cè)趯懭胛募臅r(shí)候,常常因?yàn)橐4娴氖且粋€(gè)對(duì)象,也就是一個(gè)obj,但是里面的變量又很多,我們不可能挨個(gè)申明,一個(gè)個(gè)寫入,這時(shí)候,我們就可以使用對(duì)象的序列化與反序列化。
序列化就是對(duì)象到保存文件的過程。
反序列化就是從保存的文件,轉(zhuǎn)換為對(duì)象的過程。
我們使用ObjectOutputStream和ObjectInputStream 實(shí)現(xiàn)對(duì)象的序列化和反序列化。
File file = new File("test.txt");
MyService ms = new MyService();
try {
OutputStream os = new FileOutputStream(file);
//創(chuàng)建時(shí),需要給予一個(gè)outputStream,這個(gè)很好理解,
//因?yàn)閷?duì)象操作肯定是字節(jié)操作,不能使用字符操作
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(ms);
oos.close();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
InputStream is = new FileInputStream(file);
ObjectInputStream ios = new ObjectInputStream(is);
MyService object = (MyService)ios.readObject();
System.out.println(object.name);
is.close();
ios.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}