JavaIO 流

 

1. File基本概念 

 

1). 基本概念

* File類用於表示文件(目錄)

* File類只用於表示文件(目錄)的信息(名稱、大小), 能新建、刪除、重命名文件和目錄,但不能用於文件內容的訪問,如果需要訪問文件內容本身,則需要使用輸入/輸出流

 

* File對象可以作爲參數傳遞給流的構造函數

2). 使用  
* 代碼示例
    File file=new File("E:\\javaio");

    * 文件路徑要用雙斜槓分割(在UNIX中,此字段爲‘/’,在Windows中,爲‘\\’)

 

    * 參數可以使用字符串、uri

 

3). File操作的注意: 
    * 定義文件路徑時,注意:可以用“/”或者“\\”。
    * 在寫入一個文件時,如果目錄下有同名文件將被覆蓋。

 

    * 在讀取文件時,必須保證該文件已存在,否則出異常

2 File常見的方法 
1). File的API使用  
  - exists()判斷文件/文件夾是否存在,返回值boolean類型  
  - 代碼示例

  File file=new File("E:\\javaio");
  System.out.println(file.exists());//存在爲true,不存在爲false           
  - mkdir()創建文件夾  
  - 代碼示例:
  //聲明文件對象
  File file=new File("E:\\javaio\\change");
    //判斷是否存在
    if(!file.exists()){
//創建的時候父目錄必須存在 即:E:\\javaio存在
boolean flag = file.mkdir();
//判斷是否創建成功
if(flag){
    System.out.println("創建成功");
}else{
    System.out.println("創建失敗");
}
    }
              
    - 代碼示例:

    //聲明文件對象
    File file=new File("E:\\javaio\\change.txt");
    //判斷是否存在
    if(!file.exists()){
//創建的時候父目錄必須存在 即:E:\\javaio存在
boolean flag = file.mkdir();
//判斷是否創建成功
if(flag){
    System.out.println("創建成功");
}else{
    System.out.println("創建失敗");
}
    }
  
  - mkdirs()創建多級文件夾  
  - 代碼示例:

   //聲明文件對象
    File file=new File("E:\\javaio\\change.txt");
    //判斷是否存在
    if(!file.exists()){
//父目錄不存在的情況
boolean flag = file.mkdirs();
//判斷是否創建成功
if(flag){
    System.out.println("創建成功");
}else{
    System.out.println("創建失敗");
}
    }  

  - delete() 刪除文件  
  - 代碼示例 : 

    file.delete();
  - isDirectory()判斷是否是目錄。返回值boolean類型,如果是目錄返回true,如果不是目錄或者目錄不存在返回false  
  - 代碼示例:


    file.isDirectory();
  - isFile()判斷是否是一個文件,同理上個方法  
  代碼示例:file.isFile();
    
  - createNewFile()創建文件  
  - 代碼示例  

  File file=new File("javaio\\日記.txt");
    try {
        //父目錄不存在,會出現IOException異常
        file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();

   }

 

  創建文件另一種方式 
   
  File file=new File("javaio","日記.txt");  

  - 直接輸出File對象  
  - 代碼示例:

  File file=new File("javaio\\change");
  System.out.println(file);
  - 結果:

  javaio\change

  - 返回的是File對象的toString();方法   
  - 內部源碼:
   
  //重寫Object中的toString方法
  public String toString() {
        return getPath();
  }

  - getAbsolutePath()返回的是File對象的路徑  

 

  - 代碼示例:

  File file=new File("javaio\\change");

  System.out.println(file.getAbsolutePath());

 

 

  - 結果:

 

 

  E:\EclipseWorkspase\day0805\javaio\change

 

  - getName()返回文件名字  
  - 代碼示例:

    File file1=new File("javaio\\change");
    File file2=new File("javaio\\日記.txt");
    System.out.println(file1.getName());
    System.out.println(file2.getName());
            
  - getParent()返回文件父目錄  
  - 代碼示例:

    File file=new File("javaio\\change");
    System.out.println(file.getParent());
    System.out.println(file.getParentFile().getAbsolutePath());//返回父目錄的絕對路徑

