1. 程式人生 > 其它 >Flie類,位元組流,字元流

Flie類,位元組流,字元流

技術標籤:筆記java

一,file類

1.1 概述
java.io.File 類是檔案和目錄路徑名的抽象表示,主要用於檔案和目錄的建立、獲取和刪除等操作。
記住三個單詞:file:檔案、directory:資料夾/目錄、path:路徑

1.2 構造方法
public File(String pathname) :通過將給定的路徑名字串轉換為抽象路徑名來建立新的File例項。
public File(String parent, String child) :從父路徑名字串和子路徑名字串建立新的 File例項。
public File(File parent, String child) :從父抽象路徑名和子路徑名字串建立新的 File例項。
// 檔案路徑名
String pathName = "d:\\a.txt";
File file1 = new File(pathName);
// 檔案路徑名
String pathName2 = "d:\\a\\b.txt";
File file2 = new File(pathName2);
// 通過父路徑和子路徑字串
String parent = "d:\\a";
String child = "b.txt";
File file3 = new File(parent, child);
// 通過父級File物件和子路徑字串
File parentDir = new File("d:\\a"); String child = "b.txt"; File file4 = new File(parentDir, child);
注意:
1.一個File物件代表硬碟中實際存在的一個檔案或者目錄。 
2.無論該路徑下是否存在檔案或者目錄,都不影響File物件的建立。
3.由於不同系統,路徑分隔符使用不一樣,在windows中是"d:\a",linux是"d:/a",
可以使用靜態方法separator,路徑分隔符,windows是分號,linux是冒號,用靜態方法pathSeparator。
4.路徑不區分大小寫。

絕對路徑和相對路徑 
絕對路徑:從碟符開始的路徑,這是一個完整的路徑。 
相對路徑:相對於專案目錄的路徑,這是一個便捷的路徑,開發中經常使用。
public class FilePath {
    public static void main(String[] args) {
        // D盤下的a.java檔案
        File f1 = new File("D:\\a.java");
        System.out.println(f1.getAbsolutePath());
        // 專案下的a.java檔案
        File f2 = new File("a.java");
        System.out.println(f2.getAbsolutePath());
    }
}
1.3 常用方法
獲取功能的方法
public String getAbsolutePath() :返回此File的絕對路徑名字串。 
public String getPath() :將此File轉換為路徑名字串。 
public String getName() :返回由此File表示的檔案或目錄的名稱。 
public long length() :返回由此File表示的檔案的長度。
public class FileGet {
    public static void main(String[] args) {
        File f = new File("d:/a/b.java");
        System.out.println("檔案絕對路徑:"+f.getAbsolutePath());
        System.out.println("檔案路徑:"+f.getPath());
        System.out.println("檔名稱:"+f.getName());
        System.out.println("檔案長度:"+f.length()+"位元組");
    }
}

注意:
1.資料夾是沒有大小概念的,不能獲取資料夾的大小
2.如果構造方法中給出的路徑不存在,那麼length方法返回0
3.獲取的是構造方法指定的檔案的大小,以位元組為單位
4.無論路徑是絕對的還是相對的,getAbsolutePath方法返回的都是絕對路徑

判斷功能的方法
public boolean exists() :此File表示的檔案或目錄是否實際存在。 
public boolean isDirectory() :此File表示的是否為目錄。 
public boolean isFile() :此File表示的是否為檔案。
public class FileIs {
    public static void main(String[] args) {
        File f = new File("d:\\aaa\\bbb.java");
        File f2 = new File("d:\\aaa");
        // 判斷是否存在
        System.out.println("d:\\aaa\\bbb.java 是否存在:"+f.exists());
        System.out.println("d:\\aaa 是否存在:"+f2.exists());
        // 判斷是檔案還是目錄
        System.out.println("d:\\aaa 檔案?:"+f2.isFile());
        System.out.println("d:\\aaa 目錄?:"+f2.isDirectory());
    }
}

注意:
1.電腦的硬碟中只有檔案/資料夾,兩個方法是互斥
2.這兩個方法使用前提,路徑必須是存在的,否則都返回false

