天天看點

Java學習筆記之File&遞歸&位元組流

0x00 概述

本文涉及Java知識點為IO流,包括File,遞歸和位元組流。

0x01 File類

1.1 File類概述和構造方法

  • File類介紹

    它是檔案和目錄路徑名的抽象表示

    檔案和目錄是可以通過File類封裝成對象的

    對于File而言,其封裝的并不是一個真正存在的檔案,僅僅是一個路徑而已,它可以是存在的,也可以是不存在的,将來是要通過具體的操作把這個路徑的内容轉換為具體存在的

  • File類的構造方法
Java學習筆記之File&遞歸&位元組流

示例

package FileDemo1;

import java.io.File;

public class FileDemo1 {
    public static void main(String[] args) {
        // File(String pathname): 通過将給定的路徑名字元串轉換為抽象路徑名來建立新的File執行個體
        File f1 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\FileDemo1\\java.txt");
        System.out.println(f1);

        // File(String parent, String child) : 從父路徑名字元串和子路徑名字元串建立新的File執行個體
        File f2 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\FileDemo1\\","java2.txt");
        System.out.println(f2);

        // File(File parent, String child) : 從父抽象路徑名和子路徑名字元串建立新的File執行個體
        File f3 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\FileDemo1\\");
        File f4 = new File(f3,"java3.txt");
        System.out.println(f4);
    }
}           

複制

1.2 File類建立功能

  • 方法分類
Java學習筆記之File&遞歸&位元組流

示例

package FileDemo2;

import java.io.File;
import java.io.IOException;

public class FileDemo2 {
    public static void main(String[] args) throws IOException {
        // 需求1:在C:\Users\119k\IdeaProjects\d17\FileDemo2\目錄下建立一個檔案java.txt
        File f1 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo2\\java.txt");
        System.out.println(f1.createNewFile());
        System.out.println("--------------");


        // 需求2:在C:\Users\119k\IdeaProjects\d17\FileDemo2\目錄下建立一個目錄
        File f2 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo2\\JavaSE\\");
        System.out.println(f2.mkdir());
        System.out.println("--------------");

        // 需求3:在C:\Users\119k\IdeaProjects\d17\FileDemo2\目錄下建立多級目錄\JavaSE\JavaEE\
        File f3 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo2\\JavaSE\\JavaEE\\");
        System.out.println(f3.mkdirs());
        System.out.println("--------------");

        // 需求4:在C:\Users\119k\IdeaProjects\d17\FileDemo2\目錄下建立一個檔案javaSE.txt
        File f4 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo2\\javaSE.txt");
        System.out.println(f4.createNewFile());
        System.out.println("--------------");
    }
}           

複制

1.3 File類判斷和擷取功能

  • 判斷功能
Java學習筆記之File&遞歸&位元組流
  • 擷取功能
Java學習筆記之File&遞歸&位元組流

示例

package FileDemo3;

import java.io.File;

public class FileDemo3 {
    public static void main(String[] args) {
        // 建立一個File對象
        File f = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo3\\JavaSE\\java.txt");

        // public boolean isDirectory(): 測試此抽象路徑名表示的File是否為目錄
        // public boolean isFile(): 測試此抽象路徑名表示的File是否為檔案
        // public boolean exists(): 測試此抽象路徑名表示的File是否存在
        System.out.println(f.isDirectory());
        System.out.println(f.isFile());
        System.out.println(f.exists());
        System.out.println("-------------");

        // public String getAbsolutePath(): 傳回此抽象路徑名的絕對路徑名字元串
        // public String getPath(): 将此抽象路徑名轉換為路徑名字元串
        // public String getName(): 傳回由此抽象路徑名表示的檔案或者目錄的名稱
        System.out.println(f.getAbsolutePath());
        System.out.println(f.getPath());
        System.out.println(f.getName());
        System.out.println("-------------");

        // public String[] list(): 傳回此抽象路徑名表示的目錄中的檔案和目錄的名稱String數組
        // public File[] listFiles(): 傳回此抽象路徑名表示的目錄中的檔案和目錄的名稱File數組
        File f2 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src");

        String[] strArray = f2.list();
        for(String str: strArray) {
            System.out.println(str);
        }
        System.out.println("-------------");

        File[] fileArray = f2.listFiles();
        for(File file: fileArray) {
            System.out.println(file.getName());
        }
    }
}           

複制

1.4 File類删除功能

  • 方法分類
Java學習筆記之File&遞歸&位元組流

示例

package FileDemo4;

import java.io.File;
import java.io.IOException;