* 2. 遍歷File  
  * 案例1:遍歷指定目錄下的所有文件  
  * 工具類:

    public class FileUtils {
        public static void listDirectory(File dir) throws IOException{
            if(!dir.exists()){
                 throw new IllegalArgumentException(dir+"不存在");
            }
            if(!dir.isDirectory()){
                 throw new IllegalArgumentException(dir+"不是目錄");
            }
            /*
             * 遍歷指定文件下的文件名
             */
            //String[] fileNames=dir.list();
            //for(String fileName:fileNames){
            //          System.out.println(fileName);
            //}
             /*
              * 遍歷指定文件下的文件
              */
             //File[] files=dir.listFiles();
             //for(File file:files){
             //          System.out.println(file);
             //}
               /*
                * 採用遞歸的方式,遍歷指定目錄下的所有子文件
                */
               File[] files=dir.listFiles();
                   if(files!=null&&files.length>0){
                       for(File file:files){
                           if(file.isDirectory()){
                               System.out.println(file);
                               listDirectory(file);                                         
                    }else{
                       System.out.println(file);
                    }
                 }
              }
          }

  測試類:

  public class FileTest {
      public static void main(String[] args) throws IOException {
          File file=new File("E:\\javaio");
          FileUtils.listDirectory(file);

 

      }

   }

 

 3. 流基本概念 
 - Java中IO是以流爲基礎進行輸入輸出的,所有數據被串行化寫入輸出流,或者從輸入流讀入。
 - 流是一個很形象的概念,當程序需要讀取數據的時候,就會開啓一個通向數據源的流,這個數據源可以是文件,內存,或是網絡連接。類似的,當程序需要寫入數據的時候,就會開啓一個通向目的地的流。這時候你就可以想象數據好像在這其中“流”動一樣。 
 
3.1 流的分類

 

* 流向劃分:  

 

  - 輸入流:程序可以從中讀取數據的流。
  - 輸出流:程序能向其中寫入數據的流。

* 傳輸單位劃分:

  - 字節流:以字節爲單位傳輸數據的流
  - 字符流:以字符爲單位傳輸數據的流
  
* 按角色劃分:
  
  - 節點流:用於直接操作目標設備的流
  - 處理流:“連接”在已存在的流(節點流或處理流)之上,通過對數據的處理爲程序提供更爲強大的讀寫功能。

3.2 字節流 

* 字節流主要操作byte類型數據,以byte數組爲準,主要操作類有InputStream(字節輸入流)、OutputSteam(字節輸出流)由於IputStream和OutputStream都是抽象類。

* 1. 字節輸出流:OutputStream  
  * OutputStream是一個抽象類,是所有字節流輸出流的父類,要想使用它,必須通過子類來實例他  
  * OutputStream類的常用方法  
  
  1 、int write(int b)
  // 功能:將b的最低的一個字節寫入此輸入流,其他三個字節丟棄。
          
  2、int write(byte[] b)

 

  //功能:將指定的字節數組b寫入此輸入流

  3、int write(byte[] b, int off, int len)

 

 

  //功能:將指定byte數組中從偏移量off開始的len個字節寫入輸入流。

  4、flush()
  //功能:刷新此輸入流並強制寫出所有緩衝的輸出字節數。

  5、close()
  //功能:關閉輸出流,釋放這個流的相關資源。

 

 

  *  案例2:向一個名爲”hello.txt”的文本文件中寫一個“HelloWorld"

    public static void main(String[] args) throws IOException {

 

        File file=new File("hello.txt");
        OutputStream os=new FileOutputStream(file);
        String str="Hello World";
        byte[] b=str.getBytes();
        os.write(b);
        os.close();

 

        os.flus

    }  

 

 

* 2. 字節輸入流:InputStream
  * 與OutputStream類一樣,InputStream本身也是一個抽象類,是所有字節輸入流的子類,要想使用它,也必須依靠其子類。
  InputStream類的常用方法  

 

 

   1、int read() 

   //功能:讀取下一個字節的數據,並且返回讀到得數據,如果返回-1,則表示讀到輸入流的末尾。

 

   2、int read(byte[] b)
   //功能:從輸入流中讀取一定量的字節,並將其存儲在字節數組b中,
   //返回實際讀取的字節數,如果返回-1,則表示讀到輸入流的末尾。

   3、int read(byte[] b, int off, int len)
   //功能:將數據讀入一個字節數組,同時返回讀取的實際字節數,如果返回-1,
   //則表示讀到輸入流的末尾。off指定在數組b中存放數據的起始偏移位置,

 

   //len指定讀取的最大字節數。  

   4、available()

 

 

   //功能:返回此輸入流下一個方法調用可以不受阻塞地從此輸入流讀取或跳過的估計字節數

   5、close()
   //功能:關閉輸入流,釋放這個流的相關資源。

   * 案例3 :在上一個例子的基礎上我們從文本中讀取數據並且把它顯示在控制檯上  

 

 

    public static void main(String[] args) throws IOException {

        File file=new File("hello.txt");

 

        InputStream is = new FileInputStream(file);
        //只能讀取1024字節
        byte[] b=new byte[1024];
        is.read(b);
        is.close();
        System.out.println(new String(b));
    }
 * 如果以這種方式打印,我們可以看到雖然控制檯裏是打印出了文本文件中的內容,但是後面跟了很多空格,這是我們不需要的,對於這種情況我們有兩種解決方式 :
  
* 方法一:聲明字節數組的時候指定字節數組的長度爲文本內容的長度

 

byte[] b=new byte[(int)file.length()];

 

* 方式二:在將字節數組轉換成字符串的調用String(byte b,int off,int len)這個構造函數

 

System.out.println(new String(b,0,(int)file.length()));

備註:   

1. 思考以上兩種方式那個更好.  

2. 思考要是讀取漢字會是什麼樣子尼?  

 

* 3. 字節流緩衝流  
  增加緩衝流,對文件的讀取效率有很大的提高。  
  例如,單字節讀取相當於將一個缸裏的水,一滴一滴的送往另一個缸中;而緩衝讀取的話,相當於先攢一桶水,然後再倒入另一個缸中。  
  
  - BufferedInputStream  
    帶有緩衝區的字節輸入流,通常使用它可以提高我們的讀取效率  
    BufferedInputStream內部有一個緩衝區,默認大小爲8KB,每次調用read方法的時候,它首先嚐試從緩衝區裏讀取數據,若讀取失敗(緩衝區無可讀數據),則選擇從物理數據源(譬如文件)讀取新數據(這裏會嘗試儘可能讀取多的字節)放入到緩衝區中,最後再將緩衝區中的內容部分或全部返回給用戶.由於從緩衝區裏讀取數據遠比直接從物理數據源(譬如文件)讀取速度快,所以BufferedInputStream的效率很高!  
 源碼中構造函數:  
    public BufferedInputStream(InputStream in) {

 

this(in, DEFAULT_BUFFER_SIZE);

    }  

 

 

  - BufferedOutputStream  
    帶有緩衝區的字節輸出流,提高了寫入文件的效率  
   
   * 下面通過一個案例來進行演示  案例4:複製文件  

 

 

    public static void main(String[] args) throws IOException {

        File thisFile=new File("E:\\javaio\\1.mp3");

 

File copyFile=new File("E:\\javaio\\copyFile.mp3");
if(!thisFile.exists()){
    throw new IllegalArgumentException(thisFile+"未找到");
}
if(!copyFile.exists()){
    copyFile.createNewFile();
}
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(thisFile));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(copyFile));
byte[] b=new byte[8*1024];
int i;
while((i=bis.read(b, 0, b.length))!=-1){
    bos.write(b,0,i);
    bos.flush();
}
bis.close();
bos.close();
    }

 * 案例5:緩衝流的性能  
 * 通過複製1.mp3文件,計算兩種複製方式哪種更快  
 * 工具類:  

 public class CopyUtil {
    public static void copyFile(File file1,File file2) throws IOException{
        FileInputStream fis=new FileInputStream(file1);
        FileOutputStream fos=new FileOutputStream(file2);
        int i;
        while((i=fis.read())!=-1){
    fos.write(i);
        }
        fis.close();
        fos.close();
    }
    public static void copyBuffer(File file1,File file2)throws IOException{
        BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file1));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(file2));
        int i;