建立刪除功能的方法
public boolean createNewFile() :當且僅當具有該名稱的檔案尚不存在時,建立一個新的空檔案。 
public boolean delete() :刪除由此File表示的檔案或目錄。 
public boolean mkdir() :建立由此File表示的目錄。 
public boolean  mkdirs() :建立由此File表示的目錄,包括任何必需但不存在的父目錄。
public class FileCreateDelete {
    public static void main(String[] args) throws IOException {
        // 檔案的建立
        File f = new File("aaa.txt");
        System.out.println("是否存在:" + f.exists()); 
        System.out.println("是否建立:" + f.createNewFile());
        System.out.println("是否存在:" + f.exists());
        // 目錄的建立
        File f2 = new File("d:\\aaa");
        System.out.println("是否存在:" + f2.exists());
        System.out.println("是否建立:" + f2.mkdir()); 
        System.out.println("是否存在:" + f2.exists());
        // 建立多級目錄
        File f3 = new File("d:\\workspace");
        System.out.println(f3.mkdir());
        File f4 = new File("d:\\workspace");
        System.out.println(f4.mkdirs());
        // 檔案的刪除
        System.out.println(f.delete());
        // 目錄的刪除
        System.out.println(f2.delete());
        System.out.println(f4.delete());
    }
}
注意:
    1.delete方法是直接在硬碟刪除檔案/資料夾,不走回收站,刪除要謹慎
2.public boolean mkdir() :建立單級空資料夾,public boolean mkdirs() :既可以建立單級空資料夾,也可以建立多級資料夾

1.4 目錄的遍歷
public String[] list() :返回一個String陣列,表示該File目錄中的所有子檔案或目錄。 
public File[] listFiles() :返回一個File陣列,表示該File目錄中的所有的子檔案或目錄。
public class FileFor {
    public static void main(String[] args) {
        File dir = new File("d:\\workspace");
        //獲取當前目錄下的檔案以及資料夾的名稱。
        String[] names = dir.list();
        for(String name : names){
            System.out.println(name);
        }
        //獲取當前目錄下的檔案以及資料夾物件
        File[] files = dir.listFiles();
        for (File file : files) {
            System.out.println(file);
        }
    }
}

注意:
list方法和listFiles方法遍歷的是構造方法中給出的目錄,如果構造方法中給出的目錄的路徑不存在,會丟擲空指標異常,如果構造方法中給出的路徑不是一個目錄,也會丟擲空指標異常

1.5 遞迴列印多級目錄
分析:多級目錄的列印,就是目錄的巢狀。遍歷之前,無從知道到底有多少級目錄,所以我們還是要使用遞迴實現。(終止條件就是當前遍歷項是檔名)
public class DiGuiDemo2 {
    public static void main(String[] args) {
        // 建立File物件
        File dir = new File("D:\\workspace");
        // 呼叫列印目錄方法
        printDir(dir);
    }
    public static void printDir(File dir) {
        // 獲取子檔案和目錄
        File[] files = dir.listFiles();
        // 迴圈列印
        for (File file : files) {
            //對遍歷得到的File物件f進行判斷,判斷是否是資料夾
            if (file.isFile()) {
                // file是檔案,輸出檔案絕對路徑
                System.out.println("檔名:"+ file.getAbsolutePath());
            } else {
                // 是目錄,輸出目錄絕對路徑
                System.out.println("目錄:"+file.getAbsolutePath());
                // 繼續遍歷,呼叫printDir,形成遞迴
                printDir(file);
            }
        }
    }
}
1.6 檔案搜尋
搜尋 D:\workspace 目錄中的 .java 檔案。
分析: 
1.目錄搜尋,無法判斷多少級目錄,所以使用遞迴,遍歷所有目錄。 
2.遍歷目錄時,獲取的子檔案,通過檔名稱,判斷是否符合條件。
目錄不存在,會報NullPointerException異常
public class DiGuiDemo3 {
    public static void main(String[] args) {
        // 建立File物件
        File dir = new File("D:\\workspace");
        // 呼叫列印目錄方法
        printDir(dir);
    }
    public static void printDir(File dir) {
        // 獲取子檔案和目錄
        File[] files = dir.listFiles();
        // 迴圈列印
        for (File file : files) {
            if (file.isFile()) {
                // file是檔案,判斷檔名並輸出檔案絕對路徑
                if (file.getName().endsWith(".java")) {
                    System.out.println("檔名:" + file.getAbsolutePath());
                }
            } else {
                // 是目錄,繼續遍歷,形成遞迴
                printDir(file);
            }
        }
    }
}
1.7 檔案過濾器優化
java.io.FileFilter是一個介面,是File的過濾器。 該介面的物件可以傳遞給File類的listFiles(FileFilter ff) 作為引數, 介面中只有一個方法。
boolean accept(File pathname) :測試pathname是否應該包含在當前File目錄中,符合則返回true。
分析:
 1. 介面作為引數,需要傳遞子類物件,重寫其中方法。我們選擇匿名內部類方式,比較簡單。 
