中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java File類的理解與使用

發布時間:2021-09-15 15:13:00 來源:億速云 閱讀:146 作者:chen 欄目:編程語言

這篇文章主要介紹“Java File類的理解與使用”,在日常操作中,相信很多人在Java File類的理解與使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java File類的理解與使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一、File類的使用

1. File類的理解

  • File類的一個對象,代表一個文件或一個文件目錄(俗稱:文件夾)。

  • File類聲明在java.io包下:文件和文件路徑的抽象表示形式,與平臺無關。

  • File類中涉及到關于文件或文件目錄的創建、刪除、重命名、修改時間、文件大小等方法,并未涉及到寫入或讀取文件內容的操作。如果需要讀取或寫入文件內容,必須使用IO流來完成。

  • 想要在Java程序中表示一個真實存在的文件或目錄,那么必須有一個File對象,但是Java程序中的一個File對象,可能沒有一個真實存在的文件或目錄。

  • 后續File類的對象常會作為參數傳遞到流的構造器中,指明讀取或寫入的"終點"。

2. File的實例化

2.1 常用構造器
  • File(String filePath)

  • File(String parentPath,String childPath)

  • File(File parentFile,String childPath)

代碼示例

@Test
public void test1() {
    //構造器1
    File file1 = new File("hello.txt");
    File file2 = new File("E:\\workspace_idea\\JavaSenic\\IO\\hello.txt");
    System.out.println(file1);
    System.out.println(file2);

    //構造器2
    File file3 = new File("E:\\workspace_idea\\JavaSenior", "hello.txt");
    System.out.println(file3);

    //構造器3
    File file4 = new File(file3, "hi.txt");
    System.out.println(file4);
}
2.2 路徑分類
  • 相對路徑:相較于某個路徑下,指明的路徑。

  • 絕對路徑:包含盤符在內的文件或文件目錄的路徑。

說明

  • IDEA中:

    • 如果使用JUnit中的單元測試方法測試,相對路徑即為當前Module下。

    • 如果使用main()測試,相對路徑即為當前的Project下。

  • Eclipse中:

    • 不管使用單元測試方法還是使用main()測試,相對路徑都是當前的Project下。

2.3 路徑分隔符
  • windows和DOS系統默認使用“\”來表示

  • UNIX和URL使用“/”來表示

  • Java程序支持跨平臺運行,因此路徑分隔符要慎用。

  • 為了解決這個隱患,File類提供了一個常量: public static final String separator。根據操作系統,動態的提供分隔符。

    舉例:

    //windows和DOS系統
    File file1 = new File("E:\\io\\test.txt");
    //UNIX和URL
    File file = new File("E:/io/test.txt");
    //java提供的常量
    File file = new File("E:"+File.separator+"io"+File.separator+"test.txt");


3. File類的常用方法

3.1 File類的獲取功能
  • public String getAbsolutePath():獲取絕對路徑

  • public String getPath() :獲取路徑

  • public String getName() :獲取名稱

  • public String getParent():獲取上層文件目錄路徑。若無,返回null

  • public long length() :獲取文件長度(即:字節數)。不能獲取目錄的長度。

  • public long lastModified() :獲取最后一次的修改時間,毫秒值

  • 如下的兩個方法適用于文件目錄:

  • public String[] list() :獲取指定目錄下的所有文件或者文件目錄的名稱數組

  • public File[] listFiles() :獲取指定目錄下的所有文件或者文件目錄的File數組

代碼示例:

@Test
public void test2(){
    File file1 = new File("hello.txt");
    File file2 = new File("d:\\io\\hi.txt");

    System.out.println(file1.getAbsolutePath());
    System.out.println(file1.getPath());
    System.out.println(file1.getName());
    System.out.println(file1.getParent());
    System.out.println(file1.length());
    System.out.println(new Date(file1.lastModified()));

    System.out.println();

    System.out.println(file2.getAbsolutePath());
    System.out.println(file2.getPath());
    System.out.println(file2.getName());
    System.out.println(file2.getParent());
    System.out.println(file2.length());
    System.out.println(file2.lastModified());
}
@Test
public void test3(){
    File file = new File("D:\\workspace_idea1\\JavaSenior");

    String[] list = file.list();
    for(String s : list){
        System.out.println(s);
    }

    System.out.println();

    File[] files = file.listFiles();
    for(File f : files){
        System.out.println(f);
    }

}
3.2 File類的重命名功能
  • public boolean renameTo(File dest):把文件重命名為指定的文件路徑

  • 注意:file1.renameTo(file2)為例:要想保證返回true,需要file1在硬盤中是存在的,且file2不能在硬盤中存在。

代碼示例:

@Test
public void test4(){
    File file1 = new File("hello.txt");
    File file2 = new File("D:\\io\\hi.txt");

    boolean renameTo = file2.renameTo(file1);
    System.out.println(renameTo);

}
3.3 File類的判斷功能
  • public boolean isDirectory():判斷是否是文件目錄

  • public boolean isFile() :判斷是否是文件

  • public boolean exists() :判斷是否存在

  • public boolean canRead() :判斷是否可讀

  • public boolean canWrite() :判斷是否可寫

  • public boolean isHidden() :判斷是否隱藏

代碼示例:

@Test
public void test5(){
    File file1 = new File("hello.txt");
    file1 = new File("hello1.txt");

    System.out.println(file1.isDirectory());
    System.out.println(file1.isFile());
    System.out.println(file1.exists());
    System.out.println(file1.canRead());
    System.out.println(file1.canWrite());
    System.out.println(file1.isHidden());

    System.out.println();

    File file2 = new File("d:\\io");
    file2 = new File("d:\\io1");
    System.out.println(file2.isDirectory());
    System.out.println(file2.isFile());
    System.out.println(file2.exists());
    System.out.println(file2.canRead());
    System.out.println(file2.canWrite());
    System.out.println(file2.isHidden());

}
3.4 Flie類的創建功能
  • 創建硬盤中對應的文件或文件目錄

  • public boolean createNewFile() :創建文件。若文件存在,則不創建,返回false

  • public boolean mkdir() :創建文件目錄。如果此文件目錄存在,就不創建了。如果此文件目錄的上層目錄不存在,也不創建。

  • public boolean mkdirs() :創建文件目錄。如果此文件目錄存在,就不創建了。如果上層文件目錄不存在,一并創建

代碼示例:

@Test
public void test6() throws IOException {
    File file1 = new File("hi.txt");
    if(!file1.exists()){
        //文件的創建
        file1.createNewFile();
        System.out.println("創建成功");
    }else{//文件存在
        file1.delete();
        System.out.println("刪除成功");
    }


}
@Test
public void test7(){
    //文件目錄的創建
    File file1 = new File("d:\\io\\io1\\io3");

    boolean mkdir = file1.mkdir();
    if(mkdir){
        System.out.println("創建成功1");
    }

    File file2 = new File("d:\\io\\io1\\io4");

    boolean mkdir1 = file2.mkdirs();
    if(mkdir1){
        System.out.println("創建成功2");
    }
    //要想刪除成功,io4文件目錄下不能有子目錄或文件
    File file3 = new File("D:\\io\\io1\\io4");
    file3 = new File("D:\\io\\io1");
    System.out.println(file3.delete());
}
3.5 File類的刪除功能
  • 刪除磁盤中的文件或文件目錄

  • public boolean delete():刪除文件或者文件夾

  • 刪除注意事項:Java中的刪除不走回收站。