while((i=bis.read())!=-1){
    bos.write(i);
    bos.flush();
}

 

bis.close();

        bos.close();

    }

 

 

}

* 測試類:

 

 

public class CopyTest {

    public static void main(String[] args)throws IOException {

        File file1=new File("E:\\javaio\\1.mp3");

 

File file2=new File("E:\\javaio\\copy.mp3");                  
//BufferedInputStream
long bufStart=System.currentTimeMillis();
CopyUtil.copyBuffer(file1, file2);
long bufEnd=System.currentTimeMillis();
System.out.println("使用BufferedInputStream拷貝文件的時間爲:"+(bufEnd-bufStart)+"ms");
//FileInputStream
long fStart=System.currentTimeMillis();
CopyUtil.copyFile(file1, file2);
long fEnd=System.currentTimeMillis();
System.out.println("使用FileInputStream拷貝文件的時間爲:"+(fEnd-fStart)+"ms");

 

    }

}

 

輸出結果:

使用BufferedInputStream拷貝文件的時間爲:23290ms

 

使用FileInputStream拷貝文件的時間爲:36693ms

 

3.4 字符流 

 

字符流主要是用來處理文字的。Java採用16位的Unicode來表示字符串和字符,對應的字符流輸入和輸出分別稱爲Reader和Writer。

