javaIO總體思想是圍繞以下四個抽象類來進行擴充展開。[凡以...stream結尾的類,都是字節流/比特流; 凡以Reader或Writer結尾的類,都是字符流] 1.InputStream:輸入字節流(通常所說的從文件中讀取字節,以字符形式顯示)。2.OutputStream:輸出字節流(通常所說的將字節寫入到文件中)。 3.Reader:輸入字符流 4.Writer:輸出字符流 上述四個抽象類,必須要用相關的子類進行實例化。 Reader類及其子類提供的字符流的讀取char(16位,unicode編碼), inputStream及其子類提供字節流的讀取byte(8位), 所以FileReader類是將文件按字符流的方式讀取,FileInputStream則按字節流的方式讀取文件; FileInputStream以字節爲單位(非 unicode )的流處理。字節序列即:二進制數據。與編碼無關,不存在亂碼問題。 FileInputStream :以字節流方式讀取; FileReader :把文件轉換爲字符流讀入; 常用的Reader類 FileReader ,InputStreamReader ,BufferedReader FileReader 與 InputStreamReader 涉及編碼轉換,可能在不同的平臺上出現亂碼現象。 (FileInputStream 以二進制方式處理,不會出現亂碼現象。) FileReader是InputStreamReader 類的子類。 InputStreamReader 的構造函數參數爲InputStream 和編碼方式,當要指定編碼方式時, 必須使用 InputStreamReader 類。 FileReader 構造函數的參數與 FileInputStream 同,爲 File 對象或表示 path 的 String。 衍生了兩個重要的輸入輸出轉換流:InputStreaReader和OutputStreamWriter這兩個類是字節流和字符流之間的轉換橋樑。 所以在使用這兩個類的構造方法進行實例化對象時,如果不指定編碼方式,則會自動採用當前操作系統的默認字符集進行編碼。 該兩個類會牽涉到編碼設置。 InputStreaReader:可以將一個字節中流中的字節解碼生成字符OutputStreamWriter:將寫入的字符編碼成字節後寫入字節流 編碼:字符串變成字節數組,寫入到文件中。寫的過程 解碼:字節數組變成字符串,以示人們能看懂。讀的過程 總結:源文件以什麼方式編的碼,解碼也必須用原來編碼時的方式進行解碼,否則肯定會有亂碼出現。 注意:存放在文件中的內容都是字節,而讀到內存中的纔可能變爲字符。 (1T=1024G, 1G=1024M, 1M=1024K, 1K=1024B, 1B=8bit) 以下示例主要是理解編碼與解碼。 例1.EncodeDemo.java import java.io.UnsupportedEncodingException; import java.util.Arrays; /*功能:理解編碼與解碼。 * 編碼:字符串變成字節數組。string-----> byte [] str.getBytes(); * 解碼:字節數組變成字符串(字符串纔可顯示看得懂)。byte []-----> string str = new String(byte[]); * 字節和字符之間轉換要通過兩個對象(InputStreamReader,OutputStreamWriter)來完成,這兩個對象在構造時,就加入了字符集[編碼表]。 * 編碼表的由來:計算機只能識別二進制數據,早期由來是電信號。 * 爲了方便應用計算機,讓它可以識別各個國家的文字 * 就將各個國家的文字用數字來表示,並一一對應,形成一張表。這就是編碼表。 * */ public class EncodeDemo { public static void main(String args[]){ String s = "您好嗎"; byte[] b1 = null; //b1 = s.getBytes("ISO8859-1"); //將s按操作系統默認的編碼gbk進行編碼 b1 = s.getBytes(); //static String toString(byte[] a) 返回指定數組內容的字符串表示形式。 System.out.println(Arrays.toString(b1)); String s1; String s2; try { //將b1按ISO8859-1編碼進行解碼 s1 = new String(b1,"ISO8859-1"); //因爲編碼時採用當前電腦操作系統的默認中文編碼,而解碼時採用了ISO8859-1,所以顯示時s1會亂碼。 System.out.println("s1="+s1); //對s1進行iso8859-1編碼。等於再次編碼回去。 byte [] b2 = s1.getBytes("ISO8859-1"); System.out.println(Arrays.toString(b2)); //解碼.按照 gbk進行解 s2 = new String(b2,"gbk"); System.out.println("s2="+s2); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //獲取系統當前編碼 //System.getProperty("file.encoding"); } } 例2.EncodeDemo2.java import java.util.*; public class EncodeDemo2 { /** * 功能:當解碼的方式用錯了的時候,如何再次進行編碼後,再正確地進行解碼。 * 修改,如果將程序中的iso8859-1編碼全修改成utf-8,則結果又出意外。 原因是,因爲utf-8也識別中文(而iso8859-1不識別中文,反而更不會亂碼,所以,tomcat服務器爲什麼採用iso8859-1的原因在此), 而經過gbk編碼後的字符,用utf-8解的時候,根本找不到對應的字符。 * 所以,會在未知區域中查找,就查出一堆相似的字符,返回。* @param args * @throws Exception */ public static void main(String args[]) throws Exception{ String s = "您好"; //將s以操作系統認的gbk方式進行編碼 byte [] b1 = s.getBytes(); //打印出字節數組的字符串形式 System.out.println(Arrays.toString(b1)); //將b1字節數組以iso8859-1方式進行解碼。正確的方式應該還是以gbk的方式進行解碼。 String s1 = new String(b1,"iso8859-1"); //打印出s1.肯定爲亂碼。因爲編碼和解碼的方式不統一 System.out.println("s1="+s1); //對s1以iso8859-1進行編碼.因爲上述的解碼方式錯了,所以,需要再次將錯誤的解碼方式進行反編碼 byte [] b2 = s1.getBytes("iso8859-1"); System.out.println(Arrays.toString(b2)); //將b2以gbk的方式進行解碼 String s2 = new String(b2,"gbk"); System.out.println("s2="+s2); } } 例3.EncodeDemo3.java public class EncodeDemo3 { /** * 功能:將字符串轉換成二進制數 * @param args * @throws Exception */ public static void main(String args[]) throws Exception{ String s = "聯通"; String ss = "q"; byte[] b = ss.getBytes("gbk"); for (int i = 0; i < b.length; i++) { System.out.println("q的二進制爲:"+Integer.toBinaryString(b[i])); } byte [] by = s.getBytes("gbk"); for (int i = 0; i < by.length; i++) { System.out.println(by[i]+"的二進制數爲:"); //將4個數字轉換成二進制打印出來 System.out.println(Integer.toBinaryString(by[i])); System.out.println("取後8位爲:"+Integer.toBinaryString(by[i]&255)); System.out.println("=============================="); } } } 例4.InputStreamReaderBigFile.java /** 讀取大文件 * 功能:用java讀取文件的全部內容,讀取的內容較多時,不能一個字符一個字符地讀,可以一次讀一行。 */ import java.io.*; public class InputStreamReaderBigFile { public static void main(String args[]) throws Exception{ readText(); } public static void readText() throws Exception{ //假定utf-8.txt文件已存在,並且寫入時是以utf-8的方式編碼。 InputStreamReader isr = new InputStreamReader(new FileInputStream("utf-8.txt"),"utf-8"); //BufferedReader這個對象,可以一次讀取一行 BufferedReader br = new BufferedReader(isr); String str; while((str = br.readLine())!=null){ System.out.println(str); } br.close(); isr.close(); } } 例5.OutputStreamWriterGBK.java import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStreamWriter; /** * 功能:將字符串寫入到指定文件中 ,主要是理解寫文件時編碼 * @author Administrator * */ public class OutputStreamWriterGBK { public static void main(String args[]) throws Exception{ osw(); } public static void osw() throws Exception{ try { //缺省編碼方式爲操作系統的字符集gbk,所以gbk可以不寫 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk"); //調用父類Writer的write()方法 osw.write("您好"); osw.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 例6.InputStreamReaderGBK.java import java.io.FileInputStream; import java.io.InputStreamReader; /** * 功能:用字符char的方式讀出gbk.txt文件中內容,並以gbk的方式讀取。主要是理解讀文件時解碼 * @author Administrator * */ public class InputStreamReaderGBK { public static void main(String []arg) throws Exception{ isr(); } public static void isr() throws Exception{ InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"gbk"); //unicode:一個字符佔2個字節,1個字節佔8位 //因爲知道了gbk.txt中的內容少,故在此用char來讀取 char [] buf = new char[10]; int len = isr.read(buf); System.out.println("gbk.txt文件內容長度爲:"+len+"個字符"); String string = new String(buf,0,len); System.out.println(string); isr.close(); } } 例7.OutputStreamWriterUTF8.java import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStreamWriter; /** * 功能:將字符串寫入到指定文件中 。理解寫入字符到文件時的編碼,以utf-8 * @author Administrator * */ public class OutputStreamWriterUTF8 { public static void main(String args[]) throws Exception{ osw(); } public static void osw() throws Exception{ try { //缺省編碼方式爲操作系統的字符集gbk,因爲創建utf-8.txt文件時,指定了utf-8的編碼,所以在此必須明確寫上utf-8的編碼方式 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf-8.txt"),"utf-8");//在這個地方進行轉碼操作 osw.write("您好"); osw.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 完例7相同的將字符串寫入文件功能。但用了不同的實現方式。 import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; public class WriteFile { public static void main(String[] args) throws Exception { //假定utf-8.txt文件的編碼方式是以utf-8方式編碼的 String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); OutputStream out=new FileOutputStream(f); String s = "我們"; //表示以操作系統默認字符集編碼方式寫入文件 //out.write(s.getBytes()); //表示以utf-8的編碼方式寫入文件。以後讀取文件內容時,也必須用utf-8進行解碼讀取。將字符串轉換字節的方式 //s.getBytes("utf-8")表示將一字節數組寫進去 out.write(s.getBytes("utf-8"));//在這個地方進行設置編碼 out.close(); } } 當然,上面的代碼也可修改成一個字節一個字節地進行寫入: import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; public class WriteFile { public static void main(String[] args) throws Exception { //假定utf-8.txt文件的編碼方式是以utf-8方式編碼的 String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); OutputStream out = new FileOutputStream(f); String s = "我們"; //表示以操作系統默認字符集編碼方式寫入文件 //in.write(s.getBytes()); //表示以utf-8的編碼方式寫入文件。以後讀取文件內容時,也必須用utf-8進行解碼讀取。將字符串轉換字節的方式 //s.getBytes("utf-8")表示將一字節數組寫進去 // out.write(s.getBytes("utf-8"));//在這個地方進行設置編碼 byte[] b = s.getBytes("utf-8"); for(int i=0; i<b.length; i++){ out.write(b[i]); } out.close(); } } 最後,我們用字符流的方式將內容寫入文件。不需要轉碼操作。請看如下代碼。 import java.io.*; public class WriteFile{ public static void main(String [] args){ String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); Writer w = new FileWriter(f); String str = "hello"; w.write(str); w.close(); } } 例8.InputStreamReaderUTF8.java import java.io.FileInputStream; import java.io.InputStreamReader; /** * 功能:用字符char的方式讀出gbk.txt文件中內容,並以utf-8的方式讀取 。理解讀取文件中的內容解碼 utf-8方式 * 將字節流轉換字符流的方式進行讀取文件中的內容 * @author Administrator * */ public class InputStreamReaderUTF8 { public static void main(String []arg) throws Exception{ isr(); } public static void isr() throws Exception{ //指定以utf-8的方式創建一個輸入流.目的在於注意區分,如果創建文件時指定了gbk編碼方式,而讀取時如果指定別的編碼方式,則會產生亂碼。 InputStreamReader isr = new InputStreamReader(new FileInputStream("utf-8.txt"),"utf-8"); //在這個地方進行解碼,將字節流轉換爲字符流 //unicode:一個字符佔2個字節,1個字節佔8位 //因爲知道了gbk.txt中的內容少,故在此用char來讀取 char [] buf = new char[10]; int len = isr.read(buf); System.out.println("utf-8.txt文件內容長度爲:"+len+"個字符"); String string = new String(buf,0,len); System.out.println(string); isr.close(); } } 與例8完成相同的讀取文件內容功能,但用了不同的實現方式: import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * 功能:完成解碼與編碼,以字節流的方式讀取文件內容 * @author Administrator * */ public class ReadFile { public static void main(String[] args) throws Exception { //假定utf-8.txt文件的編碼方式是以utf-8方式編碼的 String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[1030]; //將文件的內容讀到b數組中 in.read(b); in.close(); //如果源文件的編碼方式是utf-8方式,讀取時,必須指定以同樣的編碼方式進行解碼。否則就會亂碼 System.out.println(new String(b,"utf-8")); //在這個地方進行解碼 /*用下面的方式進行顯示,就會有亂碼 System.out.println(new String(b,"gbk")); System.out.println(new String(b)); */ } } 上述程序代碼讀的時候,會有大量的空格,我們可以利用in.read(b);的返回值來設計程序。如下: import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * 功能:完成解碼與編碼。以字節流的方式讀取文件內容 * @author Administrator * */ public class ReadFile { public static void main(String[] args) throws Exception { //假定utf-8.txt文件的編碼方式是以utf-8方式編碼的 String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[1030]; int len = in.read(b); in.close(); System.out.println("讀取文件的長度爲:"+len); //如果源文件的編碼方式是utf-8方式,讀取時,必須指定以同樣的編碼方式進行解碼。否則就會亂碼 System.out.println(new String(b,0,len,"utf-8")); //在這個地方進行解碼 /*用下面的方式進行顯示,就會有亂碼 System.out.println(new String(b,"gbk")); System.out.println(new String(b)); */ } } 仔細觀察上面的代碼可以看出,我們預先申請了一個指定大小空間。但是,有可能這個空間太小,有時候可能太大。我們更需要準確的大小,這樣可以節省空間。請看如下代碼: import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * 功能:完成解碼與編碼。以字節流的方式讀取文件內容。根據文件長度來創建數據大小 * @author Administrator * */ public class ReadFile { public static void main(String[] args) throws Exception { //假定utf-8.txt文件的編碼方式是以utf-8方式編碼的 String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); // byte[] b=new byte[1030]; //f.length();表示返回由此抽象路徑名錶示的文件的長度。(int)f.length();表示進行數據類型的轉換。 //定義一個不定長的字節數組。長度根據文件的長度來創建 byte [] b = new byte[(int)f.length()]; in.read(b); in.close(); System.out.println("文件的長度爲:"+f.length()); //如果源文件的編碼方式是utf-8方式,讀取時,必須指定以同樣的編碼方式進行解碼。否則就會亂碼 System.out.println(new String(b,"utf-8")); //在這個地方進行解碼 /*用下面的方式進行顯示,就會有亂碼 System.out.println(new String(b,"gbk")); System.out.println(new String(b)); */ } } 再將上述代碼進行優化,一個字節一個字節地讀。更節省空間。看如下代碼: import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * 功能:完成解碼與編碼。以字節流的方式讀取文件內容。一個字節一個字節地讀 * @author Administrator * */ public class ReadFile { public static void main(String[] args) throws Exception { //假定utf-8.txt文件的編碼方式是以utf-8方式編碼的 String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); // byte[] b=new byte[1030]; //f.length();表示返回由此抽象路徑名錶示的文件的長度。(int)f.length();表示進行數據類型的轉換。 //定義一個不定長的字節數組。長度根據文件的長度來創建 byte [] b = new byte[(int)f.length()]; for ( int i = 0; i<b.length; i++){ b[i] = in.read(); } // in.read(b); in.close(); System.out.println("文件的長度爲:"+f.length()); //如果源文件的編碼方式是utf-8方式,讀取時,必須指定以同樣的編碼方式進行解碼。否則就會亂碼 System.out.println(new String(b,"utf-8")); //在這個地方進行解碼 /*用下面的方式進行顯示,就會有亂碼 System.out.println(new String(b,"gbk")); System.out.println(new String(b)); */ } } 再仔細想:當我們不知道文件有多大時,這種情況下,需要判斷是否讀到文件末尾。採用while循環。請看如下代碼: import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * 功能:完成解碼與編碼。以字節流的方式讀取文件內容。增加判斷,是否讀到文件末尾 * @author Administrator * */ public class ReadFile { public static void main(String[] args) throws Exception { //假定utf-8.txt文件的編碼方式是以utf-8方式編碼的 String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[1030]; int i= 0; int tmp = 0; while (( tmp=in.read())!= (-1)){ //整型強制轉換成byte型.每循環一次,字節數組中就增加一個元素 b[i++} = (byte)tmp; } //f.length();表示返回由此抽象路徑名錶示的文件的長度。(int)f.length();表示進行數據類型的轉換。 //定義一個不定長的字節數組。長度根據文件的長度來創建 /* byte [] b = new byte[(int)f.length()]; for ( int i = 0; i<b.length; i++){ b[i] = in.read(); }*/ // in.read(b); in.close(); System.out.println("文件的長度爲:"+f.length()); //如果源文件的編碼方式是utf-8方式,讀取時,必須指定以同樣的編碼方式進行解碼。否則就會亂碼 System.out.println(new String(b,"utf-8")); //在這個地方進行解碼 /*用下面的方式進行顯示,就會有亂碼 System.out.println(new String(b,"gbk")); System.out.println(new String(b)); */ } } 最後,以字符的方式從文件中讀取內容。看如下代碼: public class ReadFile{ public static void main(String [] args){ String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); char [] ch = new char[100]; Reader r = new FileReader(f); int count = r.read(ch); r.close(); System.out.println("讀入的長度爲:"+count); System.out.println("內容爲:"+new String(ch,0,count)); } } 有時候,我們還不知道文件到底有多大,所以,我們更宜採用循環的方式讀取(以字符方式讀取)。看如下代碼: public static void main(String [] args){ String fileName="D:"+File.separator+"Workspaces"+File.separator+"charset"+File.separator+"utf-8.txt"; File f=new File(fileName); char [] ch = new char[100]; Reader r = new FileReader(f); int tmp = 0; int i = 0; while ((tmp = r.read())!= (-1)){ ch[i++] = (char)tmp; } // int count = r.read(ch); r.close(); //System.out.println("讀入的長度爲:"+count); System.out.println("內容爲:"+new String(ch,0,count)); } }
延伸:文件的複製。基本思路還是從一個文件中讀入內容,邊讀邊寫入另一個文件,就是這麼簡單.請看ReadANDWrite.java import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.Writer; /* * 功能:將一個文件的內容讀出來後,將所有內容寫入到另一個文件。實現文件複製功能 */ public class ReadANDWrite { public static void main(String []args) throws Exception{ File file = new File("c:\\gbk.txt"); InputStream is = new FileInputStream(file); //OutputStream os = new FileOutputStream(new File("c:\\gbk-copy.txt")); Writer writer = new OutputStreamWriter(new FileOutputStream("c:\\gbk-copy.txt")); byte [] b = new byte[100]; //int len = is.read(b); int len; int i=0; //循環判斷是否讀到文件末尾 while ((len = is.read())!=(-1)) { // String s = new String(b); // writer.write(s); //設置計數器。看看總共有幾個字節 int c = i++; //按字節進行讀取,讀到一個字節後,賦值給字節數組變量 b[c] = (byte)len; System.out.println("b"+"["+i+"]"+":"+b[c]); } //將字節數組轉換成字符串,爲了不出現多餘的空格,必須需要接上加上相關參數,從哪開始讀,讀到哪結束 String s = new String(b,0,i); writer.write(s); System.out.println(new String(b,0,i)); //os.write((byte)is.read(b)); is.close(); writer.close(); //os.close(); } } |
javaIO心得
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.