2.熟悉Java基本類庫系列——Java IO 類庫

來源:互聯網
上載者:User

標籤:

Java中常用的IO操作基本上可以分為四大部分,分別是:File類操作、RandomAccessFile類操作、位元組流操作、字元流操作。只要熟練掌握了本文中所列舉的所有例子,基本上對於Java的IO流操作就可以說是掌握了。

下面將以JUnit測試案例的方式,用一個個例子的方式列出這四大部分中常用的操作例子。

一、File類操作

File類操作定義了最基本的、與作業系統的穩健系統相關的操作,可以對檔案夾、檔案進行一系列的操作。

 1、常用的一些用法

       //1.兩個常量@Test public void twoConstant(){//輸出: ‘/‘  ‘:‘System.out.println(File.separator); System.out.println(File.pathSeparator);}//2.建立新檔案@Test public void createFile(){File f = new File("hello");try{f.createNewFile();System.out.println("建立了檔案:" + f.getAbsolutePath());}catch(Exception e){e.printStackTrace();}}//3.建立一個檔案夾@Test public void createFolder(){try{File file = new File("HelloFolder");//當一個目錄下既沒有該名字對應的目錄和檔案時,才能建立該檔案夾if(!file.isDirectory() && !file.isFile()){file.mkdir();//file.mkdirs(); //如果上級目錄不存在,那麼一併建立上級目錄}else{System.out.println("已存在該名稱的檔案或檔案夾");}}catch(Exception e){e.printStackTrace();}}//4.刪除一個檔案@Test public void deleteFile(){try{File file = new File("hello");if(file.exists()){file.delete();}else{System.out.println("檔案不存在");}}catch(Exception e){e.printStackTrace();}}//5.刪除一個檔案夾(與刪除檔案一樣)@Test public void deleteFolder(){try{File file = new File("HelloFolder");if(file.exists()){file.delete();}else{System.out.println("該檔案夾不存在");}}catch(Exception e){e.printStackTrace();}}//6.擷取指定目錄下所有檔案的檔案名稱(包括隱藏檔案和檔案夾)@Test public void getAllFileName(){try{File folder = new File(".");  //目前的目錄String[] fileStrs = folder.list();for(String str : fileStrs){System.out.print(str + " ");}}catch(Exception e){e.printStackTrace();}}//7.擷取指定目錄下所有檔案的路徑@Test public void getAllFilePath(){try{File folder = new File(".");  //目前的目錄File[] files = folder.listFiles();for(File file : files){System.out.println(file.getCanonicalPath());}}catch(Exception e){e.printStackTrace();}}    

2、列印指定目錄下的所有檔案(遞迴調用)