4. 內存解析

Java File類的理解與使用

5. 小練習

利用Fie構造器,new一個文件目錄file 1)在其中創建多個文件和目錄 2)編寫方法,實現刪除fle中指定文件的操作

@Test
public void test1() throws IOException {
    File file = new File("E:\\io\\io1\\hello.txt");
    //創建一個與file同目錄下的另外一個文件,文件名為:haha.txt
    File destFile = new File(file.getParent(),"haha.txt");
    boolean newFile = destFile.createNewFile();
    if(newFile){
        System.out.println("創建成功!");
    }
}

判斷指定目錄下是否有后綴名為jpg的文件,如果有,就輸出該文件名稱

public class FindJPGFileTest {

    @Test
    public void test1(){
        File srcFile = new File("d:\\code");

        String[] fileNames = srcFile.list();
        for(String fileName : fileNames){
            if(fileName.endsWith(".jpg")){
                System.out.println(fileName);
            }
        }
    }
    @Test
    public void test2(){
        File srcFile = new File("d:\\code");

        File[] listFiles = srcFile.listFiles();
        for(File file : listFiles){
            if(file.getName().endsWith(".jpg")){
                System.out.println(file.getAbsolutePath());
            }
        }
    }
    /*
	 * File類提供了兩個文件過濾器方法
	 * public String[] list(FilenameFilter filter)
	 * public File[] listFiles(FileFilter filter)

	 */
    @Test
    public void test3(){
        File srcFile = new File("d:\\code");

        File[] subFiles = srcFile.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".jpg");
            }
        });

        for(File file : subFiles){
            System.out.println(file.getAbsolutePath());
        }
    }

}

遍歷指定目錄所有文件名稱,包括子文件目錄中的文件。 拓展1:并計算指定目錄占用空間的大小 拓展2:刪除指定文件目錄及其下的所有文件

public class ListFileTest {

    public static void main(String[] args) {
        // 遞歸:文件目錄
        /** 打印出指定目錄所有文件名稱,包括子文件目錄中的文件 */

        //1.創建目錄對象
        File file = new File("E:\\test");

        //2.打印子目錄
        printSubFile(file);

    }

    /**
     * 遞歸方法遍歷所有目錄下的文件
     *
     * @param dir
     */
    public static void printSubFile(File dir) {
        //打印子目錄
        File[] files = dir.listFiles();
        for (File f : files) {
            if (f.isDirectory()) {//如果為文件目錄,則遞歸調用自身
                printSubFile(f);
            } else {
                System.out.println(f.getAbsolutePath());//輸出絕對路徑
            }
        }
    }

    // 拓展1:求指定目錄所在空間的大小
    // 求任意一個目錄的總大小
    public long getDirectorySize(File file) {
        // file是文件,那么直接返回file.length()
        // file是目錄,把它的下一級的所有大小加起來就是它的總大小
        long size = 0;
        if (file.isFile()) {
            size += file.length();
        } else {
            File[] allFiles = file.listFiles();// 獲取file的下一級
            // 累加all[i]的大小
            for (File f : allFiles) {
                size += getDirectorySize(f);//f的大小
            }
        }
        return size;
    }

    /**
     * 拓展2:刪除指定的目錄
     */
    public void deleteDirectory(File file) {
        // 如果file是文件,直接delete
        // 如果file是目錄,先把它的下一級干掉,然后刪除自己
        if (file.isDirectory()) {
            File[] allFiles = file.listFiles();
            //遞歸調用刪除file下一級
            for (File f : allFiles) {
                deleteDirectory(f);
            }
        } else {
            //刪除文件
            file.delete();
        }
    }
}

二、IO流概述

1. 簡述

  • IO是Input/Output的縮寫,I/O技術是非常實用的技術,用于處理設備之間的數據傳輸。如讀/寫文件,網絡通訊等。

  • Java程序中,對于數據的輸入輸出操作以“流(stream)”的方式進行。

  • Java.IO包下提供了各種“流”類和接口,用以獲取不同種類的數據,并通過標準的方法輸入或輸出數據。

2. 流的分類

操作數據單位:字節流、字符流

  • 對于文本文件(.txt,.java,.c,.cpp),使用字符流處理

  • 對于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字節流處理

數據的流向:輸入流、輸出流

  • 輸入input:讀取外部數據(磁盤、光盤等存儲設備的數據)到程序(內存)中。

  • 輸出output:將程序(內存)數據輸出到磁盤、光盤等存儲設備中。

流的角色:節點流、處理流

節點流:直接從數據源或目的地讀寫數據。

Java File類的理解與使用

處理流:不直接連接到數據源或目的地,而是“連接”在已存在的流(節點流或處理流)之上,通過對數據的處理為程序提供更為強大的讀寫功能。

Java File類的理解與使用

圖示:

Java File類的理解與使用

3. IO流的體系分類

3.1 總體分類

Java File類的理解與使用

紅框為抽象基類,藍框為常用IO流