2. accept 方法,引數為File,表示當前File下所有的子檔案和子目錄。保留住則返回true,過濾掉則返回 false。
保留規則: 
1.要麼是.java檔案。 
2.要麼是目錄,用於繼續遍歷。 
3.通過過濾器的作用, listFiles(FileFilter) 返回的陣列元素中,子檔案物件都是符合條件的,可以直接列印。
程式碼實現:
過濾器FileFilter的實現類:
public class FileFilterImpl implements FileFilter{
    @Override
    public boolean accept(File pathname) {
        //如果pathname是一個資料夾,返回true,繼續遍歷這個資料夾
        if(pathname.isDirectory()){
            return true;
        }

        return pathname.getName().toLowerCase().endsWith(".java");
    }
}
測試類1public class Demo01Filter {
    public static void main(String[] args) {
        File file = new File("D:\\workspace");
        getAllFile(file);
    }
    public static void getAllFile(File dir){
        File[] files = dir.listFiles(new FileFilterImpl());//傳遞過濾器物件
        for (File f : files) {
            //對遍歷得到的File物件f進行判斷,判斷是否是資料夾
            if(f.isDirectory()){
                //f是一個資料夾,則繼續遍歷這個資料夾
                getAllFile(f);
            }else{
                //f是一個檔案,直接列印即可
                System.out.println(f);
            }
        }
    }
}
測試類2public class Demo02Filter {
    public static void main(String[] args) {
        File file = new File("D:\\workspace");
        getAllFile(file);
    }

    public static void getAllFile(File dir){
        //傳遞過濾器物件 使用匿名內部類
        File[] files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                //過濾規則,pathname是資料夾或者是.java結尾的檔案返回true
                return pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java");
            }
        });

        for (File f : files) {
            //對遍歷得到的File物件f進行判斷,判斷是否是資料夾
            if(f.isDirectory()){
                //f是一個資料夾,則繼續遍歷這個資料夾
                getAllFile(f);
            }else{
                //f是一個檔案,直接列印即可
                System.out.println(f);
            }
        }
    }
}

二,位元組流

1.1 什麼是IO
生活中,你肯定經歷過這樣的場景。當你編輯一個文字檔案,忘記了 ctrl+s ,可能檔案就白白編輯了。當你電腦 插入一個U盤,可以把一個視訊,拷貝到你的電腦硬盤裡。那麼資料都是在哪些裝置上的呢?鍵盤、記憶體、硬碟、外接裝置等等。我們把這種資料的傳輸,可以看做是一種資料的流動,按照流動的方向,以記憶體為基準,分為輸入input和輸出output,即流向記憶體是輸入流,流出記憶體的輸出流。
Java中I/O操作主要是指使用 java.io 包下的內容,進行輸入、輸出操作。輸入也叫做讀取資料,輸出也叫做作寫出資料。

1.2 IO的分類
  根據資料的流向分為:輸入流和輸出流。
輸入流 :把資料從其他裝置上讀取到記憶體中的流。 
輸出流 :把資料從記憶體中寫出到其他裝置上的流。
根據資料的型別分為:位元組流和字元流。
位元組流 :以位元組為單位,讀寫資料的流。 
字元流 :以字元為單位,讀寫資料的流。