1. 字符輸出流:Writer  
  * Writer是一個字符流,它是一個抽象類,所以要使用它,也必須通過其子類來實例化它後才能使用它。
  * Writer類的常用方法  

    public abstract void close() throws IOException //關閉輸出流
    public void write(String str) throws IOException //將字符串輸出
    public void write(char cbuf) throws IOException //將字符數組輸出
    public abstract void flush() throws IOExcetpion //強制性清空緩存

  * 案例6: 向一個文本文件中通過字符輸出流寫入數據

    public static void main(String[] args) throws IOException {
        File file=new File("world.txt");
        Writer writer=new FileWriter(file);
        String str="Hello World";
        writer.write(str);
        writer.flush();
        writer.close(); 

 

    }

 

* 2. 字符輸入流:Reader  
* Reader本身也是一個抽象類,同樣,如果使用它,我們需要通過其子類來實例化它纔可以使用它。  
* Reader類的常用方法  

    public abstract void close() throws IOException //關閉輸入流
    public int read() throws IOException //讀取內容,以數字的方式讀取
    public int read(char c) throws IOException //將內容讀到char數組,同時返回讀入的個數

  * 案例7
  在上面的基礎上把文本中的內容讀出來,並且顯示在控制檯上

    public static void main(String[] args) throws IOException {
        File file=new File("world.txt");
Reader read=new FileReader(file);
char[] c=new char[1024];
int len=0;
int temp=0;
while((temp=read.read())!=-1){
    c[len]=(char)temp;
    len++;
}
read.close();
System.out.println(new String(c,0,len));
    }