public class FileDemo4 {
    public static void main(String[] args) throws IOException {
        // 需求1:在目前子產品目錄下建立java.txt
        File f1 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo4\\Java\\java.txt");
        //System.out.println(f1.createNewFile());
        System.out.println("---------------");

        // 需求2:删除 目前子產品目錄下的java.txt檔案
       // System.out.println(f1.delete());
        System.out.println("---------------");

        // 需求3:在目前子產品目錄下建立Java2目錄
        File f2 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo4\\Java\\Java2");
        // System.out.println(f2.mkdir());

        // 需求4: 删除Java2目錄
        //System.out.println(f2.delete());
        System.out.println("---------------");

        // 需求5: 在目前子產品下建立Java3目錄,在該目錄下再建立一個檔案Java3.txt
        File f3 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo4\\Java3");
        //System.out.println(f3.mkdir());
        File f4 = new File("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileDemo4\\Java3\\Java3.txt");
        // System.out.println(f4.createNewFile());

        // 需求6: 删除目前子產品下的目錄Java3
        System.out.println(f4.delete());
        System.out.println(f3.delete());
    }
}           

複制

  • 絕對路徑和相對路徑的差別

    絕對路徑:完整的路徑名,不需要任何其他資訊就可以定位它所表示的檔案,例如: E:\itcast\java.txt

    相對路徑:必須使用取自其他路徑名的資訊進行解釋,例如: myFile\java.txt

0x02 遞歸

2.1 遞歸

  • 遞歸的介紹

    以程式設計的角度來看,遞歸指的是方法定義中調用方法本身的現象

    把一個複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解

    遞歸政策隻需少量的程式就可以描述出解題過程中所需的多次重複計算

  • 遞歸的基本使用
package RecursionDemo1;

public class RecursionDemo1 {
    public static void main(String[] args) {
        // 回顧不死神兔問題,求第20個月兔子的對數
        // 每個月兔子的對數:1,1,2,3,5,8
        int[] arr = new int[20];

        arr[0] = 1;
        arr[1] = 1;

        for (int i = 2; i < arr.length; i++) {
            arr[i] = arr[i - 1] + arr[i - 2];
        }

        System.out.println(arr[19]);
        System.out.println(f(20));
    }

    public static int f(int n) {
        if (n == 1 || n == 2) {
            return 1;
        } else {
            return f(n - 1) + f(n - 2);
        }
    }
}           

複制

  • 遞歸的注意事項

    遞歸一定要有出口,否則記憶體溢出

    遞歸雖然有出口,但是遞歸的次數也不宜過多,否則記憶體溢出

2.2 遞歸求階乘

  • 案例需求

    用遞歸求5的階乘,并把結果在控制台輸出

示例

package RecursionDemo2;

public class RecursionDemo2 {
    public static void main(String[] args) {
        // 調用方法
        int result = jc(5);
        // 輸出結果
        System.out.println(result);
    }

    // 定義各異方法,用于遞歸求階乘,參數為一個int類型的變量
    public static int jc(int n) {
        if(n == 1) {
            // 是1,傳回1
            return 1;
        }else{
            // 不是1,傳回n*(n-1)!
            return n*jc(n-1);
        }
    }
}           

複制

2.3 遞歸周遊目錄

需求:給定一個路徑(E:\ itcast),通過遞歸完成周遊該目錄下所有内容,并把所有檔案的絕對路徑輸出在控制

示例:

package RecursionDemo3;

import java.io.File;

public class RecursionDemo3 {
    public static void main(String[] args) {
        // 根據給定的路徑建立一個File對象
        File srcFile = new File("E:\\itcast");

        // 調用方法
        getAllFilePath(srcFile);
    }

    public static void getAllFilePath(File srcFile){
        // 擷取給定的File目錄下所有的檔案或者目錄的File數組
        File[] fileArray = srcFile.listFiles();

        // 周遊該File數組,得到每一個File對象
        if(fileArray != null) {
            for(File file: fileArray) {
                // 判斷該File對象是否是目錄
                if(srcFile.isDirectory()) {
                    // 是:遞歸調用
                    getAllFilePath(file);
                } else {
                    // 不是,擷取絕對路徑輸出到控制台
                    System.out.println(file.getAbsolutePath());
                }
            }
        }
    }
}           

複制

0x03 IO流

3.1 IO流概述和分類

  • IO流介紹

    IO:輸入/輸出(Input/Output)

    流:是一種抽象概念,是對資料傳輸的總稱,也就是說資料在裝置鍵的傳輸成為流,流的本質是資料傳輸

    IO流就是用來處理裝置間資料傳輸問題的,常見的應用:檔案複制,檔案上傳,檔案下載下傳

  • IO流的分類

    按照資料的流向

      輸入流:讀資料

      輸出流:寫資料

    按照資料類型來分

      位元組流

        位元組輸入流

        位元組輸出流

      字元流

        字元輸入流

        字元輸出流

  • IO流的使用場景

    如果是純文字檔案,優先使用字元流

    如果操作的是圖檔,視訊,音頻等二進制檔案,優先使用位元組流

    如果不确定檔案類型,優先使用位元組流,位元組流是萬能的