1.3頂級父類
在這裡插入圖片描述位元組流
一切檔案資料(文字、圖片、視訊等)在儲存時,都是以二進位制數字的形式儲存,都一個一個的位元組,那麼傳輸時一樣如此。所以,位元組流可以傳輸任意檔案資料。在操作流的時候,我們要時刻明確,無論使用什麼樣的流物件,底層傳輸的始終為二進位制資料。

2.1 位元組輸出流OutputStream
java.io.OutputStream 抽象類是表示位元組輸出流的所有類的超類,將指定的位元組資訊寫出到目的地。它定義了位元組輸出流的基本共性功能方法。
public void close() :關閉此輸出流並釋放與此流相關聯的任何系統資源。 
public void flush() :重新整理此輸出流並強制任何緩衝的輸出位元組被寫出。 
public void write(byte[] b) :將 b.length位元組從指定的位元組陣列寫入此輸出流。 
public void write(byte[] b, int off, int len) :從指定的位元組陣列寫入 len位元組,從偏移量 off開始輸 出到此輸出流。 
public abstract void write(int b) :將指定的位元組輸出流。

2.2 FileOutputStream類
OutputStream 有很多子類,java.io.FileOutputStream 類是檔案輸出流,用於將資料寫出到檔案。
當你建立一個流物件時,必須傳入一個檔案路徑。《**該路徑下,如果沒有這個檔案,會建立該檔案**》。如果有這個檔案,會清空這個檔案的資料。

構造方法:
    FileOutputStream(String name):建立一個向具有指定名稱的檔案中寫入資料的輸出檔案流。
    FileOutputStream(File file):建立一個向指定 File 物件表示的檔案中寫入資料的檔案輸出流。
    引數:寫入資料的目的
        String name:目的地是一個檔案的路徑
        File file:目的地是一個檔案
    構造方法的作用:
        1.建立一個FileOutputStream物件
        2.會根據構造方法中傳遞的檔案/檔案路徑,建立一個空的檔案
        3.會把FileOutputStream物件指向建立好的檔案
public class FileOutputStreamConstructor  {
    public static void main(String[] args) throws FileNotFoundException {
        // 使用File物件建立流物件
        File file = new File("a.txt");
        FileOutputStream fos1 = new FileOutputStream(file);
        // 使用檔名稱建立流物件
        FileOutputStream fos2 = new FileOutputStream("D:\\a.txt");
    }
}
寫出位元組資料:
寫出資料的原理(記憶體-->硬碟):
        java程式-->JVM(java虛擬機器)-->OS(作業系統)-->OS呼叫寫資料的方法-->把資料寫入到檔案中

位元組輸出流的使用步驟(重點):
    1.建立一個FileOutputStream物件,構造方法中傳遞寫入資料的目的地
    2.呼叫FileOutputStream物件中的方法write,把資料寫入到檔案中
    3.釋放資源(流使用會佔用一定的記憶體,使用完畢要把記憶體清空,提供程式的效率)
1.寫出位元組: write(int b) 方法,每次可以寫出一個位元組資料,程式碼使用演示:
public class FOSWrite {
	    public static void main(String[] args) throws IOException {
	        //1.建立一個FileOutputStream物件,構造方法中傳遞寫入資料的目的地
	        FileOutputStream fos = new FileOutputStream("D:\\a.txt");
	        //2.呼叫FileOutputStream物件中的方法write,把資料寫入到檔案中
	        fos.write(97); 
	        fos.write(98); 
	        fos.write(99); 
	        // 關閉資源
	        fos.close();
	    }
	}