* 3. 字符緩衝流  
- BufferedReader   
從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。 可以指定緩衝區的大小,或者可使用默認的大小。大多數情況下,默認值足夠大。  
- readLine:  
提供了讀取文本行的能力  
**案例8:**讀取指定文本文件中第一行信息

public static void main(String[] args) throws IOException {
    BufferedReader br=new BufferedReader(new FileReader("E:\\javaio\\change.txt"));
        System.out.println(br.readLine());

 

}

- BufferedWriter   

 

將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。可以指定緩衝區的大小,或者接受默認的大小。   
newLine:    
它使用平臺自己的行分隔符概念,並非所有平臺都使用新行符 ('\n') 來終止各行。因此調用此方法來終止每個輸出行要優於直接寫入新行符。  
**案例9:**利用newLine方法將指定文本輸出換行文本

public static void main(String[] args) throws IOException {
    File file=new File("E:\\javaio\\bw.txt");
        if(!file.exists()){
            file.createNewFile();
        }
        BufferedWriter bw=new BufferedWriter(new FileWriter(file));
        bw.write("111111111");
        bw.write("222222222");
        bw.newLine();
        bw.write("333333333");
        bw.flush();
        bw.close();

 

 }

 

3.5 字節流與字符流的區別 
1. 字節流在操作的時候本身是不會用到緩衝區(內存)的,是與文件本身直接操作的,而字符流在操作的時候是使用到緩衝區的
![](img/2.png)  
2. 字節流在操作文件時,即使不關閉資源(close方法),文件也能輸出,但是如果字符流不使用close方法的話,則不會輸出任何內容,說明字符流用的是緩衝區,並且可以使用flush方法強制進行刷新緩衝區,這時才能在不close的情況下輸出內容
思考:那開發中究竟用字節流好還是用字符流好呢?
在所有的硬盤上保存文件或進行傳輸的時候都是以字節的方法進行的,包括圖片也是按字節完成,而字符是只有在內存中才會形成的,所以使用字節的操作是最多的

3.6 節點流 
* 節點流:可以從或向一個特定的地方(節點|數據源)讀寫數據。如 FileReader。 
* 常用的節點流:  

- 文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件進行處理的節點流。
- 字符串 StringReader StringWriter 對字符串進行處理的節點流。
- 數 組 ByteArrayInputStream ByteArrayOutputStreamCharArrayReader CharArrayWriter 對數組進行處理的節點流(對應的不再是文件,而是內存中的一個數組)。
- 管 道 PipedInputStream PipedOutputStream PipedReaderPipedWriter對管道進行處理的節點流。
- 父 類 InputStream OutputStream Reader Writer

3.7 處理流 

處理流:是“連接”在已存在的流(節點流或處理流)之上,通過對數據的處理爲程序提供更爲強大的讀寫功能。  
常用的處理流:  

  - 緩衝流:BufferedInputStrean BufferedOutputStream BufferedReader BufferedWriter增加緩衝功能,避免頻繁讀寫硬盤。
  - 轉換流:InputStreamReader OutputStreamReader實現字節流和字符流之間的轉換。
  - 數據流 DataInputStream DataOutputStream 等-提供將基礎數據類型寫入到文件中,或者讀取出來。
  

 

* 流的方向 是相對於我們的應用程序的。

 

 

*輸入流:程序要做讀取操作
*輸出流:程序要寫入信息到數據流

 

 

* 字節流和字符流的區別

*字節流可以操作任意類型的數據類型文件。我們一般用它操作二進制數據文件。

 

*字符流可以操作字符單位的數據流。一般指文本文件。

* 流的關閉問題。
#####JDK1.6前標準寫法。
    finally {
        try {
    fis.close();
} catch (IOException e) {
    e.printStackTrace();
}
    }

* jDK 1.7以後不用寫。因爲流對象實現了Closeable接口,只要將代碼放到try塊中。就能關閉了,就可以不寫close()了。
*  6 參考資料 
《java從入門到精通》  第三版

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章