3.2 位元組流寫資料

  • 位元組流抽象基類

    InputStream: 這個抽象類是表示位元組輸入流的所有類的超類

    OutputStream: 這個抽象類是表示位元組輸出流的所有類的超類

    子類名特點:子類名稱都是以其父類名作為子類名的字尾

  • 位元組輸出流

    FileOutputStream(String name): 建立檔案輸出流以指定的名稱寫入檔案

  • 使用位元組輸出流寫資料的步驟

    建立位元組輸出流對象(調用系統功能建立了檔案,建立位元組輸出流對象,讓位元組輸出流對象指向檔案)

    調用位元組輸出流對象的寫資料方法

    釋放資源(關閉此檔案輸出流并釋放與此流相關聯的任何系統資源)

示例

package FileOutputStreamDemo1;


import java.io.FileOutputStream;
import java.io.IOException;

public class FileoOutputStreamDemo1 {
    public static void main(String[] args) throws IOException {
        // 建立位元組輸出流對象
        // FileOutputStream(String name): 建立檔案輸出流以指定的名稱寫入檔案
        FileOutputStream fos = new FileOutputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileOutputStreamDemo1\\myByteStreamfos.txt");
        /*
            做了三件事:
                A 調用了系統功能建立了檔案
                B 建立了位元組輸出流對象
                C 讓位元組輸出流對象指向建立好的檔案
         */

        // void write(int b): 将指定的位元組寫入此檔案輸出流
        fos.write(97);
        fos.write(98);
        fos.write(99);

        // 釋放資源
        // void close(): 關閉此檔案輸出流并釋放與此相關聯的任何系統資源
        fos.close();
    }
}           

複制

3.3 位元組流寫資料的三種方式

  • 寫資料的方法分類
Java學習筆記之File&amp;遞歸&amp;位元組流

示例

package FileOutputStreamDemo2;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo2 {
    public static void main(String[] args) throws IOException {
        // FileOutputStream(String name): 建立檔案輸出流以指定的名稱寫入檔案
        FileOutputStream fos = new FileOutputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\myByteStream\\fos.txt");

        // new File(name)
        //FileOutputStream fos = new FileOutputStream(new File("myByteStream\\fos.txt");

        // FileOutputStream(File file): 建立檔案輸出流以寫入指定的File對象表示的檔案
        // File file = new File("myByteStream\\\\fos.txt");
        // FileOutputStream fos2 = new FileOutputStream(file);
        // FileOutputStream fos2 = new FileOutputStream(new File("myByteStream\\\\fos.txt"));

        // void write(int b): 将指定的位元組吸入此檔案輸出流
        // fos.write(97);
        // fos.write(98);
        // fos.write(99);
        // fos.write(100);
        // fos.write(101);

        // void write(byte[] b): 将b.length位元組從指定的位元組數組寫入檔案輸出流
        // byte[] bys = {97, 98, 99, 100, 101};
        // fos.write(bys);

        // byte[] getBytes(): 傳回字元串對應的位元組數組
        // byte[] bys = "abcde".getBytes();
        // fos.write(bys);

        // void write(byte[] b, int off, int len): 将len位元組從指定的位元組數組開始,從偏移量off開始寫入檔案輸出流
        // fos.write(bys, 0, bys.length);
        // fos.write(bys, 1, 3);

        // 釋放資源
        fos.close();
    }
}           

複制

3.4 位元組流寫資料的兩個小問題

  • 位元組流寫資料如何實作換行

    windows: \r\n

    linux: \n

    mac: \r

  • 位元組流寫資料如何實作追加寫入

    public FileOutputStream(String name, boolean append)

    建立檔案輸出流以指定的名稱寫入檔案,如果第二個參數為true,則位元組将寫入檔案的末尾而不是開頭

示例

package FileOutputStreamDemo3;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamDemo3 {
    public static void main(String[] args) throws IOException {
        // 建立位元組輸出流對象
        // FileOutputStream fos = new FileOutputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileOutputStreamDemo3\\fos.txt");
        FileOutputStream fos = new FileOutputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileOutputStreamDemo3\\fos.txt", true);

        // 寫資料
        for (int i = 0; i < 10; i++) {
            fos.write("hello".getBytes());
            fos.write("\r\n".getBytes());
        }

        // 釋放資源
        fos.close();
    }
}           

複制

3.5 位元組流寫資料加異常處理

  • 異常處理格式

    try-catch-finally

try{
    可能出現異常的代碼
}catch() {
    異常的處理代碼
}finally{
    執行所有清除操作    
}           