2.寫出位元組陣列: write(byte[] b) ,每次可以寫出陣列中的資料,程式碼使用演示:
public class FOSWrite {
    public static void main(String[] args) throws IOException {
        //1.建立一個FileOutputStream物件,構造方法中傳遞寫入資料的目的地
        FileOutputStream fos = new FileOutputStream("D:\\a.txt");
        //2.建立位元組陣列
        byte[] b = "Good Good Study".getBytes();
        //3.呼叫FileOutputStream物件中的方法write,把資料寫入到檔案中
        fos.write(b);
        // 關閉資源
        fos.close();
    }
}
3.寫出指定長度位元組陣列: write(byte[] b, int off, int len) ,每次寫出從off索引開始,len個位元組,程式碼使用演示:
public class FOSWrite {
	    public static void main(String[] args) throws IOException {
	        // 使用檔名稱建立流物件
	        FileOutputStream fos = new FileOutputStream("D:\\a.txt");
	        // 字串轉換為位元組陣列
	        byte[] b = "day day up".getBytes();
	        // 寫出從索引2開始,2個位元組
	        fos.write(b,2,2);
	        // 關閉資源
	        fos.close();
	    }
	}

注意:
①如果寫的第一個位元組是正數(0-127),那麼顯示的時候會查詢ASCII表
②如果寫的第一個位元組是負數,那第一個位元組會和第二個位元組,兩個位元組組成一箇中文顯示,查詢系統預設碼錶(GBK)

資料追加續寫:
經過以上的演示,每次程式執行,建立輸出流物件,都會清空目標檔案中的資料。如何保留目標檔案中資料,還能繼續新增新資料呢?
public FileOutputStream(File file, boolean append) : 建立檔案輸出流以寫入由指定的 File物件表示的檔案。 
public FileOutputStream(String name, boolean append) : 建立檔案輸出流以指定的名稱寫入檔案。
這兩個構造方法,引數中都需要傳入一個boolean型別的值, true 表示追加資料, false 表示清空原有資料。這樣建立的輸出流物件,就可以指定是否追加續寫了
public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileOutputStream fos = new FileOutputStream("D:\\a.txt",true);
        // 字串轉換為位元組陣列
        byte[] b = "day day up".getBytes();
        // 寫出從索引2開始,2個位元組
        fos.write(b,2,2);
        // 關閉資源
        fos.close();
    }
}

寫出換行
Windows系統裡,換行符號是 \r\n 。把以指定是否追加續寫了,程式碼使用演示:

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileOutputStream fos = new FileOutputStream("D:\\a.txt");
        // 定義位元組陣列
        byte[] words = {97,98,99,100,101};
        // 遍歷陣列
        for (int i = 0; i < words.length; i++) {
        // 寫出一個位元組
            fos.write(words[i]);
        // 寫出一個換行, 換行符號轉成陣列寫出
            fos.write("\r\n".getBytes());
        }
        // 關閉資源
        fos.close();
    }
}

注意:
回車符 \r 和換行符 \n :
回車符:回到一行的開頭(return)。
換行符:下一行(newline)。
系統中的換行:
Windows系統裡,每行結尾是回車+換行,即 \r\n ;
Linux系統裡,每行結尾只有換行,即 \n ;
Mac系統裡,每行結尾是 回車,即 \r 。

2.3 位元組輸入流InputStream
java.io.InputStream 抽象類是表示位元組輸入流的所有類的超類,可以讀取位元組資訊到記憶體中。它定義了位元組輸入流的基本共性功能方法。
public void close() :關閉此輸入流並釋放與此流相關聯的任何系統資源。  
public abstract int read() :從輸入流讀取資料的下一個位元組。 
public int read(byte[] b) :從輸入流中讀取一些位元組數,並將它們儲存到位元組陣列中。

2.4 FileInputStream類
java.io.FileInputStream 類是檔案輸入流,從檔案中讀取位元組。

構造方法:
FileInputStream(File file) : 通過開啟與實際檔案的連線來建立一個FileInputStream ,該檔案由檔案系統中的 File物件 file命名。 
FileInputStream(String name) : 通過開啟與實際檔案的連線來建立一個 
FileInputStream ,該檔案由檔案系統中的路徑名 name命名。 當你建立一個流物件時,必須傳入一個檔案路徑。該路徑下,如果沒有該檔案,會丟擲 FileNotFoundException 。 
public class FileInputStreamConstructor {
    public static void main(String[] args) throws FileNotFoundException {
        // 使用File物件建立流物件
        File file = new File("a.txt");
        FileInputStream fos1 = new FileInputStream(file);
        // 使用檔名稱建立流物件
        FileInputStream fos2 = new FileInputStream("b.txt");
    }
}
讀取資料的原理(硬碟-->記憶體)
    java程式-->JVM-->OS-->OS呼叫讀取資料的方法-->讀取檔案

