一、文件的編碼
開發時一定要注意項目默認的編碼!!!!!!!!
文件操作的時候一定要記得關閉!!!!!!!!
ASCII:美國標准信息交換碼,用一個字節的7位可以表示一個字符
ISO8859-1:拉丁碼表,西歐標准字符集,用一個字節的8位表示
GB2312:中文編碼表,用兩個字節來表示中文編碼
GBK:中文編碼表的升級,融合了更多表示中文文字符號
GB18030:GBK的取代版本
BIG-5:同行與港台地區,是繁體字編碼方案,俗稱“大五碼”
Uicode:國際標准碼,融合了多種文字
UTF-8:是Unicode編碼的實現方式,最多用三個字節來表示一個字符
GBK編碼 中文占用2個字節,英文占用1個字節
UTF-8編碼 中文占用3個字節,英文占用1個字節
UTF-16be編碼中文占用2個字節,英文占用2個字節
Java是雙字節編碼 utf-16be,即java中每個字符占用兩個字節
當你想把一個字節序列變成一個字符串時,字節序列使用什么編碼,就需要使用什么編碼去顯示的調用s.getBytes("字節序列的編碼格式");,否則會出現亂碼
文本文件就是字節序列,可以是任意編碼的字節序列,但是如果是在中文機器上直接創建文本文件,那么該文本文件只認識ANSI(本地編碼)編碼。如,新建一個TXT文件,內容為聯通,打開則會出現亂碼,是一種巧合,正好符合了UTF-8編碼的規則
Integer.toHexString(Byte);//以十六進制的方式顯示
二、File工具類的使用
1、File類用於表示文件和目錄都可以
File類只用於表示文件(目錄)的信息(名稱、大小等),不能用於文件內容的訪問
2、File類的基本API(看手冊)
構造函數的情況
創建功能:createNewFile(),mkdir(),mkdirs()
刪除功能:delete()
重命名功能:renameTo()
判斷功能:isFile(),isDirectory(),exists()等
獲取功能:getName(),getPath(),list()等
文件過濾器的作用:list(FilenameFilter filter),返回滿足指定條件的文件列表
判斷參數的時候,可以使用
IllegalArgumentException參數拋出異常
File.separator設置目錄分隔符,Windows、Unix都識別
相對目錄是當前目錄,也即在項目的根目錄下
3、遍歷目錄(遞歸 dir.listFiles())
訪問文件系統的時候因為是與JVM以外的資源進行交互,所以,寫代碼一定要嚴謹,把各種情況考慮到了
三、RandomAccessFile類的使用
1、
RandomAccessFile
java提供的對文件內容的訪問,既可以讀,也可以寫
且支持隨機訪問文件,可以訪問文件的任意位置
2、Java文件模型
在硬盤上的文件是byte byte byte存儲的,是數據的集合
3、打開文件
1 RandomAccessFile raf =newRandomAccessFile(file,"rw");//rw,讀寫,r只讀 2 //打開文件時,文件指針在開頭,pointer = 0; 3 raf.write(byte);//write方法只會寫一個字節,同時直接指針指向下一個位置 4 int b = raf.read();//每次讀一個字節,java中每個字符占用兩個字節,使用右移8位的方式分次寫入 5 raf.seek(指針位置);//移動指針 6 raf.close();//文件讀寫完一定要關閉,否則可能會有意想不到的后果
在文件下載文件的時候,這種方式有很大的好處,每個線程下載文件的一部分,
然后再拼接在一起,迅雷就是使用的這種方式,會記錄指針的位置
四、字節流(InputStream、OutputStream,兩個都是抽象類)
1、I/O流用來處理設備之間的數據傳輸
InputStream抽象了應用程序讀取數據的方式
OutputStream抽象了應用程序寫出數據的方式
2、EOF = End 讀到 -1 就讀到結尾
3、輸入流的基本方式主要是讀
int b = in.read();//讀取一個字節無符號填充到int第八位,-1是EOF
in.read(byte[] buf);//讀入多個字節填充的字節數組
4、輸出流的基本方式主要是寫
out.write(int b);
out.write(byte[] buf);
5、FileInputStream具體實現了文件的讀取操作
while((b=in.read())!=-1){讀一個文件}
in.close();//一定要記得關閉流釋放系統資源
批量讀取(速度非常快,效率高) vs. 單字節讀取(不適合讀大文件,效率很低)
6、FileOutputStream具體實現了向文件中寫數據的操作
是刪除文件重新創建,還是在原文件上追加內容,看構造方法
自己實現文件的copy操作
out.flush();
out.close();
7、數據輸入輸出流DataOutputStream/DataInputStream
對流功能的擴展,是一個包裝類,可以更加方便的讀取int,long,字符等類型數據,本質是使用的一種裝飾模式實現的
8、字節緩沖流BufferedInputStream/BufferedOutputStream
為I/O提供了帶緩沖區的操作,這種流模式提高了I/O的性能
.write();
.flush();//刷新緩沖區,否則寫入不到文件中
.close();
五、字符流(參考API)
1、Java為什么引入字符流?
操作文本時,尤其是包含中文字符等非ASCII碼的字符會很不方便
字符流 = 字節流+編碼
所以,要對編碼問題非常清楚
2、java的文本(char)是16位無符號整數,是字符的Unicode編碼(雙字節)
文件是byte byte byte……的數據序列
文本文件是文本序列按照某種編碼方式序列化為byte的存儲
3、字符流(Reader Writer)操作的是文本文件
一次處理一個字符,字符的底層仍然是基本的字節序列
InputStreamReader 完成byte流按照編碼解析為char流
OutputStreamWriter 提供char流按照編碼解析成byte流
4、文件讀寫流 FileReader、FileWriter
沒法設置編碼,必須回到字符流設置編碼
5、字符流的過濾器BufferedReader、BufferedWriter、PrintWriter
readLine 可以一次讀一行,一次寫一行
可以設置編碼,不識別換行,單獨寫出換行操作
六、對象的序列化和反序列化
1、將Object對象轉換成byte序列,反之叫對象的反序列化
2、序列化流(ObjectOutputStream),是過濾流---writeObject()
反序列化流(ObjectInputStream), ----readObject
3、序列化接口(Serializable)
對象必須實現序列化接口,才能進行序列化,否則將出現異常
這個接口沒有任何方法,只是一個標准,是標記接口
對象序列化后,如果對再次對類文件修改,那么反序列化的時候就會出問題,那么怎么解決呢?
需要在類中設置序列版本id,唯一標記,這樣無論怎么修改讀取的時候都不會再有問題 serialVersionUID
4、transient關鍵字
聲明的元素不會進行JVM默認的序列化,也可以自己完成這個元素的序列化
網絡中傳輸時,並不是所有的元素都是有必要傳輸的,尤其是要考慮節約網絡流量的時候
在有些情況下,可以幫助我們提高性能(ArrayList在數組沒有放滿的時候,只把有效元素序列化)
5、序列化中 子類和父類構造函數的調用問題
父類實現了序列化接口,子類不需要再次實現,就能進行序列化
對子類對象進行反序列化操作時,如果其父類沒有顯示的實現序列化接口,那么其父類的構造函數會被調用
七、輸入輸出流的一些包裝類
1、打印流
PrintStream :字節打印流
PrintWriter :字符打印流
集成了Print()格式化輸出方法,可以操作任意類型的數據
2、標准輸入輸出流
System類的in、out字段
默認輸入設備是鍵盤,輸出設備是顯示器
標准IO重定向
System.setIn(InputStream);
//重定向輸出可以將打印到控制台的日志寫到文件
System.setOut(PrintStream);
System.err(PrintStream);
3、進程控制
在Java內部執行其他操作系統的程序,並要求控制這些程序的輸入輸出時
向OSExecute.command()傳遞一個command字符串
Process process = new ProcessBuilder(command.split(" ")).start(); OSExecute.command("javap test"); //javap是java的一個反編譯程序
八、IO操作過程中異常處理
自己編程要用try-catch-finally包圍起來,如果有異常盡量處理,千萬不要僅僅是用printStackTrace()打印棧信息,在finally中進行流的關閉(判斷引用不為空的話關閉),以確保一定能得到執行