複制

    finally特點

      被finally控制的語句一定會執行,除非JVM退出

示例

package FileOutputStreamDemo4;

import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputDemo4 {
    public static void main(String[] args) throws IOException {
        // 加入finally來實作釋放資源
        FileOutputStream fos = null;

        try {
            fos = new FileOutputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileOutputStreamDemo4\\fos.txt");
            fos.write("hello".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}           

複制

3.6 位元組流讀資料

  • 位元組輸入流

    FileInputStream(String name):通過打開與實際檔案的連結來建立一個FileputStream,該檔案由檔案系統中的路徑名name命名

  • 位元組輸入流讀取資料的步驟

    建立位元組輸入流對象

    調用位元組輸入流對象的讀資料方法

    釋放方法

示例

package FileOutputStreamDemo5;

import java.io.FileInputStream;
import java.io.IOException;

public class FileOutputStreamDemo5 {
    public static void main(String[] args) throws IOException {
        // 建立位元組輸入流對象
        // FileInputStream(String name)
        FileInputStream fis = new FileInputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\FileOutputStreamDemo5\\fos.txt");

        int by;

        /*
            fis.read():  讀資料
            by = fis.read(): 把讀取到的資料指派給by
            by != -1: 判斷讀取到的資料是否是-1
         */
        while ((by = fis.read()) !=-1){
            System.out.println((char)by);
        }

        // 釋放資源
        fis.close();
    }
}           

複制

3.7 位元組流複制文本檔案

  • 案例需求:把E:\itcast\窗裡窗外.txt 複制到子產品目錄下
  • 實作步驟

    複制文本檔案,其實就是把文本檔案的内容從過一個檔案中讀取出來(資料源),然後寫入到另一個檔案中(目的地)

    資料源: E:\itcast\窗裡窗外.txt -- 讀資料 -- InputStream -- FileInputStream

    目的地: myBestStream\窗裡窗外.txt -- 寫資料 -- OutputStream -- FileOutputStream

示例

package CopyTextDemo;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyTextDemo {
    public static void main(String[] args) throws IOException {
        // 根據資料源建立位元組輸入流對象
        FileInputStream fis = new FileInputStream("E:\\itcast\\窗裡窗外.txt");

        // 根據目的地建立位元組輸出流對象
        FileOutputStream fos = new FileOutputStream("E:\\itcast2\\窗裡窗外.txt");

        // 讀寫資料,複制文本檔案(一次讀取一個位元組,一次寫入一個位元組)
        int by;
        while ((by = fis.read()) != -1) {
            fos.write(by);
        }
        // 釋放資源
        fos.close();
        fis.close();
    }
}           

複制

3.8 位元組流讀資料(一次讀一個位元組數組資料)

  • 一次讀一個位元組數組的方法

    public int read(byte[] b) : 從輸入流讀取最多b.length個位元組的資料

    傳回的是讀入緩沖區的總位元組數,也就是實際的讀取位元組個數

示例

package CopyTextDemo2;

import java.io.FileInputStream;
import java.io.IOException;

public class CopyTextDemo2 {
    public static void main(String[] args) throws IOException {
        // 建立位元組流輸入對象
        FileInputStream fis = new FileInputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\CopyTextDemo2\\fos.txt");

        byte[] bys = new byte[1024]; // 1024及其整數倍

        int len;

        while ((len = fis.read()) != -1) {
            System.out.println(new String(bys, 0, len));
        }
        
        // 釋放資源
        fis.close();
    }
}           

複制

3.9 位元組流複制圖檔

  • 案例需求:把E:\itcast\mn.jpg複制到子產品目錄下
  • 實作步驟

    根據資料源建立位元組輸入流對象

    根據目的地建立位元組輸出流對象

    讀寫資料,複制圖檔(一次讀取一個位元組數組,一次寫入一個位元組數組)

    釋放資源

示例

package CooyJPGDemo;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.FileOutputStream;

public class CopyJPGDemo {
    public static void main(String[] args) throws IOException {
        // 根據資料源建立位元組輸入流對象
        FileInputStream fis = new FileInputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\CooyJPGDemo\\mn.jpg");

        // 根據目的地建立位元組輸出流對象
        FileOutputStream fos = new FileOutputStream("C:\\Users\\119k\\IdeaProjects\\d17\\src\\CooyJPGDemo\\mn2.jpg");

        // 讀寫資料,複制圖檔(一次讀取一個位元組數組,一次寫入一個位元組數組)
        byte[] bys = new byte[1024];
        int len;
        while ((len = fis.read(bys)) != -1) {
            fos.write(bys, 0, len);
        }

        // 釋放資源
        fos.close();
        fis.close();
    }
}           

複制