IO 是什么?其實就是Java中的一種輸入和輸出功能,也可以理解為對文件的寫入和讀出的操作,只不過Java中對這種操作叫做對流的操作。而流不只是對文件進(jìn)行讀寫,還可以對內(nèi)存,網(wǎng)絡(luò),程度操作。
一、字節(jié)與字符
在Java中有輸入、輸出兩種IO流,每種輸入、輸出流又分為字節(jié)流和字符流兩大類。
- 關(guān)于字節(jié),每個字節(jié)(byte)有8bit組成。
- 關(guān)于字符,我們可能知道代表一個漢字或者英文字母。
字節(jié)與字符之間的關(guān)系
Java采用unicode編碼,通講,2個字節(jié)來表示一個字符。
在0~127整數(shù)之間的字符映射,unicode向下兼容ASCII,也就是1個字節(jié)表示一個字符。
一個中文或英文字符的unicode編碼都占2個字節(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 跨平臺分隔符
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)建一個File對象所對應(yīng)的目錄,成功返回true,否則false。且File對象必須為路徑而不是文件。只會創(chuàng)建最后一級目錄,如果上級目錄不存在就拋異常。
boolean mkdir();
//創(chuàng)建一個File對象所對應(yīng)的目錄,成功返回true,否則false。且File對象必須為路徑而不是文件。創(chuàng)建多級目錄,創(chuàng)建路徑中所有不存在的目錄
boolean mkdirs() ;
//如果文件存在返回true并且刪除文件,否則返回false
boolean delete();
//在虛擬機(jī)終止時,刪除File對象所表示的文件或目錄。
void deleteOnExit();
判斷方法
boolean canExecute() ;//判斷文件是否可執(zhí)行
boolean canRead();//判斷文件是否可讀
boolean canWrite();//判斷文件是否可寫
boolean exists();//判斷文件是否存在
boolean isDirectory();//判斷是否是目錄
boolean isFile();//判斷是否是文件
boolean isHidden();//判斷是否是隱藏文件或隱藏目錄
boolean isAbsolute();//判斷是否是絕對路徑 文件不存在也能判斷
作者:Ruheng
鏈接:http://www.lxweimin.com/p/c58ed5ec7e4a
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
獲取參數(shù)方法
String getName();//返回文件或者是目錄的名稱
String getPath();//返回路徑
String getAbsolutePath();//返回絕對路徑
String getParent();//返回父目錄,如果沒有父目錄則返回null
long lastModified();//返回最后一次修改的時間
long length();//返回文件的長度
File[] listRoots();// 列出所有的根目錄(Window中就是所有系統(tǒng)的盤符)
String[] list() ;//返回一個字符串?dāng)?shù)組,給定路徑下的文件或目錄名稱字符串
String[] list(FilenameFilter filter);//返回滿足過濾器要求的一個字符串?dāng)?shù)組
File[] listFiles();//返回一個文件對象數(shù)組,給定路徑下文件或目錄
File[] listFiles(FilenameFilter filter);//返回滿足過濾器要求的一個文件對象數(shù)組
其中FilenameFileter 是一個文件過濾器。找到所有png圖片。
file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".png");
}
});
三、IO流
Java的IO流是實現(xiàn)輸入/輸出的基礎(chǔ),它可以方便地實現(xiàn)數(shù)據(jù)的輸入/輸出操作,在Java中把不同的輸入/輸出源抽象表述為"流"。
流是一組有順序的字節(jié)集合,是對數(shù)據(jù)傳輸?shù)目偡Q或抽象。
流有輸入和輸出,輸入時是流從數(shù)據(jù)源流向程序。輸出時是流從程序傳向數(shù)據(jù)源,而數(shù)據(jù)源可以是內(nèi)存,文件,網(wǎng)絡(luò)或程序等。
四、分類
- 按照流向不同,分為 輸入流、輸出流
- 按照流對象不同,分為 字節(jié)流、字符流
字節(jié)流可以處理任意類型的數(shù)據(jù),而字符只能處理字符類型的數(shù)據(jù)
- 按照處理過程不同,分為 節(jié)點流、處理流(一種典型的裝飾器模式)
五、4中基本方式的講解 和 實例
- inputStream
- outputStream
- Reader
- Write
四大抽象基類,其中inputStream,outputStream是字節(jié)流的基類,Reader,Write是字符流的基類。不能創(chuàng)建實例,但是為所有實現(xiàn)類提供了基礎(chǔ)的模板。
inputStream
outputStream
Reader
Write
總結(jié):
從上面的方法中我可以看出。inputStream和reader,outputStream與write的函數(shù)都很相似,并且每次進(jìn)行了IO操作,要記得close,因為IO資源并不屬于內(nèi)存資源,并不會被GC回收。所以需要顯示的 手動的回收資源。對于輸出操作,close還會自動flush。
六、RandomAccessFile的使用與簡介
RandomAccessFile簡介
我們在對文件的操作過程中,除了使用字節(jié)流和字符流的方式之外,我們還可以使用RandomAcessFile這個工具類來實現(xiàn)。
RandomAccessFile可以實現(xiàn)對文件的讀 和 寫,但是他并不是繼承于以上4中基本虛擬類。
而且在對文件的操作中,RandomAccessFile有一個巨大的優(yōu)勢,他可以支持文件的隨機(jī)訪問,程序快可以直接跳轉(zhuǎn)到文件的任意地方來讀寫數(shù)據(jù)。所以如果需要訪問文件的部分內(nèi)容,而不是把文件從頭讀到尾,使用RandomAccessFile將是更好的選擇。
RandomAccessFile的方法雖然多,但它有一個最大的局限,就是只能讀寫文件,不能讀寫其他IO節(jié)點。
RandomAccessFile的一個重要使用場景就是網(wǎng)絡(luò)請求中的多線程下載及斷點續(xù)傳。
構(gòu)造方法以及參數(shù)
mode中,有4中啟動的方式
"r" 以只讀方式打開。調(diào)用結(jié)果對象的任何 write 方法都將導(dǎo)致拋出 IOException。
"rw" 打開以便讀取和寫入。如果該文件尚不存在,則嘗試創(chuàng)建該文件。
"rws" 打開以便讀取和寫入,對于 "rw",還要求對文件的內(nèi)容或元數(shù)據(jù)的每個更新都同步寫入到底層存儲設(shè)備。
"rwd" 打開以便讀取和寫入,對于 "rw",還要求對文件內(nèi)容的每個更新都同步寫入到底層存儲設(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個字節(jié)的位置開始寫入
raf.write(text.getBytes());
raf.close();
注意:RandomAccessFile雖然可以設(shè)置了偏移的方法,但他不能實現(xiàn)中間插入的效果,如果你需要實現(xiàn)文本中間插入的話,要先將后面的文件內(nèi)容拷貝,然后寫入,最后在寫入的寫一行,將拷貝的東西復(fù)制回來。
七、對象的序列化與反序列化
什么是序列化和反序列化呢?這是針對對象來說的,因為我們在寫入文件的時候,常常因為要保存的是一個對象,也就是一個obj,但是里面的變量又很多,我們不可能挨個申明,一個個寫入,這時候,我們就可以使用對象的序列化與反序列化。
序列化就是對象到保存文件的過程。
反序列化就是從保存的文件,轉(zhuǎn)換為對象的過程。
我們使用ObjectOutputStream和ObjectInputStream 實現(xiàn)對象的序列化和反序列化。
File file = new File("test.txt");
MyService ms = new MyService();
try {
OutputStream os = new FileOutputStream(file);
//創(chuàng)建時,需要給予一個outputStream,這個很好理解,
//因為對象操作肯定是字節(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();
}