3.2 常用的幾個IO流結構
抽象基類節點流(或文件流)緩沖流(處理流的一種)
InputStreamFileInputStream (read(byte[] buffer))BufferedInputStream (read(byte[] buffer))
OutputSteamFileOutputStream (write(byte[] buffer,0,len)BufferedOutputStream (write(byte[] buffer,0,len) / flush()
ReaderFileReader (read(char[] cbuf))BufferedReader (read(char[] cbuf) / readLine())
WriterFileWriter (write(char[] cbuf,0,len)BufferedWriter (write(char[] cbuf,0,len) / flush()
3.3 對抽象基類的說明:
抽象基類字節流字符流
輸入流InputSteamReader
輸出流OutputSteamWriter
  • 說明:Java的lO流共涉及40多個類,實際上非常規則,都是從如下4個抽象基類派生的。

  • 由這四個類派生出來的子類名稱都是以其父類名作為子類名后綴。

3.3.1InputSteam & Reader

  • InputStream和Reader是所有輸入流的基類。

  • InputStream(典型實現:FileInputStream)

    • int read()

    • int read(byte[] b)

    • int read(byte[] b,int off,int len)

  • Reader(典型實現:FileReader)

    • int read()

    • int read(char[] c)

    • int read(char[] c,int off,int len)

  • 程序中打開的文件IO資源不屬于內存里的資源,垃圾回收機制無法回收該資源,所以應該顯式關閉文件IO資源。

  • FileInputStream從文件系統中的某個文件中獲得輸入字節。FileInputStream用于讀取非文本數據之類的原始字節流。要讀取字符流,需要使用 FileReader。

InputSteam:

  • int read()

    從輸入流中讀取數據的下一個字節。返回0到255范圍內的int字節值。如果因為已經到達流末尾而沒有可用的字節,則返回值-1。

  • int read(byte[] b)

    從此輸入流中將最多b.length個字節的數據讀入一個byte數組中。如果因為已經到達流末尾而沒有可用的字節,則返回值-1.否則以整數形式返回實際讀取的字節數。

  • int read(byte[] b,int off,int len)

    將輸入流中最多len個數據字節讀入byte數組。嘗試讀取len個字節,但讀取的字節也可能小于該值。以整數形式返回實際讀取的字節數。如果因為流位于文件末尾而沒有可用的字節,則返回值-1。

  • public void close throws IOException

    關閉此輸入流并釋放與該流關聯的所有系統資源。

Reader:

  • int read()

    讀取單個字符。作為整數讀取的字符,范圍在0到65535之間(0x00-0xffff)(2個字節的 Unicode碼),如果已到達流的末尾,則返回-1。

  • int read(char[] cbuf)

    將字符讀入數組。如果已到達流的末尾,則返回-1。否則返回本次讀取的字符數。

  • int read(char[] cbuf,int off,int len)

    將字符讀入數組的某一部分。存到數組cbuf中,從off處開始存儲,最多讀len個字符。如果已到達流的末尾,則返回-1。否則返回本次讀取的字符數。

  • public void close throws IOException

    關閉此輸入流并釋放與該流關聯的所有系統資源

3.3.2 OutputSteam & Writer

  • OutputStream和Writer也非常相似:

    • void write(int b/int c);

    • void write(byte[] b/char[] cbuf);

    • void write(byte[] b/char[] buff,int off,int len);

    • void flush();

    • void close();需要先刷新,再關閉此流

  • 因為字符流直接以字符作為操作單位,所以 Writer可以用字符串來替換字符數組,即以 String對象作為參數

    • void write(String str);

    • void write(String str,int off,int len);

  • FileOutputStream從文件系統中的某個文件中獲得輸出字節。FileOutputstream用于寫出非文本數據之類的原始字節流。要寫出字符流,需要使用 FileWriter

OutputStream:

  • void write(int b)

    將指定的字節寫入此輸出流。 write的常規協定是:向輸出流寫入一個字節。要寫入的字節是參數b的八個低位。b的24個高位將被忽略。即寫入0~255范圍的

  • void write(byte[] b)

    將b.length個字節從指定的byte數組寫入此輸出流。write(b)的常規協定是:應該與調用wite(b,0,b.length)的效果完全相同。

  • void write(byte[] b,int off,int len)

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

  • public void flush()throws IOException

    刷新此輸出流并強制寫出所有緩沖的輸出字節,調用此方法指示應將這些字節立即寫入它們預期的目標。

  • public void close throws IOException

    關閉此輸岀流并釋放與該流關聯的所有系統資源。

Writer:

  • void write(int c)

    寫入單個字符。要寫入的字符包含在給定整數值的16個低位中,16高位被忽略。即寫入0到65535之間的 Unicode碼。

  • void write(char[] cbuf)

    寫入字符數組

  • void write(char[] cbuf,int off,int len)

    寫入字符數組的某一部分。從off開始,寫入len個字符

  • void write(String str)

    寫入字符串。

  • void write(String str,int off,int len)

    寫入字符串的某一部分。

  • void flush()

    刷新該流的緩沖,則立即將它們寫入預期目標。

  • public void close throws IOException

    關閉此輸出流并釋放與該流關聯的所有系統資源

4. 輸入、輸出標準化過程

4.1 輸入過程:

① 創建File類的對象,指明讀取的數據的來源。(要求此文件一定要存在)

② 創建相應的輸入流,將File類的對象作為參數,傳入流的構造器中

③ 具體的讀入過程:創建相應的byte[] 或 char[]。

④ 關閉流資源

說明:程序中出現的異常需要使用try-catch-finally處理。

4.2 輸出過程:

① 創建File類的對象,指明寫出的數據的位置。(不要求此文件一定要存在)

② 創建相應的輸出流,將File類的對象作為參數,傳入流的構造器中

③ 具體的寫出過程:write(char[]/byte[] buffer,0,len)

④ 關閉流資源

說明:程序中出現的異常需要使用try-catch-finally處理。

三、節點流(文件流)

1. 文件字符流FileReader和FileWriter的使用

1.1文件的輸入

從文件中讀取到內存(程序)中

步驟:

  1. 建立一個流對象,將已存在的一個文件加載進流 FileReader fr = new FileReader(new File("Test. txt"));

  2. 創建一個臨時存放數據的數組 char[] ch = new char[1024];

  3. 調用流對象的讀取方法將流中的數據讀入到數組中。 fr.read(ch);

  4. 關閉資源。 fr.close();

代碼示例:

@Test
public void testFileReader1()  {
    FileReader fr = null;
    try {
        //1.File類的實例化
        File file = new File("hello.txt");

        //2.FileReader流的實例化
        fr = new FileReader(file);

        //3.讀入的操作
        //read(char[] cbuf):返回每次讀入cbuf數組中的字符的個數。如果達到文件末尾,返回-1
        char[] cbuf = new char[5];
        int len;
        while((len = fr.read(cbuf)) != -1){
            String str = new String(cbuf,0,len);
            System.out.print(str);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(fr != null){
            //4.資源的關閉
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

}

注意點:

  1. read()的理解:返回讀入的一個字符。如果達到文件末尾,返回-1

  2. 異常的處理:為了保證流資源一定可以執行關閉操作。需要使用try-catch-finally處理

  3. 讀入的文件一定要存在,否則就會報FileNotFoundException。

1.2 文件的輸出

從內存(程序)到硬盤文件中

步驟:

  1. 創建流對象,建立數據存放文件 File Writer fw = new File Writer(new File("Test.txt"))

  2. 調用流對象的寫入方法,將數據寫入流 fw.write("HelloWord")

  3. 關閉流資源,并將流中的數據清空到文件中。 fw.close();

代碼示例:

@Test
public void testFileWriter() {
    FileWriter fw = null;
    try {
        //1.提供File類的對象,指明寫出到的文件
        File file = new File("hello1.txt");

        //2.提供FileWriter的對象,用于數據的寫出
        fw = new FileWriter(file,false);

        //3.寫出的操作
        fw.write("I have a dream!\n");
        fw.write("you need to have a dream!");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.流資源的關閉
        if(fw != null){

            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
1.3 小練習

實現文本文件的復制操作

@Test
public void testFileReaderFileWriter() {
    FileReader fr = null;
    FileWriter fw = null;
    try {
        //1.創建File類的對象,指明讀入和寫出的文件
        File srcFile = new File("hello.txt");
        File destFile = new File("hello2.txt");

        //不能使用字符流來處理圖片等字節數據
        //            File srcFile = new File("test.jpg");
        //            File destFile = new File("test1.jpg");

        //2.創建輸入流和輸出流的對象
        fr = new FileReader(srcFile);
        fw = new FileWriter(destFile);

        //3.數據的讀入和寫出操作
        char[] cbuf = new char[5];
        int len;//記錄每次讀入到cbuf數組中的字符的個數
        while((len = fr.read(cbuf)) != -1){
            //每次寫出len個字符
            fw.write(cbuf,0,len);

        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.關閉流資源
        try {
            if(fw != null)
                fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            if(fr != null)
                fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

2. 文件字節流FileInputSteam和FileOutputSteam的使用

文件字節流操作與字符流操作類似,只是實例化對象操作和數據類型不同。

代碼示例:

//使用字節流FileInputStream處理文本文件,可能出現亂碼。
@Test
public void testFileInputStream() {
    FileInputStream fis = null;
    try {
        //1. 造文件
        File file = new File("hello.txt");

        //2.造流
        fis = new FileInputStream(file);

        //3.讀數據
        byte[] buffer = new byte[5];
        int len;//記錄每次讀取的字節的個數
        while((len = fis.read(buffer)) != -1){

            String str = new String(buffer,0,len);
            System.out.print(str);

        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(fis != null){
            //4.關閉資源
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

}

小練習

實現圖片文件復制操作

@Test
public void testFileInputOutputStream()  {
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        //1.創建File對象
        File srcFile = new File("test.jpg");
        File destFile = new File("test2.jpg");

        //2.創建操流
        fis = new FileInputStream(srcFile);
        fos = new FileOutputStream(destFile);

        //3.復制的過程
        byte[] buffer = new byte[5];
        int len;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.關閉流
        if(fos != null){
            //
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(fis != null){
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

}

3. 注意點

  • 定義路徑時,可以用“/”或“\\”。

  • 輸出操作,對應的File可以不存在的。并不會報異常。

  • File對應的硬盤中的文件如果不存在,在輸出的過程中,會自動創建此文件。

  • File對應的硬盤中的文件如果存在:

    • 如果流使用的構造器是:FileWriter(file,false) / FileWriter(file):對原有文件的覆蓋。

    • 如果流使用的構造器是:FileWriter(file,true):不會對原有文件覆蓋,而是在原有文件基礎上追加內容。

  • 讀取文件時,必須保證文件存在,否則會報異常。

  • 對于文本文件(.txt,.java,.c,.cpp),使用字符流處理

  • 對于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字節流處理

四、緩沖流

1. 緩沖流涉及到的類:

  • BufferedInputStream

  • BufferedOutputStream

  • BufferedReader

  • BufferedWriter

2. 引入目的:

  • 作用:提供流的讀取、寫入的速度

  • 提高讀寫速度的原因:內部提供了一個緩沖區。默認情況下是8kb

    Java File類的理解與使用

處理流與節點流的對比圖示

Java File類的理解與使用

Java File類的理解與使用

3. 使用說明

  • 當讀取數據時,數據按塊讀入緩沖區,其后的讀操作則直接訪問緩沖區。

  • 當使用 BufferedInputStream讀取字節文件時,BufferedInputStream會一次性從文件中讀取8192個(8Kb),存在緩沖區中,直到緩沖區裝滿了,才重新從文件中讀取下一個8192個字節數組。

  • 向流中寫入字節時,不會直接寫到文件,先寫到緩沖區中直到緩沖區寫滿,BufferedOutputStream才會把緩沖區中的數據一次性寫到文件里。使用方法flush()可以強制將緩沖區的內容全部寫入輸出流。

  • 關閉流的順序和打開流的順序相反。只要關閉最外層流即可,關閉最外層流也會相應關閉內層節點流。

  • flush()方法的使用:手動將buffer中內容寫入文件。

  • 如果是帶緩沖區的流對象的close()方法,不但會關閉流,還會在關閉流之前刷新緩沖區,關閉后不能再寫出。

代碼示例:

3.1使用BufferInputStream和BufferOutputStream實現非文本文件的復制
@Test
public void testBufferedStream(){
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
        //1.造文件
        File srcFile = new File("test.jpg");
        File destFile = new File("test4.jpg");
        //2.造流
        //2.1造節點流
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);
        //2.2造緩沖流,可以合并書寫
        bis = new BufferedInputStream(fis);
        bos = new BufferedOutputStream(fos);

        //3.文件讀取、寫出操作
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bis.read(buffer)) != -1){
            bos.write(buffer,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.關閉流
        if (bos != null){
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (bis != null){

            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
3.2 使用BufferedReader和BufferedWriter實現文本文件的復制
@Test
public void testBufferedReaderBufferedWriter(){
    BufferedReader br = null;
    BufferedWriter bw = null;
    try {
        //創建文件和相應的流
        br = new BufferedReader(new FileReader(new File("dbcp.txt")));
        bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));

        //讀寫操作
        //方式一:使用char[]數組
        //            char[] cbuf = new char[1024];
        //            int len;
        //            while((len = br.read(cbuf)) != -1){
        //                bw.write(cbuf,0,len);
        //    //            bw.flush();
        //            }

        //方式二:使用String
        String data;
        while((data = br.readLine()) != null){
            //方法一:
            //                bw.write(data + "\n");//data中不包含換行符
            //方法二:
            bw.write(data);//data中不包含換行符
            bw.newLine();//提供換行的操作

        }


    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //關閉資源
        if(bw != null){

            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(br != null){
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

}

4. 小練習

4.1測試緩沖流和節點流文件復制速度

節點流實現復制方法

//指定路徑下文件的復制
public void copyFile(String srcPath,String destPath){
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        //1.造文件
        File srcFile = new File(srcPath);
        File destFile = new File(destPath);

        //2.造流
        fis = new FileInputStream(srcFile);
        fos = new FileOutputStream(destFile);

        //3.復制的過程
        byte[] buffer = new byte[1024];
        int len;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer,0,len);
        }

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(fos != null){
            //4.關閉流
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if(fis != null){
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

緩沖流實現復制操作

//實現文件復制的方法
public void copyFileWithBuffered(String srcPath,String destPath){
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;

    try {
        //1.造文件
        File srcFile = new File(srcPath);
        File destFile = new File(destPath);
        //2.造流
        //2.1 造節點流
        FileInputStream fis = new FileInputStream((srcFile));
        FileOutputStream fos = new FileOutputStream(destFile);
        //2.2 造緩沖流
        bis = new BufferedInputStream(fis);
        bos = new BufferedOutputStream(fos);

        //3.復制的細節:讀取、寫入
        byte[] buffer = new byte[1024];
        int len;
        while((len = bis.read(buffer)) != -1){
            bos.write(buffer,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.資源關閉
        //要求:先關閉外層的流,再關閉內層的流
        if(bos != null){
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        if(bis != null){
            try {
                bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

測試二者速度

@Test
public void testCopyFileWithBuffered(){
    long start = System.currentTimeMillis();

    String srcPath = "C:\\Users\\Administrator\\Desktop\\01-視頻.avi";
    String destPath = "C:\\Users\\Administrator\\Desktop\\03-視頻.avi";

    copyFileWithBuffered(srcPath,destPath);

    long end = System.currentTimeMillis();

    System.out.println("復制操作花費的時間為:" + (end - start));//618 - 176
}
4.2實現圖片加密操作

加密操作

  • 將圖片文件通過字節流讀取到程序中

  • 將圖片的字節流逐一進行^操作

  • 將處理后的圖片字節流輸出

//圖片的加密
@Test
public void test1() {

    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        fis = new FileInputStream("test.jpg");
        fos = new FileOutputStream("testSecret.jpg");

        byte[] buffer = new byte[20];
        int len;
        while ((len = fis.read(buffer)) != -1) {

            for (int i = 0; i < len; i++) {
                buffer[i] = (byte) (buffer[i] ^ 5);
            }

            fos.write(buffer, 0, len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

解密操作

  • 將加密后圖片文件通過字節流讀取到程序中

  • 將圖片的字節流逐一進行^操作(原理:A^B^B = A)

  • 將處理后的圖片字節流輸出

//圖片的解密
@Test
public void test2() {

    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
        fis = new FileInputStream("testSecret.jpg");
        fos = new FileOutputStream("test4.jpg");

        byte[] buffer = new byte[20];
        int len;
        while ((len = fis.read(buffer)) != -1) {
          
            for (int i = 0; i < len; i++) {
                buffer[i] = (byte) (buffer[i] ^ 5);
            }

            fos.write(buffer, 0, len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}
4.3 統計文本字符出現次數

實現思路:

  1. 遍歷文本每一個字符

  2. 字符出現的次數存在Map中

  3. 把map中的數據寫入文件

@Test
public void testWordCount() {
    FileReader fr = null;
    BufferedWriter bw = null;
    try {
        //1.創建Map集合
        Map<Character, Integer> map = new HashMap<Character, Integer>();

        //2.遍歷每一個字符,每一個字符出現的次數放到map中
        fr = new FileReader("dbcp.txt");
        int c = 0;
        while ((c = fr.read()) != -1) {
            //int 還原 char
            char ch = (char) c;
            // 判斷char是否在map中第一次出現
            if (map.get(ch) == null) {
                map.put(ch, 1);
            } else {
                map.put(ch, map.get(ch) + 1);
            }
        }

        //3.把map中數據存在文件count.txt
        //3.1 創建Writer
        bw = new BufferedWriter(new FileWriter("wordcount.txt"));

        //3.2 遍歷map,再寫入數據
        Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();
        for (Map.Entry<Character, Integer> entry : entrySet) {
            switch (entry.getKey()) {
                case ' ':
                    bw.write("空格=" + entry.getValue());
                    break;
                case '\t'://\t表示tab 鍵字符
                    bw.write("tab鍵=" + entry.getValue());
                    break;
                case '\r'://
                    bw.write("回車=" + entry.getValue());
                    break;
                case '\n'://
                    bw.write("換行=" + entry.getValue());
                    break;
                default:
                    bw.write(entry.getKey() + "=" + entry.getValue());
                    break;
            }
            bw.newLine();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.關流
        if (fr != null) {
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        if (bw != null) {
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

五、轉換流

1. 簡介

  • 轉換流提供了在字節流和字符流之間的轉換

  • Java API提供了兩個轉換流:

    • InputstreamReader:將 Inputstream轉換為Reader

    • OutputStreamWriter:將 Writer轉換為OutputStream

  • 字節流中的數據都是字符時,轉成字符流操作更高效。

  • 很多時候我們使用轉換流來處理文件亂碼問題。實現編碼和解碼的功能。

1.1 InputStreamReader

InputStreamReader將一個字節的輸入流轉換為字符的輸入流 解碼:字節、字節數組 --->字符數組、字符串

構造器:

  • public InputStreamReader(InputStream in)

  • public InputStreamReader(Inputstream in,String charsetName)//可以指定編碼集

1.2 OutputStreamWriter

OutputStreamWriter將一個字符的輸出流轉換為字節的輸出流 編碼:字符數組、字符串 ---> 字節、字節數組

構造器:

  • public OutputStreamWriter(OutputStream out)

  • public OutputStreamWriter(Outputstream out,String charsetName)//可以指定編碼集

圖示:

Java File類的理解與使用

2.代碼示例:

/**
綜合使用InputStreamReader和OutputStreamWriter
     */
@Test
public void test1() {
    InputStreamReader isr = null;
    OutputStreamWriter osw = null;
    try {
        //1.造文件、造流
        File file1 = new File("dbcp.txt");
        File file2 = new File("dbcp_gbk.txt");

        FileInputStream fis = new FileInputStream(file1);
        FileOutputStream fos = new FileOutputStream(file2);

        isr = new InputStreamReader(fis, "utf-8");
        osw = new OutputStreamWriter(fos, "gbk");

        //2.讀寫過程
        char[] cbuf = new char[20];
        int len;
        while ((len = isr.read(cbuf)) != -1){
            osw.write(cbuf,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //3.關流
        if (isr != null){

            try {
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (osw != null){
            try {
                osw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

說明:文件編碼的方式(比如:GBK),決定了解析時使用的字符集(也只能是GBK)。

3. 編碼集

3.1 常見的編碼表
  • ASCII:美國標準信息交換碼。用一個字節的7位可以表示。

  • ISO8859-1:拉丁碼表。歐洲碼表用一個字節的8位表示。

  • GB2312:中國的中文編碼表。最多兩個字節編碼所有字符

  • GBK:中國的中文編碼表升級,融合了更多的中文文字符號。最多兩個字節編碼

  • Unicode:國際標準碼,融合了目前人類使用的所字符。為每個字符分配唯一的字符碼。所有的文字都用兩個字節來表示。

  • UTF-8:變長的編碼方式,可用1-4個字節來表示一個字符。

Java File類的理解與使用

說明:

  • 面向傳輸的眾多UTF(UCS Transfer Format)標準出現了,顧名思義,UTF-8就是每次8個位傳輸數據,而UTF-16就是每次16個位。這是為傳輸而設計的編碼,并使編碼無國界,這樣就可以顯示全世界上所有文化的字符了。

  • Unicode只是定義了一個龐大的、全球通用的字符集,并為每個字符規定了唯確定的編號,具體存儲成什么樣的字節流,取決于字符編碼方案。推薦的Unicode編碼是UTF-8和UTF-16。

UTF-8變長編碼表示

Java File類的理解與使用

3.2 編碼應用
  • 編碼:字符串-->字節數組

  • 解碼:字節數組-->字符串

  • 轉換流的編碼應用

    • 可以將字符按指定編碼格式存儲

    • 可以對文本數據按指定編碼格式來解讀

    • 指定編碼表的動作由構造器完成

使用要求:

客戶端/瀏覽器端 <----> 后臺(java,GO,Python,Node.js,php) <----> 數據庫

要求前前后后使用的字符集都要統一:UTF-8.

六、標準輸入、輸出流

1.簡介

System.in:標準的輸入流,默認從鍵盤輸入

System.out:標準的輸出流,默認從控制臺輸出

2. 主要方法

System類的setIn(InputStream is) 方式重新指定輸入的流

System類的setOut(PrintStream ps)方式重新指定輸出的流。

3. 使用示例

從鍵盤輸入字符串,要求將讀取到的整行字符串轉成大寫輸出。然后繼續進行輸入操作,

直至當輸入“e”或者“exit”時,退出程序。

設計思路

方法一:使用Scanner實現,調用next()返回一個字符串

方法二:使用System.in實現。System.in ---> 轉換流 ---> BufferedReader的readLine()

public static void main(String[] args) {
    BufferedReader br = null;
    try {
        InputStreamReader isr = new InputStreamReader(System.in);
        br = new BufferedReader(isr);

        while (true) {
            System.out.println("請輸入字符串:");
            String data = br.readLine();
            if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
                System.out.println("程序結束");
                break;
            }

            String upperCase = data.toUpperCase();
            System.out.println(upperCase);

        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (br != null) {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

4. 小練習

設計實現Scanner類

public class MyInput {
    // Read a string from the keyboard
    public static String readString() {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // Declare and initialize the string
        String string = "";

        // Get the string from the keyboard
        try {
            string = br.readLine();

        } catch (IOException ex) {
            System.out.println(ex);
        }

        // Return the string obtained from the keyboard
        return string;
    }

    // Read an int value from the keyboard
    public static int readInt() {
        return Integer.parseInt(readString());
    }

    // Read a double value from the keyboard
    public static double readDouble() {
        return Double.parseDouble(readString());
    }

    // Read a byte value from the keyboard
    public static double readByte() {
        return Byte.parseByte(readString());
    }

    // Read a short value from the keyboard
    public static double readShort() {
        return Short.parseShort(readString());
    }

    // Read a long value from the keyboard
    public static double readLong() {
        return Long.parseLong(readString());
    }

    // Read a float value from the keyboard
    public static double readFloat() {
        return Float.parseFloat(readString());
    }
}

七、打印流

PrintStream 和 PrintWriter 說明:

  • 提供了一系列重載的print()和println()方法,用于多種數據類型的輸出

  • System.out返回的是PrintStream的實例

@Test
public void test2() {
    PrintStream ps = null;
    try {
        FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
        // 創建打印輸出流,設置為自動刷新模式(寫入換行符或字節 '\n' 時都會刷新輸出緩沖區)
        ps = new PrintStream(fos, true);
        if (ps != null) {// 把標準輸出流(控制臺輸出)改成文件
            System.setOut(ps);
        }


        for (int i = 0; i <= 255; i++) { // 輸出ASCII字符
            System.out.print((char) i);
            if (i % 50 == 0) { // 每50個數據一行
                System.out.println(); // 換行
            }
        }


    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (ps != null) {
            ps.close();
        }
    }

}

八、數據流

DataInputStream 和 DataOutputStream 作用: 用于讀取或寫出基本數據類型的變量或字符串

示例代碼:

將內存中的字符串、基本數據類型的變量寫出到文件中。

@Test
public void test3(){
    //1.造對象、造流
    DataOutputStream dos = null;
    try {
        dos = new DataOutputStream(new FileOutputStream("data.txt"));
        //數據輸出
        dos.writeUTF("Bruce");
        dos.flush();//刷新操作,將內存的數據寫入到文件
        dos.writeInt(23);
        dos.flush();
        dos.writeBoolean(true);
        dos.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //3.關閉流
        if (dos != null){
            try {
                dos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

將文件中存儲的基本數據類型變量和字符串讀取到內存中,保存在變量中。

/*
注意點:讀取不同類型的數據的順序要與當初寫入文件時,保存的數據的順序一致!
 */
@Test
public void test4(){
    DataInputStream dis = null;
    try {
        //1.造對象、造流
        dis = new DataInputStream(new FileInputStream("data.txt"));
        //2.從文件讀入數據
        String name = dis.readUTF();
        int age = dis.readInt();
        boolean isMale = dis.readBoolean();

        System.out.println("name:"+name);
        System.out.println("age:"+age);
        System.out.println("isMale:"+isMale);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //3.關閉流
        if (dis != null){

            try {
                dis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

九、對象流

1.對象流:

ObjectInputStream 和 ObjectOutputStream

2.作用:

  • ObjectOutputStream:內存中的對象--->存儲中的文件、通過網絡傳輸出去:序列化過程

  • ObjectInputStream:存儲中的文件、通過網絡接收過來 --->內存中的對象:反序列化過程

3. 對象的序列化

  • 對象序列化機制允許把內存中的Java對象轉換成平臺無關的二進制流,從而允許把這種二進制流持久地保存在磁盤上,或通過網絡將這種二進制流傳輸到另一個網絡節點。//當其它程序獲取了這種二進制流,就可以恢復成原來的Java對象。

  • 序列化的好處在于可將任何實現了Serializable接口的對象轉化為字節數據,使其在保存和傳輸時可被還原。

  • 序列化是RMI(Remote Method Invoke-遠程方法調用)過程的參數和返回值都必須實現的機制,RMI是JavaEE的基礎。因此序列化機制是JavaEE平臺的基礎。

  • 如果需要讓某個對象支持序列化機制,則必須讓對象所屬的類及其屬性是可序列化的,為了讓某個類是可序列化的,該類必須實現如下兩個接口之一。否則,會拋出 NotserializableEXception異常

    • Serializable

    • Externalizable

  • 凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量:

    • private static final long serialVersionUID;

    • serialVersionUID用來表明類的不同版本間的兼容性。簡言之,其目的是以序列化對象進行版本控制,有關各版本反序列化時是否兼容

    • 如果類沒有顯示定義這個靜態常量,它的值是Java運行時環境根據類的內部細節自動生成的。若類的實例變量做了修改,serialVersionUID可能發生變化。故建議顯式聲明。

  • 簡單來說,Java的序列化機制是通過在運行時判斷類的serialversionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialversionUID與本地相應實體類的serialversionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常。(InvalidCastException)

4.實現序列化的對象所屬的類需要滿足:

  1. 需要實現接口:Serializable(標識接口)

  2. 當前類提供一個全局常量:serialVersionUID(序列版本號)

  3. 除了當前Person類需要實現Serializable接口之外,還必須保證其內部所屬性也必須是可序列化的。(默認情況下,基本數據類型可序列化)

補充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量

5. 對象流的使用

5.1序列化代碼實現

序列化:將對象寫入磁盤或進行網絡傳輸

要求被序列化對象必須實現序列化

@Test
public void testObjectOutputStream(){
    ObjectOutputStream oos = null;

    try {
        //1.創建對象,創建流
        oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
        //2.操作流
        oos.writeObject(new String("我愛北京天安門"));
        oos.flush();//刷新操作

        oos.writeObject(new Person("王銘",23));
        oos.flush();

        oos.writeObject(new Person("張學良",23,1001,new Account(5000)));
        oos.flush();

    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(oos != null){
            //3.關閉流
            try {
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

}
5.2 反序列化代碼實現

反序列化:將磁盤的對象數據源讀出

@Test
public void testObjectInputStream(){
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(new FileInputStream("object.dat"));

        Object obj = ois.readObject();
        String str = (String) obj;

        Person p = (Person) ois.readObject();
        Person p1 = (Person) ois.readObject();

        System.out.println(str);
        System.out.println(p);
        System.out.println(p1);

    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if(ois != null){
            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

十、任意存取文件流

RandomAccessFile的使用

1.簡介

  • RandomAccessFile直接繼承于java.lang.Object類,實現了DataInput和DataOutput接口

  • RandomAccessFile既可以作為一個輸入流,又可以作為一個輸出流

  • RandomAccessFile類支持“隨機訪問”的方式,程序可以直接跳到文件的任意地方來讀、寫文件

    • 支持只訪問文件的部分內容

    • 可以向已存在的文件后追加內容

  • RandomAccessFile對象包含一個記錄指針,用以標示當前讀寫處的位置

  • RandomaccessFile類對象可以自由移動記錄指針:

    • long getFilePointer():獲取文件記錄指針的當前位置

    • void seek(long pos):將文件記錄指針定位到pos位置

構造器

public RandomAccessFile(File file,String mode)

public RandomAccessFile(String name,String mode)

2.使用說明:

  1. 如果RandomAccessFile作為輸出流時,寫出到的文件如果不存在,則在執行過程中自動創建。

  2. 如果寫出到的文件存在,則會對原文件內容進行覆蓋。(默認情況下,從頭覆蓋)

  3. 可以通過相關的操作,實現RandomAccessFile“插入”數據的效果。借助seek(int pos)方法

  4. 創建RandomAccessFile類實例需要指定一個mode參數,該參數指定RandomAccessFile的訪問模式:

    • r:以只讀方式打開

    • rw:打開以便讀取和寫入

    • rwd:打開以便讀取和寫入;同步文件內容的更新

    • rws:打開以便讀取和寫入;同步文件內容和元數據的更新

  5. 如果模式為只讀r,則不會創建文件,而是會去讀取一個已經存在的文件,讀取的文件不存在則會出現異常。如果模式為rw讀寫,文件不存在則會去創建文件,存在則不會創建。

3. 使用示例

文件的讀取和寫出操作

@Test
public void test1() {

    RandomAccessFile raf1 = null;
    RandomAccessFile raf2 = null;
    try {
        //1.創建對象,創建流
        raf1 = new RandomAccessFile(new File("test.jpg"),"r");
        raf2 = new RandomAccessFile(new File("test1.jpg"),"rw");
        //2.操作流
        byte[] buffer = new byte[1024];
        int len;
        while((len = raf1.read(buffer)) != -1){
            raf2.write(buffer,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //3.關閉流
        if(raf1 != null){
            try {
                raf1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        if(raf2 != null){
            try {
                raf2.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

使用RandomAccessFile實現數據的插入效果

@Test
public void test2(){
    RandomAccessFile raf1 = null;
    try {
        raf1 = new RandomAccessFile(new File("hello.txt"), "rw");

        raf1.seek(3);//將指針調到角標為3的位置
        //            //方式一
        //            //保存指針3后面的所有數據到StringBuilder中
        //            StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
        //            byte[] buffer = new byte[20];
        //            int len;
        //            while ((len = raf1.read(buffer)) != -1){
        //                builder.append(new String(buffer,0,len));
        //            }

        //方式二
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[20];
        int len;
        while ((len = raf1.read(buffer)) != -1){
            baos.write(buffer);
        }
        //調回指針,寫入“xyz”
        raf1.seek(3);
        raf1.write("xyz".getBytes());
        //將StringBuilder中的數據寫入到文件中
        raf1.write(baos.toString().getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (raf1 != null){
            try {
                raf1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}

十一、流的基本應用總結

  • 流是用來處理數據的。

  • 處理數據時,一定要先明確數據源,與數據目的地數據源可以是文件,可以是鍵盤數據目的地可以是文件、顯示器或者其他設備

  • 而流只是在幫助數據進行傳輸,并對傳輸的數據進行處理,比如過濾處理、轉換處理等

  • 除去RandomAccessFile類外所有的流都繼承于四個基本數據流抽象類InputSteam、OutputSteam、Reader、Writer

  • 不同的操作流對應的后綴均為四個抽象基類中的某一個

    Java File類的理解與使用

  • 不同處理流的使用方式都是標準操作:

    • 創建文件對象,創建相應的流

    • 處理流數據

    • 關閉流

    • 用try-catch-finally處理異常

十二、NIO

Path、Paths、Files的使用,介紹比較簡單,后期會再抽時間詳細寫有關NIO的博客。

1.NIO的使用說明:

  • Java NIO (New IO,Non-Blocking IO)是從Java 1.4版本開始引入的一套新的IO API,可以替代標準的Java IO AP。

  • NIO與原來的IO同樣的作用和目的,但是使用的方式完全不同,NIO支持面向緩沖區的(IO是面向流的)、基于通道的IO操作。

  • NIO將以更加高效的方式進行文件的讀寫操作。

  • JDK 7.0對NIO進行了極大的擴展,增強了對文件處理和文件系統特性的支持,稱他為 NIO.2。

Java API中提供了兩套NIO,一套是針對標準輸入輸出NIO,另一套就是網絡編程NIO
|-----java.nio.channels.Channel
      |---- FileChannel:處理本地文件
      |---- SocketChannel:TCP網絡編程的客戶端的Channel
      |---- ServerSocketChannel:TCP網絡編程的服務器端的Channel
      |---- DatagramChannel:UDP網絡編程中發送端和接收端的Channel

2.Path接口 ---JDK 7.0提供

  • 早期的Java只提供了一個File類來訪問文件系統,但File類的功能比較有限,所提供的方法性能也不高。而且,大多數方法在出錯時僅返回失敗,并不會提供異常信息。

  • NIO.2為了彌補這種不足,引入了Path接口,代表一個平臺無關的平臺路徑,描述了目錄結構中文件的位置。Path可以看成是File類的升級版本,實際引用的資源也可以不存在。

2.1Path的說明:

Path替換原有的File類。

  • 在以前IO操作都是這樣寫的:

    • import java.io.File

    • File file = new File("index.html");

  • 但在Java7中,我們可以這樣寫:

    • import java.nio.file.Path;

    • import java.nio.file.Paths;

    • Path path = Paths.get("index. html");

2.2 Paths的使用
  • Paths類提供的靜態get()方法用來獲取Path對象:

  • static Path get(String first, String….more):用于將多個字符串串連成路徑

  • static Path get(URI uri):返回指定uri對應的Path路徑

代碼示例

@Test
public void test1(){
    Path path2 = Paths.get("hello.txt");//new File(String filepath)

    Path path3 = Paths.get("E:\\", "test\\test1\\haha.txt");//new File(String parent,String filename);

    Path path4 = Paths.get("E:\\", "test");

    System.out.println(path2);
    System.out.println(path3);
    System.out.println(path4);

}
2.3 常用方法
  • String toString() : 返回調用 Path 對象的字符串表示形式

  • boolean startsWith(String path) : 判斷是否以 path 路徑開始

  • boolean endsWith(String path) : 判斷是否以 path 路徑結束

  • boolean isAbsolute() : 判斷是否是絕對路徑

  • Path getParent() :返回Path對象包含整個路徑,不包含 Path 對象指定的文件路徑

  • Path getRoot() :返回調用 Path 對象的根路徑

  • Path getFileName() : 返回與調用 Path 對象關聯的文件名

  • int getNameCount() : 返回Path 根目錄后面元素的數量

  • Path getName(int idx) : 返回指定索引位置 idx 的路徑名稱

  • Path toAbsolutePath() : 作為絕對路徑返回調用 Path 對象

  • Path resolve(Path p) :合并兩個路徑,返回合并后的路徑對應的Path對象

  • File toFile(): 將Path轉化為File類的對象

代碼示例

@Test
public void test2() {
    Path path2 = Paths.get("d:\\", "nio\\nio1\\nio2\\hello.txt");
    Path path3 = Paths.get("hello.txt");

    //		String toString() : 返回調用 Path 對象的字符串表示形式
    System.out.println(path2);

    //		boolean startsWith(String path) : 判斷是否以 path 路徑開始
    System.out.println(path2.startsWith("d:\\nio"));
    //		boolean endsWith(String path) : 判斷是否以 path 路徑結束
    System.out.println(path2.endsWith("hello.txt"));
    //		boolean isAbsolute() : 判斷是否是絕對路徑
    System.out.println(path2.isAbsolute() + "~");
    System.out.println(path3.isAbsolute() + "~");
    //		Path getParent() :返回Path對象包含整個路徑,不包含 Path 對象指定的文件路徑
    System.out.println(path2.getParent());
    System.out.println(path3.getParent());
    //		Path getRoot() :返回調用 Path 對象的根路徑
    System.out.println(path2.getRoot());
    System.out.println(path3.getRoot());
    //		Path getFileName() : 返回與調用 Path 對象關聯的文件名
    System.out.println(path2.getFileName() + "~");
    System.out.println(path3.getFileName() + "~");
    //		int getNameCount() : 返回Path 根目錄后面元素的數量
    //		Path getName(int idx) : 返回指定索引位置 idx 的路徑名稱
    for (int i = 0; i < path2.getNameCount(); i++) {
        System.out.println(path2.getName(i) + "*****");
    }

    //		Path toAbsolutePath() : 作為絕對路徑返回調用 Path 對象
    System.out.println(path2.toAbsolutePath());
    System.out.println(path3.toAbsolutePath());
    //		Path resolve(Path p) :合并兩個路徑,返回合并后的路徑對應的Path對象
    Path path4 = Paths.get("d:\\", "nio");
    Path path5 = Paths.get("nioo\\hi.txt");
    path4 = path4.resolve(path5);
    System.out.println(path4);

    //		File toFile(): 將Path轉化為File類的對象
    File file = path2.toFile();//Path--->File的轉換

    Path newPath = file.toPath();//File--->Path的轉換

}

3.Files類

java.nio.file.Files用于操作文件或目錄的工具類

3.1 Files類常用方法
  • Path copy(Path src, Path dest, CopyOption … how) : 文件的復制

    要想復制成功,要求path2對應的物理上的文件存在。path2對應的文件沒有要求。

  • Files.copy(path2, path3, StandardCopyOption.REPLACE_EXISTING);

  • Path createDirectory(Path path, FileAttribute<?> … attr) : 創建一個目錄

    要想執行成功,要求path對應的物理上的文件目錄不存在。一旦存在,拋出異常。

  • Path createFile(Path path, FileAttribute<?> … arr) : 創建一個文件

  • 要想執行成功,要求path對應的物理上的文件不存在。一旦存在,拋出異常。

  • void delete(Path path) : 刪除一個文件/目錄,如果不存在,執行報錯

  • void deleteIfExists(Path path) : Path對應的文件/目錄如果存在,執行刪除.如果不存在,正常執行結束

  • Path move(Path src, Path dest, CopyOption…how) : 將 src 移動到 dest 位置

    要想執行成功,src對應的物理上的文件需要存在,dest對應的文件沒有要求。

  • long size(Path path) : 返回 path 指定文件的大小

代碼示例

@Test
public void test1() throws IOException{
    Path path2 = Paths.get("d:\\nio", "hello.txt");
    Path path3 = Paths.get("atguigu.txt");

    //		Path copy(Path src, Path dest, CopyOption … how) : 文件的復制
    //要想復制成功,要求path2對應的物理上的文件存在。path2對應的文件沒有要求。
    //		Files.copy(path2, path3, StandardCopyOption.REPLACE_EXISTING);

    //		Path createDirectory(Path path, FileAttribute<?> … attr) : 創建一個目錄
    //要想執行成功,要求path對應的物理上的文件目錄不存在。一旦存在,拋出異常。
    Path path4 = Paths.get("d:\\nio\\nio1");
    //		Files.createDirectory(path4);

    //		Path createFile(Path path, FileAttribute<?> … arr) : 創建一個文件
    //要想執行成功,要求path對應的物理上的文件不存在。一旦存在,拋出異常。
    Path path5 = Paths.get("d:\\nio\\hi.txt");
    //		Files.createFile(path5);

    //		void delete(Path path) : 刪除一個文件/目錄,如果不存在,執行報錯
    //		Files.delete(path5);

    //		void deleteIfExists(Path path) : Path對應的文件/目錄如果存在,執行刪除.如果不存在,正常執行結束
    Files.deleteIfExists(path4);

    //		Path move(Path src, Path dest, CopyOption…how) : 將 src 移動到 dest 位置
    //要想執行成功,src對應的物理上的文件需要存在,dest對應的文件沒有要求。
    //		Files.move(path2, path3, StandardCopyOption.ATOMIC_MOVE);

    //		long size(Path path) : 返回 path 指定文件的大小
    long size = Files.size(path3);
    System.out.println(size);

}
3.2 Files類常用方法:用于判斷
  • boolean exists(Path path, LinkOption … opts) : 判斷文件是否存在

  • boolean isDirectory(Path path, LinkOption … opts) : 判斷是否是目錄

    不要求此path對應的物理文件存在。

  • boolean isRegularFile(Path path, LinkOption … opts) : 判斷是否是文件

  • boolean isHidden(Path path) : 判斷是否是隱藏文件

    要求此path對應的物理上的文件需要存在。才可判斷是否隱藏。否則,拋異常。

  • boolean isReadable(Path path) : 判斷文件是否可讀

  • boolean isWritable(Path path) : 判斷文件是否可寫

  • boolean notExists(Path path, LinkOption … opts) : 判斷文件是否不存在

代碼示例

@Test
public void test2() throws IOException{
    Path path2 = Paths.get("d:\\nio", "hello.txt");
    Path path3 = Paths.get("atguigu.txt");
    //		boolean exists(Path path, LinkOption … opts) : 判斷文件是否存在
    System.out.println(Files.exists(path3, LinkOption.NOFOLLOW_LINKS));

    //		boolean isDirectory(Path path, LinkOption … opts) : 判斷是否是目錄
    //不要求此path對應的物理文件存在。
    System.out.println(Files.isDirectory(path2, LinkOption.NOFOLLOW_LINKS));

    //		boolean isRegularFile(Path path, LinkOption … opts) : 判斷是否是文件

    //		boolean isHidden(Path path) : 判斷是否是隱藏文件
    //要求此path對應的物理上的文件需要存在。才可判斷是否隱藏。否則,拋異常。
    //		System.out.println(Files.isHidden(path2));

    //		boolean isReadable(Path path) : 判斷文件是否可讀
    System.out.println(Files.isReadable(path2));
    //		boolean isWritable(Path path) : 判斷文件是否可寫
    System.out.println(Files.isWritable(path2));
    //		boolean notExists(Path path, LinkOption … opts) : 判斷文件是否不存在
    System.out.println(Files.notExists(path2, LinkOption.NOFOLLOW_LINKS));
}

補充:

  • StandardOpenOption.READ:表示對應的Channel是可讀的。

  • StandardOpenOption.WRITE:表示對應的Channel是可寫的。

  • StandardOpenOption.CREATE:如果要寫出的文件不存在,則創建。如果存在,忽略

  • StandardOpenOption.CREATE_NEW:如果要寫出的文件不存在,則創建。如果存在,拋異常

3.3 Files類常用方法:用于操作內容
  • InputStream newInputStream(Path path, OpenOption…how):獲取 InputStream 對象

  • OutputStream newOutputStream(Path path, OpenOption…how) : 獲取 OutputStream 對象

  • SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 獲取與指定文件的連接,how 指定打開方式。

  • DirectoryStream<Path> newDirectoryStream(Path path) : 打開 path 指定的目錄

代碼示例

@Test
public void test3() throws IOException{
    Path path2 = Paths.get("d:\\nio", "hello.txt");

    //		InputStream newInputStream(Path path, OpenOption…how):獲取 InputStream 對象
    InputStream inputStream = Files.newInputStream(path2, StandardOpenOption.READ);

    //		OutputStream newOutputStream(Path path, OpenOption…how) : 獲取 OutputStream 對象
    OutputStream outputStream = Files.newOutputStream(path2, StandardOpenOption.WRITE,StandardOpenOption.CREATE);


    //		SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 獲取與指定文件的連接,how 指定打開方式。
    SeekableByteChannel channel = Files.newByteChannel(path2, StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);

    //		DirectoryStream<Path>  newDirectoryStream(Path path) : 打開 path 指定的目錄
    Path path3 = Paths.get("e:\\teach");
    DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path3);
    Iterator<Path> iterator = directoryStream.iterator();
    while(iterator.hasNext()){
        System.out.println(iterator.next());
    }
}

到此,關于“Java File類的理解與使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

菏泽市| 玉田县| 同德县| 平潭县| 贞丰县| 正定县| 岱山县| 秭归县| 罗山县| 甘洛县| 双江| 八宿县| 文山县| 景洪市| 修文县| 荔浦县| 秦安县| 古丈县| 溧阳市| 芜湖市| 太保市| 广水市| 邢台市| 亳州市| 琼海市| 望谟县| 裕民县| 客服| 濮阳市| 栾川县| 翁源县| 福泉市| 茂名市| 蒙阴县| 巴林右旗| 巩义市| 汝州市| 逊克县| 旅游| 永昌县| 高台县|