位元組輸入流的使用步驟(重點):
    1.建立FileInputStream物件,構造方法中繫結要讀取的資料來源
    2.使用FileInputStream物件中的方法read,讀取檔案
    3.釋放資源

讀取位元組資料 
1.讀取位元組: read()方法,每次可以讀取一個位元組的資料,提升為int型別,讀取到檔案末尾,返回 -1,程式碼使用演示:
public class FISRead {
    public static void main(String[] args) throws IOException{
        // 使用檔名稱建立流物件
        FileInputStream fis = new FileInputStream("D:\\a.txt");
        // 讀取資料,返回一個位元組
        int b;
        // 迴圈讀取
        while ((b = fis.read())!=-1) {
            System.out.println((char)b);
        }
        // 關閉資源
        fis.close();
    }
}
2.使用位元組陣列讀取: read(byte[] b) ,每次讀取b長度個位元組到陣列中,返回讀取到的有效位元組個數,讀取到末尾時,返回 -1 。
明確兩件事情:
    1.方法的引數byte[]的作用?
        起到緩衝作用,儲存每次讀取到的多個位元組
        陣列的長度一般定義為1024(1kb)或者1024的整數倍
    2.方法的返回值int是什麼?
        每次讀取的有效位元組個數

String類的構造方法
    String(byte[] bytes) :把位元組陣列轉換為字串
    String(byte[] bytes, int offset, int length) 把位元組陣列的一部分轉換為字串 offset:陣列的開始索引 length:轉換的位元組個數
public class FISRead {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件.
        FileInputStream fis = new FileInputStream("D:\\a.txt");//112233a
        // 定義變數,作為有效個數
        int len;
        // 定義位元組陣列,作為裝位元組資料的容器
        byte[] b = new byte[2];
        // 迴圈讀取
        while ((len = fis.read(b)) != -1) {
            // 每次讀取後,把陣列變成字串列印
            System.out.println(new String(b));
        }
        // 關閉資源
        fis.close();
    }
}
錯誤資料 3 ,是由於最後一次讀取時,只讀取一個位元組 a ,陣列中,上次讀取的資料沒有被完全替換,所以要通過 len ,獲取有效的位元組,程式碼使用演示:
public class FISRead {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件.
        FileInputStream fis = new FileInputStream("D:\\a.txt");//112233a
        // 定義變數,作為有效個數
        int len;
        // 定義位元組陣列,作為裝位元組資料的容器
        byte[] b = new byte[2];
        // 迴圈讀取
        while ((len = fis.read(b)) != -1) {
            // 每次讀取後,把陣列變成字串列印
            System.out.println(new String(b,0,len));// len 每次讀取的有效位元組個數

        }
        // 關閉資源
        fis.close();
    }
}

三,字元流

當使用位元組流讀取文字檔案時,可能會有一個小問題。就是遇到中文字元時,可能不會顯示完整的字元,那是因為一箇中文字元可能佔用多個位元組儲存。所以Java提供一些字元流類,以字元為單位讀寫資料,專門用於處理文字檔案。(GBK:佔用兩個位元組;UTF-8:佔用3個位元組)

3.1 字元輸入流Reader
java.io.Reader 抽象類是表示用於讀取字元流的所有類的超類,可以讀取字元資訊到記憶體中。它定義了字元輸入流的基本共性功能方法。 
public void close() :關閉此流並釋放與此流相關聯的任何系統資源。 
public int read() : 從輸入流讀取一個字元。 
public int read(char[] cbuf) : 從輸入流中讀取一些字元,並將它們儲存到字元陣列 cbuf中。