package com.chanshuyi.io;/** * 列出指定目錄的全部內容 * */import java.io.*;class ListAllFile{    public static void main(String[] args) {        File f = new File(".");        print(f);    }        //遞迴列印    public static void print(File f){    if(f != null){    if(f.isDirectory()){    File[] fileArray = f.listFiles();    if(fileArray != null){    for(int i = 0; i < fileArray.length; i++){    print(fileArray[i]);    }    }    }else{    System.out.println(f);    }    }    }} 

二、RandomAccessFile類操作

RandomAccessFile類可以對檔案進行隨機訪問,比如可以指定讀寫指標到某一個位元組處,也可以讀寫指標指定跳過指定位元組數。簡單地說,RandomAccessFile類提供了許多方法,使得我們可以對檔案進行更加細緻的讀寫操作。

//8.隨機讀寫檔案類@Test public void operateRandom(){try{//1.跳過兩個位元組讀取檔案內容//檔案內容是:Hello, this is demo File.RandomAccessFile randomRW = new RandomAccessFile(new File("demo.txt"), "rw"); randomRW.skipBytes(2);  //跳過兩個位元組,即跳過了‘he‘兩個英文字元(一個英文字元佔用1個位元組)byte b[] = new byte[100];int length = randomRW.read(b);System.out.println("總共讀取了" + length + "個位元組,讀取的內容是:" + new String(b));//總共讀取了23個位元組,讀取的內容是:llo, this is demo File.//2.將讀寫指標跳迴文件頭重新讀取randomRW.seek(0);length = randomRW.read(b);System.out.println("總共讀取了" + length + "個位元組,讀取的內容是:" + new String(b));//總共讀取了25個位元組,讀取的內容是:Hello, this is demo File.//3.擷取讀寫指標所在地址long pointer = randomRW.getFilePointer();System.out.println("檔案指標地址:" + pointer);  //檔案指標地址:25randomRW.seek(2);pointer = randomRW.getFilePointer();System.out.println("檔案指標地址:" + pointer);//檔案指標地址:2randomRW.seek(77);pointer = randomRW.getFilePointer();System.out.println("檔案指標地址:" + pointer);//檔案指標地址:77randomRW.close();}catch(Exception e){e.printStackTrace();}

三、位元組流讀寫

FileInputStream / FileOutputStream - 實現了對檔案的讀寫操作

ObjectInpuStream / ObjectOutputStream - 實現了對序列化對象的讀寫操作

ByteArrayInputStream / ByteArrayOutputStream - 實現了對位元組數組的讀寫操作

PipedInputStream / PipedOutputStream - 實現不同線程之間的通訊

SequenceInputStream - 實現不同輸入資料流的合并(此對象沒有對應的OutputStream類)

BufferedInputStream / BufferedOutputStream - 實現讀寫緩衝層

1、位元組流讀取 - byte(表示讀取的資料類型是byte或byte[])

//15.位元組流讀取 - byte@Test public void readByte(){try{File file = new File("hello.txt");InputStream fos = new FileInputStream(file);byte[] bytes = new byte[fos.available()];fos.read(bytes);String str = new String(bytes);System.out.println("檔案內容是:\n" + str);fos.close();}catch(Exception e){e.printStackTrace();}}

2、位元組流讀取(緩衝) - byte

//位元組流讀取(緩衝) - byte@Test public void writeByteWithBuffere(){try{File file = new File("hello1.txt");OutputStream fos = new FileOutputStream(file);BufferedOutputStream out = new BufferedOutputStream(fos);out.write("你好\n".getBytes());out.write("吃飯了麼!".getBytes());out.flush();fos.close();}catch(Exception e){e.printStackTrace();}}

3、位元組流寫入 - byte

//17.位元組流寫入 - byte@Test public void writeByte(){try{File file = new File("hello.txt");OutputStream fos = new FileOutputStream(file);fos.write("Hello Mac.\n你好,Mac.".getBytes());fos.close();}catch(Exception e){e.printStackTrace();}}

4、位元組流寫入(緩衝) - byte

//18.位元組流寫入(緩衝) - byte@Test public void writeByteWithBuffer(){try{File file = new File("hello.txt");OutputStream fos = new FileOutputStream(file);BufferedOutputStream bos = new BufferedOutputStream(fos);bos.write("Hello Mac.\n你好,Mac.".getBytes());bos.close();fos.close();}catch(Exception e){e.printStackTrace();}}

如果你仔細敲過上面4個例子的代碼你會發現,其實好像位元組流的讀取和寫入,好像加了緩衝和沒加緩衝,它們的代碼好像都差不多啊,至少再寫入資料的時候是一樣的。而字元流的讀取在加了緩衝層之後,至少還能直接讀取整行資料,字元流的寫入加了緩衝之後,可以寫入分行符號。那位元組流的緩衝究竟有什麼必要性呢?

確實,從代碼以及其方法上看,其實他們並沒有什麼區別,但是從官方的API文檔來看,緩衝最重要的一個地方就是減少程式對於磁碟的IO次數。加了緩衝的程式再讀取的時候會一次性讀取很多個位元組,之後提供給程式使用,但如果你不加緩衝,那麼程式就只會讀取代碼中指定的位元組數。這在你一個位元組一個位元組從檔案中讀取資料的時候,其差別就凸現出來了。如果你沒有使用緩衝進行資料讀取,那麼你每讀一個位元組的資料,程式就去磁碟讀取一次檔案,這樣會造成磁碟的頻繁IO讀取,減少磁碟的壽命。

5、ObjectInputStream / ObjectOutputStream - 序列化一個對象

要被序列化的POJO對象:

package com.chanshuyi.io.po;import java.io.Serializable;public class Student implements Serializable{/** * 序列化ID */private static final long serialVersionUID = 7288449352920655248L;private String name;private int age;private String phone;public Student(){}public Student(String name, int age, String phone){this.name = name;this.age = age;this.phone = phone;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String toString(){return name + "," + age + "," + phone;}}

被序列化的POJO對象需要實現Serializable介面。

序列化對象方法:

//20.ObjectOutputStream - 序列化對象 - 將對象屬性序列化儲存@Test public void serialized(){try{Student std = new Student("Tommy", 13, "18923923876");ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("StudentObject.obj"));oos.writeObject(std);oos.close();}catch(Exception e){e.printStackTrace();}}

還原序列化對象方法:

//21.ObjectInputStream - 還原序列化對象 - 讀取序列化後的對象@Test public void deSerialized(){try{ObjectInputStream ois = new ObjectInputStream(new FileInputStream("StudentObject.obj"));Student std = (Student)ois.readObject();System.out.println(std);ois.close();}catch(Exception e){e.printStackTrace();}}

6、ByteArrayInputStream / ByteArrayOutputStream - 操作記憶體位元組資料

//19.ByteArrayInputStream - 記憶體操作流 - 將記憶體資料轉化為流@Test public void random2Stream(){try{String str = "你好";ByteArrayInputStream input = new ByteArrayInputStream(str.getBytes());ByteArrayOutputStream output = new ByteArrayOutputStream();int temp = 0;while((temp = input.read()) != (-1)){char ch = (char)temp;output.write(Character.toLowerCase(ch));}String outputStr = output.toString();input.close();output.close();System.out.println(outputStr);}catch(Exception e){e.printStackTrace();}}

7、PipedInputStream / PipedOutputStream - 實現進程間的管道通訊

接收者:

package com.chanshuyi.io.pineStream;import java.io.PipedInputStream;/** * 管道流 - 接收者 * @author yurongchan * */public class Receiver implements Runnable{private PipedInputStream in = null;public Receiver(){in = new PipedInputStream();}public PipedInputStream getIn(){return this.in;}public void run(){byte[] b = new byte[1000];int length = 0;try{length = this.in.read(b);}catch(Exception e){e.printStackTrace();}System.out.println("接收到的訊息:" + new String(b, 0, length));}}

寄件者:

package com.chanshuyi.io.pineStream;import java.io.PipedOutputStream;/** * 管道流 - 寄件者 * @author yurongchan * */public class Send implements Runnable{private PipedOutputStream out = null;public Send(){out = new PipedOutputStream();}public PipedOutputStream getOut(){return this.out;}public void run(){String msg = "Hello, I‘m outputer.\n你好,我是寄件者。";try{out.write(msg.getBytes());out.close();}catch(Exception e){e.printStackTrace();}}}

測試方法:

//22.PipedInputStream - 在不同線程之間進行通訊@Test public void pipeContact(){try{Send send = new Send();Receiver receiver = new Receiver();try{send.getOut().connect(receiver.getIn()); }catch(Exception e){e.printStackTrace();}new Thread(send).start();new Thread(receiver).start();}catch(Exception e){e.printStackTrace();}}

8、SequenceInputStream - 合并輸入資料流

//23.SequenceInputStream - 合并幾個輸入資料流@Test public void sequenceInputStream(){try{InputStream is1 = new FileInputStream(new File("sequence1.txt"));InputStream is2 = new FileInputStream(new File("sequence2.txt"));OutputStream os = new FileOutputStream(new File("sequence3.txt"));SequenceInputStream sis = new SequenceInputStream(is1, is2);int temp = 0;while((temp = sis.read()) != -1){os.write(temp);}sis.close();is1.close();is2.close();os.close();}catch(Exception e){e.printStackTrace();}}

之後開啟sequence3.txt會發現,1、2文本中的內容都到了sequence3.txt中了。

四、字元流讀寫

字元流的讀寫實際上還是基於位元組流實現的,而且數組儲存時更多是以位元組為單位儲存,因此更多時候還是使用位元組流進行讀寫操作。

因此對於字元流的讀寫,我們只需要掌握常用的幾個操作即可。

InputStreamReader / OutputStreamWriter - 實現字元流的讀寫

BufferedReader / BufferedWriter - 實現字元流的緩衝層

FileReader / FileWriter - 字元流的工具類

1、字元流讀取 - char(表示讀取的資料類型是char或char[]) 

//9.字元流讀取 - char@Test public void writeChar(){try{    InputStreamReader reader = new InputStreamReader(new FileInputStream("OutputStreamWriter.txt"));    char[] chars = new char[1000];    int length = reader.read(chars);    System.out.println("一共讀取了" + length + "個字元,內容是:" + new String(chars));    reader.close();  }catch(Exception e){    e.printStackTrace();  }}

2、字元流讀取(緩衝) - char

//10.字元流讀取(緩衝)@Test public void writeCharWithBuffer(){try{InputStreamReader isr = new InputStreamReader(new FileInputStream("BufferedWriter.txt"));BufferedReader reader = new BufferedReader(isr);String str = ""; while((str = reader.readLine()) != null && str.length() != 0){System.out.println(str);}reader.close();}catch(Exception e){e.printStackTrace();}}

3、字元流寫入 - char / char[] / String

//11.字元流寫入 @Test public void readChar(){try{  OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("OutputStreamWriter.txt"));  writer.write("AllFileTest.fileReadUtil -> 字元流寫入檔案");  writer.close();}catch(Exception e){  e.printStackTrace();}}

4、字元流的寫入(緩衝)- char/ String

//12.字元流寫入(緩衝)@Test public void readCharWithBuffer(){try{OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("BufferedWriter.txt"));BufferedWriter writer = new BufferedWriter(osw);writer.write("AllFileTest.fileReadUtil -> 字元流寫入檔案");writer.newLine();//換行writer.write("第二行");writer.close();}catch(Exception e){e.printStackTrace();    }}

總結一下上面四種方式的字元流寫入寫出,我們會發現兩個規律,一個是讀寫規律,一個是緩衝層的規律:

· 讀寫規律。字元流的讀取,其讀取的資料都是char(字元型)的單個或者數組。而字元流的寫入除了可以寫入單個或多個char類型的字元歪,還可以直接寫入String(字串)類型。

· 緩衝層規律。字元流的讀寫,增加了緩衝層之後的一個明顯區別就是:加了緩衝層(Buffer)之後,字元流讀取可以實現整行讀取(readLine),而字元流寫入可以實現寫入分行符號(writeLine)。

5、檔案讀取工具類

//13.FileReader - 檔案讀取工具類(這是加了緩衝的。但也可以不加緩衝)@Test public void fileReadUtil(){    try{FileReader fr = new FileReader(new File("demo.txt"));BufferedReader reader = new BufferedReader(fr);String str = "";while((str = reader.readLine()) != null && str.length() != 0){System.out.println(str);}reader.close();}catch(Exception e){e.printStackTrace();}}

將這個例子與上面的第2個例子,即加了緩衝的字元流讀取例子相比,你會發現其實這兩個例子的區別就只是聲明FileReader、InputStreamReader的區別而已。聲明FileReader只需要再加上File型別參數即可,而聲明InputStreamReader則需要再加上一個FileInputStream類,之後才能跟上File類型的參數。因此,我們才說FileReader是一個檔案讀取工具類。

6、檔案寫入工具類

//14.FileWriter - 檔案寫入工具類(這是加了緩衝的。但也可以不加緩衝)@Test public void fileWriteUtil(){try{FileWriter fw = new FileWriter(new File("FileWriteUtil1.txt"));BufferedWriter writer = new BufferedWriter(fw);writer.write("HelloMan1");writer.newLine();writer.write("HelloMan2");writer.close();}catch(Exception e){e.printStackTrace();}}

同樣的,其實FileWriter與OutputStreamWriter也只是聲明上的區別而已。

五、其他

這裡會收集一些不怎麼常用,但是有時也會用到的例子,遇到的時候可以快速的查詢到。

1、追加新的內容 

//9.位元組流 - 追加新內容//無論是位元組流還是字元流,要追加新的內容都是再FileOutputStream中指定第二個參數為true@Test public void appendFile(){try{File file = new File("hello.txt");OutputStream fos = new FileOutputStream(file, true);String str = "\n這是新增加的內容";fos.write(str.getBytes());fos.close();}catch(Exception e){e.printStackTrace();}}

2、類比列印流輸出資料

//18.列印流 - 類比列印的方式輸出資料@Test public void printStream(){try{PrintStream print = new PrintStream(new FileOutputStream(new File("PrintStream.txt")));print.println(true);print.println("您好,我是列印輸出資料流");print.printf("名字:%s.年齡:%d", "Tom", 32); //格式化輸出print.close();//這裡的資料要再PrintStream.txt檔案中才能看到}catch(Exception e){e.printStackTrace();}}

3、使用OutputStream向螢幕輸出內容

//19.使用OutputStream向螢幕輸出內容@Test public void systemOutStream(){try{OutputStream out = System.out;out.write("你好".getBytes());out.close();}catch(Exception e){e.printStackTrace();}}

4、標準輸出重新導向

//20.標準輸出重新導向@Test public void redirectOutput(){try{System.out.println("Print in the Screen. 你好");System.setOut(new PrintStream(new FileOutputStream(new File("RedirectOutput.txt"))));//下面的輸出都將重新導向到檔案中System.out.println("=== 重新導向後的輸出 ===");System.out.println("Hello, Eclipse in Mac.");}catch(Exception e){e.printStackTrace();}}

5、標準輸入重新導向

//21.標準輸入重新導向@Test public void redirectInput(){try{File file = new File("RedirectOutput.txt");if(!file.exists()){System.out.println("檔案不存在!");return;}else{System.setIn(new FileInputStream(file));byte b[] = new byte[1000];int length = System.in.read(b);System.out.println("讀入的內容為:" + new String(b, 0, length));}}catch(Exception e){e.printStackTrace();}}

6、錯誤輸出重新導向

//22.錯誤輸出重新導向@Test public void redirectErrOutput(){try{System.err.println("Print in the Screen. 你好");System.setErr(new PrintStream(new FileOutputStream(new File("RedirectErrOutput.txt"))));//下面的輸出都將重新導向到檔案中System.err.println("=== 重新導向後的錯誤輸出 ===");System.err.println("Hello, Eclipse in Mac.");}catch(Exception e){e.printStackTrace();}}

 

感謝以下博文的參考:

1、http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html

2、http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html

 

2.熟悉Java基本類庫系列——Java IO 類庫

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.