3.2 FileReader類
java.io.FileReader 類是讀取字元檔案的便利類。構造時使用系統預設的字元編碼和預設位元組緩衝區。

注意:
1.字元編碼:位元組與字元的對應規則。Windows系統的中文編碼預設是GBK編碼表。 idea中UTF-8 
2.位元組緩衝區:一個位元組陣列,用來臨時儲存位元組資料。

構造方法:
FileReader(File file) : 建立一個新的 FileReader ,給定要讀取的File物件。 
FileReader(String fileName) : 建立一個新的 FileReader ,給定要讀取的檔案的名稱。

構造方法:
    FileReader(String fileName)
    FileReader(File file)
    引數:讀取檔案的資料來源
        String fileName:檔案的路徑
        File file:一個檔案
    FileReader構造方法的作用:
        1.建立一個FileReader物件
        2.會把FileReader物件指向要讀取的檔案

字元輸入流的使用步驟:
    1.建立FileReader物件,構造方法中繫結要讀取的資料來源
    2.使用FileReader物件中的方法read讀取檔案
    3.釋放資源


讀取字元資料
1.讀取字元: read 方法,每次可以讀取一個字元的資料,提升為int型別,讀取到檔案末尾,返回 -1 ,迴圈讀 取,程式碼使用演示:
public class FRRead {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileReader fr = new FileReader("D:\\a.txt");//112233a
        // 定義變數,儲存資料
        int b;
        // 迴圈讀取
        while ((b = fr.read()) != -1) {
            System.out.println((char) b);
        }
        // 關閉資源
        fr.close();
    }

}
2.使用字元陣列讀取: read(char[] cbuf) ,每次讀取b的長度個字元到陣列中,返回讀取到的有效字元個數, 讀取到末尾時,返回 -1 ,程式碼使用演示:

public class FRRead {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileReader fr = new FileReader("D:\\a.txt");//112233a
        // 定義變數,儲存有效字元個數
        int len;
        // 定義字元陣列,作為裝字元資料的容器
        char[] cbuf = new char[3];
        // 迴圈讀取
        while ((len = fr.read(cbuf)) != -1) {
            System.out.println(new String(cbuf));
        }
        // 關閉資源
        fr.close();
    }
}
獲取有效的字元改進,程式碼使用演示:
public class FRRead {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileReader fr = new FileReader("D:\\a.txt");//112233a
        // 定義變數,儲存有效字元個數
        int len;
        // 定義字元陣列,作為裝字元資料的容器
        char[] cbuf = new char[2];
        // 迴圈讀取
        while ((len = fr.read(cbuf)) != -1) {
            System.out.println(new String(cbuf,0,len));
        }
        // 關閉資源
        fr.close();
    }
}
3.3 字元輸出流Writer
java.io.Writer 抽象類是表示用於寫出字元流的所有類的超類,將指定的字元資訊寫出到目的地。它定義了位元組 輸出流的基本共性功能方法。
pulic void write(int c) 寫入單個字元。 
pulic void write(char[] cbuf) 寫入字元陣列。 
pulic abstract void write(char[] cbuf, int off, int len) 寫入字元陣列的某一部分,off陣列的開始索引,len 寫的字元個數。 
pulic void write(String str) 寫入字串。 
pulic void write(String str, int off, int len) 寫入字串的某一部分,off字串的開始索引,len寫的字元個 數。 
public void flush() 重新整理該流的緩衝。 
public void close() 關閉此流,但要先重新整理它。

3.4 FileWriter類
java.io.FileWriter 類是寫出字元到檔案的便利類。構造時使用系統預設的字元編碼和預設位元組緩衝區。

構造方法: 
FileWriter(File file) :建立一個新的 FileWriter,給定要讀取的File物件。 
FileWriter(String fileName) :建立一個新的 FileWriter,給定要讀取的檔案的名稱。

構造方法:
    FileWriter(File file)根據給定的 File 物件構造一個 FileWriter 物件。
    FileWriter(String fileName) 根據給定的檔名構造一個 FileWriter 物件。
    引數:寫入資料的目的地
        String fileName:檔案的路徑
        File file:是一個檔案

構造方法的作用:
        1.會建立一個FileWriter物件
        2.會根據構造方法中傳遞的檔案/檔案的路徑,建立檔案
        3.會把FileWriter物件指向建立好的檔案
字元輸出流的使用步驟(重點):
    1.建立FileWriter物件,構造方法中繫結要寫入資料的目的地
    2.使用FileWriter中的方法write,把資料寫入到記憶體緩衝區中(字元轉換為位元組的過程)
    3.使用FileWriter中的方法flush,把記憶體緩衝區中的資料,重新整理到檔案中
    4.釋放資源(會先把記憶體緩衝區中的資料重新整理到檔案中)
public class FileWriterConstructor {
    public static void main(String[] args) throws IOException {
        // 使用File物件建立流物件
        File file = new File("a.txt");
        FileWriter fw1 = new FileWriter(file);
        // 使用檔名稱建立流物件
        FileWriter fw2 = new FileWriter("b.txt");
    }
}
寫出資料 
	寫出字元: write(int b) 方法,每次可以寫出一個字元資料,程式碼使用演示:
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileWriter fw = new FileWriter("D:\\a.txt");
        // 寫出資料
        fw.write(97); // 寫出第1個字元
        fw.write('b'); // 寫出第2個字元
        fw.write('C'); // 寫出第3個字元
        fw.write(30000); // 寫出第4個字元,中文編碼表中30000對應一個漢字。
        fw.close();//關閉流
    }
}
注意:關閉資源時,與FileOutputStream不同。如果不關閉,資料只是儲存到緩衝區,並未儲存到檔案。

關閉和重新整理
因為內建緩衝區的原因,如果不關閉輸出流,無法寫出字元到檔案中。但是關閉的流物件,是無法繼續寫出資料的。如果我們既想寫出資料,又想繼續使用流,就需要 flush 方法了。
flush :重新整理緩衝區,流物件可以繼續使用。 
close :先重新整理緩衝區,然後通知系統釋放資源。流物件不可以再被使用了。
程式碼使用演示:
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileWriter fw = new FileWriter("D:\\a.txt");
        // 寫出資料,通過flush
        fw.write('刷'); // 寫出第1個字元
        fw.flush();
        fw.write('新'); // 繼續寫出第2個字元,寫出成功
        fw.flush();
        // 寫出資料,通過close
        fw.write('關'); // 寫出第1個字元
        fw.close();
//        fw.write('閉'); // 繼續寫出第2個字元,【報錯】java.io.IOException: Stream closed
//        fw.close();
    }
}
寫出其他資料
1.寫出字元陣列 : write(char[] cbuf) 和 write(char[] cbuf, int off, int len) ,每次可以寫出字元陣列中的資料,用法類似FileOutputStream,程式碼使用演示:
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileWriter fw = new FileWriter("D:\\a.txt");
        // 字串轉換為位元組陣列
        char[] chars = "hello man".toCharArray();
        // 寫出從索引2開始,2個位元組。
        fw.write(chars,2,2); 
        // 關閉資源
        fw.close();
    }
}
2. 寫出字串: write(String str) 和 write(String str, int off, int len) ,每次可以寫出字串中的 資料,更為方便,程式碼使用演示:
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件
        FileWriter fw = new FileWriter("D:\\a.txt");
        // 字串
        String msg = "程式設計師";
        // 寫出從索引2開始,2個位元組。
        fw.write(msg, 2, 1);
        // 關閉資源
        fw.close();
    }
}

練習:修改程式碼,完成續寫和換行。

public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔名稱建立流物件,可以續寫資料
        FileWriter fw = new FileWriter("D:\\a.txt",true);
        // 寫出字串
        fw.write("hello");
        // 寫出換行
        fw.write("\r\n");
        // 寫出字串
        fw.write("man");
        // 關閉資源
        fw.close();
    }
}

注意:字元流,只能操作文字檔案,不能操作圖片,視訊等非文字檔案。當我們單純讀或者寫文字檔案時使用字元流其他情況使用位元組流。