Java基礎系列——文件和流(29)

文件和Stream

這裏介紹關於文件以及在Java中常用的IO流。

java.io.File

在文件系統中,文件名是用於定位存儲位置 元數據:描述數據的數據,在這裏我們將一個文件當作一個數據,那麼文件的屬性就是元數據。

java.io.File 類代表與當前系統平臺無關的文件和目錄;File 類的一個實例就代表一個文件或目錄;File 類提供了判斷其實例是文件還是目錄的方法;File 類提供了可以操作文件系統中的文件和目錄的方法;File 類僅代表文件或目錄,不支持對文件的內容進行修改。

官方聲明

public class File
extends Object
implements Serializable, Comparable<File>

該類是可以通過compareTo進行比較的,同時實現了序列化接口。

官方說明

An abstract representation of file and directory pathnames. User interfaces and operating systems use system-dependent pathname strings to name files and directories. This class presents an abstract, system-independent view of hierarchical pathnames. An abstract pathname has two components:

  1. An optional system-dependent prefix string, such as a disk-drive specifier, "/" for the UNIX root directory, or "\\" for a Microsoft Windows UNC pathname, and
  2. A sequence of zero or more string names.

The first name in an abstract pathname may be a directory name or, in the case of Microsoft Windows UNC pathnames, a hostname. Each subsequent name in an abstract pathname denotes a directory; the last name may denote either a directory or a file. The empty abstract pathname has no prefix and an empty name sequence.

文件和目錄路徑名的抽象表示形式。

用戶界面和操作系統使用與系統相關的路徑名字符串 來命名文件和目錄。此類呈現分層路徑名的一個抽象的、與系統無關的視圖。抽象路徑名 有兩個組件:

  1. 一個可選的與系統有關的前綴 字符串,比如盤符,"/" 表示 UNIX 中的根目錄,"\\\\" 表示 Microsoft Windows UNC 路徑名。
  2. 零個或更多字符串名稱 的序列。

抽象路徑名中的第一個名稱是目錄名,對於 Microsoft Windows UNC 路徑名則是主機名。抽象路徑名中第一個名稱之後的每個名稱表示一個目錄;最後一個名稱既可以表示目錄,也可以表示文件。 抽象路徑名沒有前綴和名稱序列。

注意:==File 類的實例是不可變的;也就是說,一旦創建,File 對象表示的抽象路徑名將永不改變。==

內部字段

該類中定義了一些內部字段,主要是用來進行定義分割符的,有以下四種:

Modifier and Type Field Description 翻譯
static String pathSeparator The system-dependent path-separator character, represented as a string for convenience. 與系統有關的路徑分隔符,爲了方便,它被表示爲一個字符串。
static char pathSeparatorChar The system-dependent path-separator character. 與系統相關的路徑分隔符。
static String separator The system-dependent default name-separator character, represented as a string for convenience. 與系統有關的默認名稱分隔符,爲了方便,它被表示爲一個字符串。
static char separatorChar The system-dependent default name-separator character. 與系統有關的默認名稱分隔符

具體示例如下:

public class TestFile01 {
    public static void main(String[] args) throws IOException {
        String pathSeparator = File.pathSeparator;
        System.out.println( pathSeparator );

        char pathSeparatorChar = File.pathSeparatorChar;
        System.out.println( pathSeparatorChar );

        String separator = File.separator;
        System.out.println( separator );

        char separatorChar = File.separatorChar;
        System.out.println( separatorChar );
    }
}

注意:根據系統的不一樣,那麼得出的結果也是不一樣的。本人這裏使用的Windows,得到的結果是:;;\\

構造方法

該類暴露出來有四種構造方法,如下所示: |Constructor|Description|翻譯| | ---- | ---- | ---- | ---- | |File​(File parent, String child)|Creates a new File instance from a parent abstract pathname and a child pathname string.|根據 parent 抽象路徑名和 child 路徑名字符串創建一個新 File 實例。| |File​(String pathname)|Creates a new File instance by converting the given pathname string into an abstract pathname.|通過將給定路徑名字符串轉換爲抽象路徑名來創建一個新 File 實例。| |File​(String parent, String child)|Creates a new File instance from a parent pathname string and a child pathname string.|根據 parent 路徑名字符串和 child 路徑名字符串創建一個新 File 實例。| |File​(URI uri)|Creates a new File instance by converting the given file: URI into an abstract pathname.|通過將給定的 file: URI 轉換爲一個抽象路徑名來創建一個新的 File 實例。|

具體示例如下:

public class TestFile02 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\") ;
        System.out.println( file );

        file = new File( file , "後端學習\\Java基礎") ;
        System.out.println( file );

        file = new File( "E:\\後端學習" , "Java基礎" ) ;
        System.out.println( file );

        file = new File( file.toURI() ) ;
        System.out.println( file );

        file = new File(".") ;
        System.out.println( file );
        System.out.println( file.getAbsolutePath() );

        file = new File("/");
        System.out.println( file );
        System.out.println( file.getAbsolutePath() );
    }
}

在IDEA的開發環境中,如果在路徑上寫了一個.,那麼就表示當前的路徑爲 工程路徑 ;一個\ 那麼就表示盤符(windows環境下)。

具體方法

static方法

createTempFile

該方法有重載:

  • createTempFile(String prefix, String suffix) : 在默認臨時文件目錄中創建一個空文件,使用給定前綴和後綴生成其名稱。
  • createTempFile(String prefix, String suffix, File directory) : 在指定目錄中創建一個新的空文件,使用給定的前綴和後綴字符串生成其名稱。

具體示例如下:

public class TestFile03 {
    public static void main(String[] args) throws IOException {
        File tempFile = File.createTempFile("haha", ".md");
        System.out.println( tempFile );
        tempFile = File.createTempFile( "haha" , ".md" , new File("E:\\")) ;
        System.out.println( tempFile );
    }
}

需要注意的是:在文件名中間會生成一個Long類型的隨機數,用於構建這個臨時文件。如果是沒有指定文件夾的話,那麼會在C:\Users\當前的計算機用戶\AppData\Local\Temp這裏生成對應的文件;如果指定的文件夾,那麼就會在對應的文件夾下生成文件。

listRoots

列出可用的文件系統根。

示例如下:

public class TestFile04 {
    public static void main(String[] args) throws IOException {
        File[] files = File.listRoots();
        for (File file : files) {
            System.out.println( file );
        }
    }
}

在windows系統中,會獲取所有的盤符表示文件下的根。(沒有在Linux的環境中進行測試)

實例方法

can方法

can方法表示該文件具有什麼樣子的能力,具體方法如下所示:

  • canExecute() : 判斷該文件或文件夾是否是可以執行的。當且僅當抽象路徑名存在 允許應用程序執行文件時返回 true
  • canRead() : 是否可以讀取此抽象路徑名錶示的文件。當且僅當此抽象路徑名指定的文件存在 可被應用程序讀取時,返回 true;否則返回 false
  • canWrite() :是否可以修改此抽象路徑名錶示的文件。允許寫入返回true

具體示例如下:

public class TestFile05 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\後端學習\\Java基礎\\Java基礎系列(01)——入門概述.md");
        boolean b = file.canExecute();
        System.out.println( b );

        b = file.canRead() ;
        System.out.println( b );

        b = file.canWrite() ;
        System.out.println( b );
    }
}
比較

該系列方法有兩個:compareToequals。具體示例如下:

public class TestFile06 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\後端學習\\Java基礎\\Java基礎系列(01)——入門概述.md");
        File file1 = new File("E:\\後端學習\\Java基礎") ;
        // 獲取文件名,然後比較的是文件名對應的字符串
        int i = file.compareTo(file1);
        System.out.println( i );
        // 內部調用compareTo方法進行比較
        boolean equals = file.equals(file1);
        System.out.println( equals );
    }
}

說明:

在compareTo方法內部,其實是調用了==f1.getPath().compareToIgnoreCase(f2.getPath());==代碼,那麼這裏就可以看出來是比較的是字符串。

equals 方法內部調用了 compareTo方法。

操作文件

該系列方法包含了以下方法:

  • createNewFile() : 當且僅當不存在具有此抽象路徑名指定名稱的文件時,不可分地創建一個新的空文件。
  • delete() :刪除此抽象路徑名錶示的文件或目錄。
  • deleteOnExit() : 在虛擬機終止時,請求刪除此抽象路徑名錶示的文件或目錄。
  • mkdir():創建此抽象路徑名指定的目錄。
  • mkdirs() : 創建此抽象路徑名指定的目錄,包括所有必需但不存在的父目錄。

具體示例如下:

public class TestFile07 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\後端學習\\Java基礎\\kaka.md");
        boolean newFile = file.createNewFile();
        System.out.println( newFile );

        boolean delete = file.delete();
        System.out.println( delete );

        file = new File("E:\\後端學習\\Java基礎\\hah");
        boolean mkdirs = file.mkdirs();
        System.out.println( mkdirs );
        boolean mkdir = file.mkdir();
        System.out.println( mkdir );
        file.deleteOnExit();
    }
}
get方法

該系列方法主要是獲取一些數據,有如下所示方法:

  • getAbsoluteFile() :返回此抽象路徑名的絕對路徑名形式。
  • getAbsolutePath() : 返回此抽象路徑名的絕對路徑名字符串。
  • getCanonicalFile() : 返回此抽象路徑名的規範形式。
  • getCanonicalPath() : 返回此抽象路徑名的規範路徑名字符串。
  • getFreeSpace() : 返回此抽象路徑名指定的分區中未分配的字節數。
  • getName() : 返回由此抽象路徑名錶示的文件或目錄的名稱
  • getParent() : 返回此抽象路徑名父目錄的路徑名字符串;如果此路徑名沒有指定父目錄,則返回 null
  • getParentFile() : 返回此抽象路徑名父目錄的抽象路徑名;如果此路徑名沒有指定父目錄,則返回 null
  • getPath() :將此抽象路徑名轉換爲一個路徑名字符串。
  • getTotalSpace():返回此抽象路徑名指定的分區大小。
  • getUsableSpace():返回此抽象路徑名指定的分區上可用於此虛擬機的字節數。
  • lastModified() : 返回此抽象路徑名錶示的文件最後一次被修改的時間。
  • length() :返回由此抽象路徑名錶示的文件的長度。

可以看到該系列方法是主要是獲取File對象的一些屬性,具體示例如下:

public class TestFile08 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\後端學習\\Java基礎\\Java基礎1.pdf");
        File absoluteFile = file.getAbsoluteFile();
        System.out.println( absoluteFile );
        String absolutePath = file.getAbsolutePath();
        System.out.println( absolutePath );

        File canonicalFile = file.getCanonicalFile();
        System.out.println( canonicalFile );
        String canonicalPath = file.getCanonicalPath();
        System.out.println( canonicalPath );

        long freeSpace = file.getFreeSpace();
        System.out.println( freeSpace );

        String name = file.getName();
        System.out.println( name  );

        String parent = file.getParent();
        System.out.println( parent );
        File parentFile = file.getParentFile();
        System.out.println( parentFile );

        String path = file.getPath();
        System.out.println( path );

        long totalSpace = file.getTotalSpace();
        System.out.println( totalSpace );

        long usableSpace = file.getUsableSpace();
        System.out.println( usableSpace );

        long l = file.lastModified();
        System.out.println( l );

        long length = file.length();
        System.out.println( length );

    }
}
is方法

該系列方法主要是進行判斷File對象是否是存在等操作。

  • exists() : 判斷文件是否存在
  • isAbsolute() : 是否是絕對路徑
  • isDirectory() : 是否是一個文件夾
  • isFile() : 是否是一個文件
  • isHidden() : 是否是隱藏的

具體示例如下:

public class TestFile09 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\後端學習\\Java基礎\\Java基礎1.pdf");
        boolean exists = file.exists();
        System.out.println( exists );

        boolean absolute = file.isAbsolute();
        System.out.println( absolute );

        boolean directory = file.isDirectory();
        System.out.println( directory );

        boolean file1 = file.isFile();
        System.out.println( file1 );

        boolean hidden = file.isHidden();
        System.out.println( hidden );
    }
}
list

該系列方法主要獲取一個文件夾內的所有文件構成的數組或者是文件名那個組成的數組。

  • list() : 返回一個字符串數組,這些字符串指定此抽象路徑名錶示的目錄中的文件和目錄。
  • list(FilenameFilter filter) : 返回一個字符串數組,這些字符串指定此抽象路徑名錶示的目錄中滿足指定過濾器的文件和目錄。
  • listFiles() : 返回一個抽象路徑名數組,這些路徑名錶示此抽象路徑名錶示的目錄中的文件。
  • listFiles(FileFilter filter) : 返回抽象路徑名數組,這些路徑名錶示此抽象路徑名錶示的目錄中滿足指定過濾器的文件和目錄。
  • listFiles(FilenameFilter filter) : 返回抽象路徑名數組,這些路徑名錶示此抽象路徑名錶示的目錄中滿足指定過濾器的文件和目錄。
  • listRoots() : 列出可用的文件系統根。

具體示例如下:

public class TestFile10 {
    public static void main(String[] args) throws IOException {
        File dir = new File("E:\\後端學習\\Java基礎") ;
        String[] list = dir.list();
        for (String s : list) {
            System.out.println( s );
        }
        System.out.println("--------------------");
        String[] mds = dir.list((dir1, name) -> name.endsWith("md"));
        for (String md : mds) {
            System.out.println( md );
        }
        System.out.println("--------------------");

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

        File[] javas = dir.listFiles((file, name) -> name.startsWith("Java"));
        for (File java : javas) {
            System.out.println( java );
        }

        System.out.println("-----------------------------");

        File[] mds1 = dir.listFiles(pathname -> pathname.getName().endsWith("md"));
        for (File file : mds1) {
            System.out.println( file );
        }
        System.out.println("-----------------------------");
        File[] files1 = File.listRoots();
        for (File file : files1) {
            System.out.println( file );
        }
    }
}

注意:listRoots方法爲static修飾的方法。

set方法

set系列的方法表示給文件對象設置一些屬性

  • setExecutable(boolean executable) :設置此抽象路徑名所有者執行權限的方法。
  • setExecutable(boolean executable, boolean ownerOnly) : 設置此抽象路徑名的所有者或所有用戶的執行權限。
  • setLastModified(long time) : 設置此抽象路徑名指定的文件或目錄的最後一次修改時間。
  • setReadable(boolean readable) : 設置此抽象路徑名所有者讀權限的方法。
  • setReadable(boolean readable, boolean ownerOnly) : 設置此抽象路徑名的所有者或所有用戶的讀權限。
  • setReadOnly() : 標記此抽象路徑名指定的文件或目錄,從而只能對其進行讀操作。
  • setWritable(boolean writable) : 設置此抽象路徑名所有者寫權限的方法。
  • setWritable(boolean writable, boolean ownerOnly) : 設置此抽象路徑名的所有者或所有用戶的寫權限。
public class TestFile11 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\後端學習\\Java基礎\\Java基礎系列(23)——JDK1.8之後的時間與日期.pdf") ;
        boolean b = file.setExecutable(true);
        System.out.println( b );

       b  = file.setExecutable(true, false);
        System.out.println( b );
        b = file.setLastModified( System.currentTimeMillis() ) ;
        System.out.println( b );

        b = file.setReadable( false ) ;
        System.out.println( b );

        b = file.setReadable( true , true) ;
        System.out.println( b );
        b = file.setReadOnly() ;
        System.out.println( b );

        b = file.setWritable( false ) ;
        System.out.println( b );

        b = file.setWritable( true , true ) ;
        System.out.println( b );

    }
}
其他方法

這裏會介紹在上邊沒有出現過的方法

  • renameTo( File file ) :重新命名此抽象路徑名錶示的文件
  • toString() : 返回此抽象路徑名的路徑名字符串。
  • toPath() : 返回從此抽象路徑構造的java.nio.file.Path對象。
  • toURI() : 構造一個表示此抽象路徑名的 file: URI。

具體示例如下:

public class TestFile12 {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\後端學習\\Java基礎\\Java基礎系列(23)——JDK1.8之後的時間與日期.pdf") ;
        URI uri = file.toURI();
        System.out.println( uri );

        Path path = file.toPath();
        System.out.println( path );

        boolean b = file.renameTo(new File( file.getName() );
        System.out.println( b );
    }
}

Stream

Java語言中,把一組有序的數據序列稱爲流(Stream)。

那麼在Java體系中,按照操作的類型(數據的流向)可以分爲

  • 輸入流,向程序中輸入(注意是針對程序的)
  • 輸出流,從程序中輸出

注意:Java中的輸入還是輸出,都是相對於當前程序的!

按數據流中最小的數據單元分爲

  • 字節流,數據流中最小的數據單元是字節,Stream 結束的 基本上都是 字節流。
  • 字符流,數據中最小的數據單元是字符,以 Reader 結束 或 以 Writer 結束的流基本都是字符流。

按功能分爲節點流和包裝流

  • 節點流,可以從或向一個特定的IO設備讀/寫數據的流,節點流也常常被稱爲低級流。如 FileReader ,從一個指定的地方讀取文件。
  • 包裝流(處理流、過濾流):是對一個已存在的流的連接和封裝,通過所封裝的流的功能調用實現數據讀寫。如 BufferedReader,處理流的構造方法總是要帶一個其他的流對象做參數。一個流對象經過其他流的多次包裝,稱爲流的鏈接。

Java中的 IO 涉及幾十個類,這幾十個類大都是從 4 個抽象基類中派生出來的:

  • 輸入流的基類:InputStream / Reader

  • 輸出流的基類:OutputStream / Writer

根據輸入輸出、數據傳輸的最小單元,可以做出以下表格:

字節流 字符流
輸入流 InputStream Reader
輸出流 OutputStream Writer

字節流

在字節流中主要進行輸入輸出流的使用。一般在使用的時候,基本上就是結合使用。

java.io.InputStream

官方聲明
public abstract class InputStream extends Object implements Closeable

該類是一個抽象類,那麼就意味着沒有辦法使用構造方法進行實例化,實現了Closeable接口,那麼就會有close方法。

This abstract class is the superclass of all classes representing an input stream of bytes.

Applications that need to define a subclass of InputStream must always provide a method that returns the next byte of input.

此抽象類是表示字節輸入流的所有類的父類。需要定義 InputStream 子類的應用程序必須總是提供返回下一個輸入字節的方法。

方法描述
nullInputStream()

該方法爲static修飾的方法,那麼就是可以通過類直接訪問。該方法返回一個不讀取任何字節的新 InputStream 。 示例如下:

public class TestInputStream {
    public static void main(String[] args) {
        // 該方法主要返回一個不讀取任何字節的InputStream
        // 採用匿名內部類的方式進行實現
        InputStream inputStream = InputStream.nullInputStream();
        System.out.println( inputStream );
    }
}
read

read方法表示從字節輸入流(InputStream)讀取字節,該方法有重載,具體如下:

  • read() : 從輸入流中讀取數據的下一個字節。
  • read(byte[] b) : 從輸入流中讀取一定數量的字節,並將其存儲在緩衝區數組 b 中。
  • read(byte[] b, int off, int len) : 將輸入流中最多 len 個數據字節讀入 byte 數組。
  • readAllBytes() : 讀取所有字節
  • readNBytes(byte[] b, int off, int len) : 從輸入流中讀取請求的字節數到給定的字節數組中
  • readNBytes(int len):從輸入流中讀取指定的字節數。

具體示例如下:

public class TestInputStream02 {
    public static void main(String[] args) throws IOException {
        String path = "E:\\後端學習\\Java基礎\\Java基礎系列(01)——入門概述.md" ;
        InputStream inputStream = new FileInputStream(path) ;
        int read = inputStream.read();
        System.out.println( read );

        byte[] bytes = new byte[1<<12] ;
        int read1 = inputStream.read(bytes);
        System.out.println( read1 );
        System.out.println(Arrays.toString( bytes ));
        System.out.println( new String( bytes ));

        System.out.println("------------------");

        byte[] bytes2 = inputStream.readNBytes(10);
        System.out.println( new String( bytes2 ));

        System.out.println("------------------");

        int i = inputStream.readNBytes(bytes2, 0, 10);
        System.out.println( i );
        System.out.println( new String(bytes2));
        System.out.println("-----------------------");

        byte[] bytes1 = inputStream.readAllBytes();
        System.out.println( new String( bytes1 ));
    }
}

read方法有返回值,當讀取到文件末尾的時候返回-1,通常用這個值進行判斷是否已經讀取完文件

標記相關

該系列方法是用於標記-取消-重置(重定位)的,經常用於有緩衝區的流中進行操作。具體方法如下:

  • mark(int readlimit) : 在此輸入流中標記當前的位置。
  • markSupported() : 測試此輸入流是否支持 markreset 方法。
  • reset() : 將此流重新定位到最後一次對此輸入流調用 mark 方法時的位置。

具體示例如下:

public class TestInputStream03 {
    public static void main(String[] args) throws IOException {
        String path = "E:\\IdeaProject\\JavaSystem\\baseJava\\src\\cn\\lujiapeng\\io_stream\\TestInput.txt";
        InputStream inputStream = new BufferedInputStream(new FileInputStream(path));
        // 判斷是否支持做標記
        boolean supported = inputStream.markSupported();
        if (supported) {
            byte[] bytes = new byte[1 << 4];
            int read = inputStream.read(bytes, 0, bytes.length);
            System.out.println(read);
            inputStream.mark(4);
            inputStream.read();
            System.out.println(new String(bytes));
            inputStream.reset();
            int read1 = inputStream.read( bytes , 0 , bytes.length );
            System.out.println(read1);
            System.out.println( new String( bytes ));
        }
    }
}
skip

該方法表示跳過指定的字節數,那麼如果是跳過的話,就表示不再進行讀取。示例如下:

public class TestInputStream04 {
    public static void main(String[] args) throws IOException {
        String path = "E:\\IdeaProject\\JavaSystem\\baseJava\\src\\cn\\lujiapeng\\io_stream\\TestInput.txt";
        InputStream inputStream = new FileInputStream( path ) ;
        inputStream.skip( 10 ) ;
        byte[] bytes = new byte[1<<4] ;
        int read = inputStream.read(bytes);
        System.out.println( read );
        System.out.println( new String( bytes ));
        inputStream.close();
    }
}
transferTo(OutputStream out)

從此輸入流中讀取所有字節,並按讀取的順序將字節寫入給定的輸出流。示例如下:

public class TestInputStream05 {
    public static void main(String[] args) throws IOException {
        String path = "E:\\IdeaProject\\JavaSystem\\baseJava\\src\\cn\\lujiapeng\\io_stream\\TestInput.txt";
        InputStream inputStream = new FileInputStream( path ) ;
        File file = new File("test_transferTo.txt");
        OutputStream outputStream = new FileOutputStream(file);
        inputStream.transferTo( outputStream ) ;
        outputStream.close();
        inputStream.close();
    }
}

java.io.OutputStream

官方說明
public abstract class OutputStream extends Object implements Closeable, Flushable

該類是一個抽象類,那麼就意味着沒有辦法使用構造方法進行實例化,實現了Closeable接口,那麼就會有close方法;同時實現了Flushable接口,就會有flush方法

This abstract class is the superclass of all classes representing an output stream of bytes. An output stream accepts output bytes and sends them to some sink.

Applications that need to define a subclass of OutputStream must always provide at least a method that writes one byte of output.

此抽象類是表示輸出字節流的所有類的父類。輸出流接受輸出字節並將這些字節發送到某個接收器。需要定義 OutputStream 子類的應用程序必須始終提供至少一種可寫入一個輸出字節的方法。

方法描述
nullOutputStream()

該方法爲static修飾的方法,那麼就是可以通過類直接訪問。該方法返回一個不讀取任何字節的新 OutputStream。 示例如下:

public class TestOutputStream {
    public static void main(String[] args) throws IOException {
        // 該方法主要返回一個丟棄所有字節的OutputStream
        // 採用匿名內部類的方式進行實現
        OutputStream outputStream = OutputStream.nullOutputStream() ;
        System.out.println( outputStream );
    }
}
write

write方法表示向字節輸出流(OutputStream)寫出字節,該方法有重載,具體如下:

  • write(byte[] b) : 將 b.length 個字節從指定的 byte 數組寫入此輸出流。
  • write(byte[] b, int off, int len) : 將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此輸出流。
  • write(int b) : 將指定的字節寫入此輸出流。

具體示例如下:

public class TestOutputStream02 {
    public static void main(String[] args) throws IOException {
        File file = new File("./baseJava/src/cn/lujiapeng/io_stream/TestOutput.txt");
        OutputStream outputStream = new FileOutputStream(file);
        outputStream.write(123);
        byte[] bytes = new byte[]{97,98,99,100,101,102,103,104} ;
        outputStream.write( bytes );

        outputStream.write( bytes , 0 , 5);
    }
}
flush && close

這兩個方法主要是進行將流關閉和刷出。描述如下:

  • close() : 關閉此輸出流並釋放與此流有關的所有系統資源。
  • flush() : 刷新此輸出流並強制寫出所有緩衝的輸出字節。

通常在寫出的最後將流進行刷出和關閉操作。示例如下:

public class TestOutputStream03 {
    public static void main(String[] args) throws IOException {
        File file = new File("./baseJava/src/cn/lujiapeng/io_stream/TestOutput.txt");
        OutputStream outputStream = new FileOutputStream(file);
        outputStream.write(123);
        byte[] bytes = new byte[]{97,98,99,100,101,102,103,104} ;
        outputStream.write( bytes );

        outputStream.write( bytes , 0 , 5);
        // 這裏使用 FileOutputStream作爲子類進行構建
        // 但是 FileOutputStream並沒有對flush方法進行重寫,所以這裏flush方法並沒有起到效果
        outputStream.flush();
        // 關閉流,節省資源
        outputStream.close();
    }
}

以上就是兩個字節流的所有父類中的方法,以及對應的操作。

FileInputStream && FileOutputStream

FileInputStreamFileOutputStream分別是InputStreamOutputStream的子類,主要是針對於文件進行操作。

這兩個類中的方法並沒有什麼特殊的方法(getChannel放在NIO中描述),這裏只進行描述對應的構造方法,並給出對應的示例。

java.io.FileInputStream

構造方法:

  • FileInputStream(File file) : 通過打開一個到實際文件的連接來創建一個 FileInputStream,該文件通過文件系統中的 File 對象 file 指定。
  • FileInputStream(FileDescriptor fdObj) : 通過使用文件描述符 fdObj 創建一個 FileInputStream,該文件描述符表示到文件系統中某個實際文件的現有連接。
  • FileInputStream(String name) : 通過打開一個到實際文件的連接來創建一個 FileInputStream,該文件通過文件系統中的路徑名 name 指定。

具體示例如下:

public class TestInputStream {
    public static void main(String[] args) throws IOException {
        String path = "./baseJava/src/cn/lujiapeng/io_stream/TestInput.txt" ;
        File file = new File( path );
        FileInputStream fileInputStream = new FileInputStream(file);

        System.out.println( fileInputStream );

        fileInputStream = new FileInputStream(path);
        System.out.println( fileInputStream );

        FileDescriptor fdObj = new FileDescriptor() ;
        fileInputStream = new FileInputStream(fdObj);
        System.out.println( fileInputStream );
    }
}
java.io.FileOutputStream

構造方法:

  • FileOutputStream(File file) : 創建一個向指定 File 對象表示的文件中寫入數據的文件輸出流。
  • FileOutputStream(FileDescriptor fdObj) : 創建一個向指定文件描述符處寫入數據的輸出文件流,該文件描述符表示一個到文件系統中的某個實際文件的現有連接。
  • FileOutputStream(File file, boolean append) : 創建一個向指定 File 對象表示的文件中寫入數據的文件輸出流。
  • FileOutputStream(String name) : 創建一個向具有指定名稱的文件中寫入數據的輸出文件流。
  • FileOutputStream(String name, boolean append) : 創建一個向具有指定 name 的文件中寫入數據的輸出文件流。

具體示例如下:

public class TestOutputStream {
    public static void main(String[] args) throws IOException {
        String path = "./baseJava/src/cn/lujiapeng/io_stream/TestOutput.txt" ;
        File file = new File( path );
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        System.out.println( fileOutputStream );

        fileOutputStream = new FileOutputStream(file, true);
        System.out.println( fileOutputStream );

        fileOutputStream = new FileOutputStream( path ) ;
        System.out.println( fileOutputStream );

        fileOutputStream = new FileOutputStream( path , true  ) ;
        System.out.println( fileOutputStream );

        fileOutputStream = new FileOutputStream( new FileDescriptor() ) ;
        System.out.println( fileOutputStream );
    }
}
聯合使用

需求:通過讀取一個文件中的內容,向另一個文件中寫出。

public class TestInputOutputStream {
    public static void main(String[] args) throws IOException {
        String source = "./baseJava/src/cn/lujiapeng/io_stream/TestInput.txt" ;
        String dest = "./baseJava/src/cn/lujiapeng/io_stream/TestOutput.txt" ;
        FileInputStream fis = new FileInputStream( source ) ;
        FileOutputStream fos = new FileOutputStream( dest , true );

        int read ;
        while( (read = fis.read()) != -1){
            fos.write( read );
        }
        fos.close();
        fis.close();
    }
}

BufferedInputStream && BufferOutputStream

BufferedInputStreamBufferedOutputStream分別是InputStreamOutputStream的子類,主要是利用緩衝區針對於文件進行操作。

這兩個類中的方法並沒有什麼特殊的方法,這裏只進行描述對應的構造方法,並給出對應的示例。

注意:==BufferedInputStream是支持做標記並支持reset方法的。==

java.io.BufferedInputStream

BufferedInputStream 爲另一個輸入流添加一些功能,即緩衝輸入以及支持 markreset 方法的能力。在創建 BufferedInputStream 時,會創建一個內部緩衝區數組。在讀取或跳過流中的字節時,可根據需要從包含的輸入流再次填充該內部緩衝區,一次填充多個字節。mark 操作記錄輸入流中的某個點,reset 操作使得在從包含的輸入流中獲取新字節之前,再次讀取自最後一次 mark 操作後讀取的所有字節。

內部設計

BufferedInputStream內部定義了一個字節數組,充當一個緩衝數組。

public class BufferedInputStream extends FilterInputStream {
    private static int DEFAULT_BUFFER_SIZE = 8192; // 默認緩衝區大小

    private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; // 最大的緩衝區大小
    
    protected volatile byte[] buf; //內置緩存字節數組

    protected int count; //當前buf中的字節總數、注意不是底層字節輸入流的源中字節總數

    protected int pos; //當前buf中下一個被讀取的字節下標

    protected int markpos = -1; //最後一次調用mark(int readLimit)方法記錄的buf中下一個被讀取的字節的位置

    protected int marklimit;//調用mark後、在後續調用reset()方法失敗之前雲尋的從in中讀取的最大數據量、用於限制被標記後buffer的最大值
    // 省略其他代碼
}    
構造方法
  • BufferedInputStream(InputStream in) : 創建一個 BufferedInputStream 並保存其參數,即輸入流 in,以便將來使用。
  • BufferedInputStream(InputStream in, int size) : 創建具有指定緩衝區大小的 BufferedInputStream 並保存其參數,即輸入流 in,以便將來使用。

示例如下:

public class TestBufferedInputStream {
    public static void main(String[] args) throws IOException {
        InputStream in = new FileInputStream("./baseJava/src/cn/lujiapeng/io_stream/TestInput.txt");
        BufferedInputStream bufferedInputStream = new BufferedInputStream(in);
        byte[] bytes = new byte[10] ;
        int read = bufferedInputStream.read( bytes );
        System.out.println(read);
        System.out.println( new String( bytes ));
        bufferedInputStream.close();
        in.close();
    }
}
public class TestBufferedInputStream2 {
    public static void main(String[] args) throws IOException {
        InputStream in = new FileInputStream("./baseJava/src/cn/lujiapeng/io_stream/TestInput.txt");
        BufferedInputStream bufferedInputStream = new BufferedInputStream(in , 4096);
        byte[] bytes = new byte[10] ;
        int read = bufferedInputStream.read( bytes );
        System.out.println(read);
        System.out.println( new String( bytes ));
        bufferedInputStream.close();
        in.close();
    }
}

在BufferInputStream內部定義了一個字節數組(默認大小8k),當通過read()讀取輸入流的數據時,BufferedInputStream會將該輸入流的數據分批的填入到緩衝區中。每當緩衝區中的數據被讀完之後,輸入流會再次填充數據緩衝區;如此反覆,直到我們讀完輸入流數據位置。

java.io.BufferedOutputStream
內部設計
public class BufferedOutputStream extends FilterOutputStream {
    
    protected byte buf[];  //內置緩存字節數組、用於存放程序要寫入out的字節 
   
    protected int count; //內置緩存字節數組中現有字節總數
    // 省略其他代碼
}

那麼也就是內部這個數組用於存放即將要寫出的數據。那麼如果要寫出的數據在內部數組中存不下了,就直接將數據寫出,並重新計算count的值。

構造方法
  • BufferedOutputStream(OutputStream out) : 創建一個新的緩衝輸出流,以將數據寫入指定的底層輸出流。
  • BufferedOutputStream(OutputStream out, int size) : 創建一個新的緩衝輸出流,以將具有指定緩衝區大小的數據寫入指定的底層輸出流。

示例如下:

public class TestBufferedOutputStream {
    public static void main(String[] args) throws IOException {
        File file = new File("./baseJava/src/cn/lujiapeng/io_stream/TestOutput.txt");
        BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file));

        outputStream.write(97);
        byte[] bytes = new byte[10] ;
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) (97+i);
        }
        outputStream.write( bytes , 0 , bytes.length / 2 );

        outputStream.write( bytes );

        outputStream.flush();
        outputStream.close();
    }
}

當使用一個參數的構造的時候,那麼內部數組的大小就是8k,如果使用兩個參數的時候,就會創建指定參數大小的數組。

當調用close方法的時候,會在內部自動調用flush方法,會將內部數組中的所有數據進行寫出。建議:每次調用close方法的之前都調用一次flush方法。

轉換流

轉換流的功能是字符流與字節流之間的轉換,從而實現字節流向字節流的轉換。

java.io.InputStreamReader

官方聲明
An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.
Each invocation of one of an InputStreamReader's read() methods may cause one or more bytes to be read from the underlying byte-input stream. To enable the efficient conversion of bytes to characters, more bytes may be read ahead from the underlying stream than are necessary to satisfy the current read operation.

InputStreamReader是從字節流到字符流的橋接器:它使用指定的charset讀取字節並將其解碼爲字符。它使用的字符集可以通過名稱指定,也可以明確指定,或者可以接受平臺的默認字符集。

每次調用一個InputStreamReader的read()方法都可能導致從底層字節輸入流中讀取一個或多個字節。 爲了實現字節到字符的有效轉換,可以從基礎流中提取比滿足當前讀取操作所需的更多字節。

構造方法
  • InputStreamReader(InputStream in) : 創建一個使用默認字符集的InputStreamReader。
  • InputStreamReader(InputStream in, String charsetName) : 創建一個使用指定charset的InputStreamReader。
  • InputStreamReader(InputStream in, Charset cs) : 創建一個使用給定charset的InputStreamReader。
  • InputStreamReader(InputStream in, CharsetDecoder dec) : 創建一個使用給定charset解碼器的InputStreamReader。

具體示例如下:

public class TestInputStreamReader {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in ;
        InputStreamReader inputStreamReader = new InputStreamReader(in);
        System.out.println( inputStreamReader );
        inputStreamReader = new InputStreamReader(in ,"UTF-8") ;

        inputStreamReader = new InputStreamReader(in , StandardCharsets.UTF_8);

        inputStreamReader.close();
        in.close();
    }
}

在這裏可以看到,是將InputStream包裝成一個InputStreamReader,而InputStreamReader作爲Reader的子類,必然會有Reader的方法。

java.io.OutputStreamWriter

官方聲明
An OutputStreamWriter is a bridge from character streams to byte streams: Characters written to it are encoded into bytes using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.
Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream. Note that the characters passed to the write() methods are not buffered.

OutputStreamWriter是從字符流到字節流的橋接器:使用指定的charset將寫入其中的字符編碼爲字節。它使用的字符集可以通過名稱指定,也可以明確指定,或者可以接受平臺的默認字符集。

每次調用write()方法都會導致在給定字符上調用編碼轉換器。 生成的字節在寫入底層輸出流之前在緩衝區中累積。 請注意,傳遞給write()方法的字符不會被緩衝。

構造方法
  • OutputStreamWriter(OutputStream out) : 創建使用默認字符編碼的OutputStreamWriter。
  • OutputStreamWriter(OutputStream out, String charsetName) : 創建使用指定charset的OutputStreamWriter。
  • OutputStreamWriter(OutputStream out, Charset cs) : 創建使用給定charset的OutputStreamWriter。
  • OutputStreamWriter(OutputStream out, CharsetEncoder enc) : 創建使用給定charset編碼器的OutputStreamWriter。

具體示例如下:

public class TestOutputStreamWriter {
    public static void main(String[] args) throws IOException {
        String pathName = "./baseJava/src/cn/lujiapeng/io_stream/TestInput.txt" ;
        File file = new File(pathName);
        OutputStream out = new FileOutputStream(file);
        OutputStreamWriter writer = new OutputStreamWriter(out);
        System.out.println( writer );
        writer = new OutputStreamWriter(out , "UTF-8");
        System.out.println( writer );
        
        writer = new OutputStreamWriter(out , StandardCharsets.UTF_8);
        System.out.println( writer );
        
        writer.close();
        out.close();
    }
}

在這裏可以看到,是將OutputStream包裝成一個OutputStreamWriter,而OutputStreamWriter作爲Writer的子類,必然會有Writer的方法。

字符流

字符流主要是利用字符進行I/O操作。

java.io.Reader

官方聲明
Abstract class for reading character streams. The only methods that a subclass must implement are read(char[], int, int) and close(). Most subclasses, however, will override some of the methods defined here in order to provide higher efficiency, additional functionality, or both.

用於讀取字符流的抽象類。 子類必須實現的唯一方法是read(char [],int,int)和close()。 但是,大多數子類將覆蓋此處定義的一些方法,以提供更高的效率,附加功能或兩者兼而有之。

注:該類與java.io.InputStream的使用方式是一樣的,區別就在於讀取的是字符。

具體示例
public class TestReader {
    public static void main(String[] args) throws IOException {
        Reader reader = new FileReader("./baseJava/src/cn/lujiapeng/io_stream/TestReader.txt");
        int read = reader.read();
        System.out.println( (char)read );

        char[] chars = new char[10] ;
        read = reader.read(chars);
        System.out.println( new String( chars ));
        read = reader.read( chars , 0 , chars.length/2 ) ;
        System.out.println(new String( chars ));
        reader.skip( 3 ) ;
        read = reader.read(chars);
        System.out.println( new String( chars ));
        
        reader.close();
    }
}

Reader 是一個抽象類,這裏採用子類FileReader進行構建,但是不支持做標記。

java.io.Writer

官方聲明
Abstract class for writing to character streams. The only methods that a subclass must implement are write(char[], int, int), flush(), and close(). Most subclasses, however, will override some of the methods defined here in order to provide higher efficiency, additional functionality, or both.

用於寫入字符流的抽象類。 子類必須實現的唯一方法是write(char [],int,int),flush()和close()。 但是,大多數子類將覆蓋此處定義的一些方法,以提供更高的效率,附加功能或兩者兼而有之。

注:該類與java.io.OutputStream的使用方式是一樣的,區別就在於讀取的是字符。

具體示例
public class TestWriter {
    public static void main(String[] args) throws IOException {
        File file = new File("./baseJava/src/cn/lujiapeng/io_stream/TestWriter.txt");
        String s = "大家都挺好的" ;
        Writer writer = new FileWriter(file , true);
        writer.write(s );
        writer.write(1000);
        writer.write(  s, 0 , 3 );
        writer.write(s.toCharArray());
        writer.write( s.toCharArray() , 0 , 3 );
        writer.write("\n");
        // append 表示向文件中追加內容
        writer.append( s ) ;
        writer.append( '過') ;
        writer.append( s , 0  , s.length() / 2) ;
        writer.close();
    }
}

Writer是一個抽象類,這裏採用子類FileWriter進行構建,但是不支持做標記。

java.io.FileReader && java.io.FileWriter

java.io.FileReader
 Reads text from character files using a default buffer size. Decoding from bytes to characters uses either a specified charset or the platform's default charset.

使用默認緩衝區大小從字符文件中讀取文本。 從字節到字符的解碼使用指定的charset或平臺的default charset 。

該類是java.io.Reader的間接子類,

構造如下:

  • FileReader(File file) : 使用平臺 FileReader ,在 File讀取時創建一個新的 FileReader 。
  • FileReader(FileDescriptor fd) : 使用平臺 default charset創建一個新的 FileReader ,給定 FileDescriptor進行讀取。
  • FileReader(File file, Charset charset) : 創建一個新的FileReader ,給出File讀取和charset 。
  • FileReader(String fileName) : 使用平臺 default charset創建一個新的 FileReader ,給定要讀取的文件的 名稱 。
  • FileReader(String fileName, Charset charset) : 給定要讀取的文件的名稱和FileReader ,創建一個新的FileReader 。

在這裏可以看到,是可以根據不同的編碼進行讀取文件,但是在一般情況下,使用filefileName進行構建的情況是最常見的。

示例如下:

public class TestFileReader {
    public static void main(String[] args) throws Exception{
        String path = "./baseJava/src/cn/lujiapeng/io_stream/TestReader.txt" ;
        File file = new File(path );
        FileReader fileReader = new FileReader(file);
        System.out.println( fileReader);
        
        fileReader = new FileReader( path );
        System.out.println( fileReader );
        
        fileReader = new FileReader(FileDescriptor.in);
        System.out.println( fileReader );
        
        fileReader = new FileReader(file , StandardCharsets.UTF_8);
        System.out.println( fileReader );
        
        fileReader = new FileReader( path , StandardCharsets.UTF_8 );
        System.out.println( fileReader );
        
        fileReader.close();
    }
}
java.io.FileWriter
Writes text to character files using a default buffer size. Encoding from characters to bytes uses either a specified charset or the platform's default charset.

使用默認緩衝區大小將文本寫入字符文件。 從字符到字節的編碼使用指定的charset或平臺的default charset 。

該類是java.io.Writer的間接子類。

構造方法:

  • FileWriter(File file) : 給 File寫一個 FileWriter ,使用平臺的 default charset
  • FileWriter(FileDescriptor fd) : 構造一個 FileWriter給出的文件描述符,使用該平臺的 default charset 。
  • FileWriter(File file, boolean append) : 在給出要寫入的 FileWriter下構造 File ,並使用平臺的 default charset構造一個布爾值,指示是否附加寫入的數據。
  • FileWriter(File file, Charset charset) : 構造一個FileWriter給予File編寫和charset 。
  • FileWriter(File file, Charset charset, boolean append) : 構造FileWriter給出File寫入, charset和一個布爾值,指示是否附加寫入的數據。
  • FileWriter(String fileName) : 構造一個 FileWriter給出文件名,使用平臺的 default charset
  • FileWriter(String fileName, boolean append) : 使用平臺的 default charset構造一個 FileWriter給定一個文件名和一個布爾值,指示是否附加寫入的數據。
  • FileWriter(String fileName, Charset charset) : 構造一個FileWriter給出文件名和charset 。
  • FileWriter(String fileName, Charset charset, boolean append) : 構造一個FileWriter給定一個文件名, charset和一個布爾值,指示是否附加寫入的數據。

可以看到,在構造中可以使用文件或文件名進行構建對象,同時也可以指定對應的字符集編碼,也可以決定是否進行追加或替換。

具體示例如下:

public class TestFileWriter {
    public static void main(String[] args) throws IOException {
        String pathName = "./baseJava/src/cn/lujiapeng/io_stream/TestWriter.txt";
        File file = new File(pathName);
        FileWriter fileWriter = new FileWriter(file);
        System.out.println(fileWriter);
        fileWriter = new FileWriter(file , StandardCharsets.UTF_8);
        System.out.println(fileWriter);
        fileWriter = new FileWriter(file , StandardCharsets.UTF_8, true );
        System.out.println(fileWriter);
        fileWriter = new FileWriter(file, false );
        System.out.println(fileWriter);
        fileWriter = new FileWriter(pathName );
        System.out.println(fileWriter);
        fileWriter = new FileWriter(pathName , false );
        System.out.println(fileWriter);
        fileWriter = new FileWriter(pathName , StandardCharsets.UTF_8 );
        System.out.println(fileWriter);
        fileWriter = new FileWriter(pathName , StandardCharsets.UTF_8 , false );
        System.out.println(fileWriter);
        fileWriter = new FileWriter(FileDescriptor.in);
        System.out.println(fileWriter);

        fileWriter.close();
    }
}

該類中的常用方法是write,進行寫出,與FileOutputStream對應的方法含義基本一致,只不過寫出的字符。

聯合使用

使用FileReader與FileWriter實現複製文件內容

public class TestFileReaderAndWriter {
    public static void main(String[] args) throws IOException {
        FileReader fileReader = new FileReader("./baseJava/src/cn/lujiapeng/io_stream/TestReader.txt");

        FileWriter fileWriter = new FileWriter("./baseJava/src/cn/lujiapeng/io_stream/TestWriter.txt");
        int i ;
        try ( fileReader ; fileWriter){
            while(  (i = fileReader.read()) !=-1 ) {
                fileWriter.write( (char)i );
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // jdk10 新增的方法 , 更加簡單
//        fileReader.transferTo( fileWriter ) ; 
    }
}

java.io.BufferedReader && java.io.BufferedWriter

BufferedReaderBufferedWriter分別是ReaderWriter的子類,主要是利用緩衝區針對於文件進行操作。

這兩個類中的方法並沒有什麼特殊的方法,這裏只進行描述對應的構造方法,並給出對應的示例。

注意:==BufferedReader是支持做標記並支持reset方法的。==

java.io.BufferedReader

BufferedReader 爲另一個輸入流添加一些功能,即緩衝輸入以及支持 markreset 方法的能力。在創建 BufferedReader 時,會創建一個內部緩衝區數組。在讀取或跳過流中的字符時,可根據需要從包含的輸入流再次填充該內部緩衝區,一次填充多個字符。mark 操作記錄輸入流中的某個點,reset 操作使得在從包含的輸入流中獲取新字符之前,再次讀取自最後一次 mark 操作後讀取的所有字符。

內部設計

BufferedReader內部定義了一個字符數組,充當一個緩衝數組。

//  字符輸入流
private Reader in;
// 字符緩衝區
private char cb[];
// 讀取字符存儲的最末下標+1 ; 讀取字符存儲的起始下標
private int nChars, nextChar;

private static final int INVALIDATED = -2;
private static final int UNMARKED = -1;
private int markedChar = UNMARKED;
// 僅在markedChar大於0時有效
private int readAheadLimit = 0; /* Valid only when markedChar > 0 */

/** If the next character is a line feed, skip it */
// 如果下個字符是換行符,則跳過--專用於readLine()方法裏面控制
private boolean skipLF = false;

/** The skipLF flag when the mark was set */
// 設置標誌時的markedSkipLF--用於mark()方法的變量
private boolean markedSkipLF = false;
// 默認的字符緩衝大小
private static int defaultCharBufferSize = 8192;
// 用於readLine()方法時初始化StringBuffer的初始容量
private static int defaultExpectedLineLength = 80;
構造方法
  • BufferedReader(Reader in) : 創建使用默認大小的輸入緩衝區的緩衝字符輸入流。
  • BufferedReader(Reader in, int sz) : 創建使用指定大小的輸入緩衝區的緩衝字符輸入流。

示例如下:

public class TestBufferedReader {
    public static void main(String[] args)throws Exception {
        String pathName = "./baseJava/src/cn/lujiapeng/io_stream/TestReader.txt" ;
        Reader in = new FileReader(pathName);
        // 使用默認的大小:8192,進行構建對應的char[]
        BufferedReader bufferedReader = new BufferedReader(in);
        System.out.println( bufferedReader );
        // 使用指定的大小:4096,進行構建對應的char[]
        bufferedReader = new BufferedReader(in , 4096);
        System.out.println( bufferedReader );
        bufferedReader.close();
        in.close();
    }
}

BufferedReader是支持mark以及reset方法的,示例如下:

public class TestBufferedReader02 {
    public static void main(String[] args)throws Exception {
        String pathName = "./baseJava/src/cn/lujiapeng/io_stream/TestReader.txt" ;
        Reader in = new FileReader(pathName);
        // 使用默認的大小:8192,進行構建對應的char[]
        BufferedReader bufferedReader = new BufferedReader(in);
        System.out.println( bufferedReader );
        String s = bufferedReader.readLine();
        System.out.println( s );
        boolean supported = bufferedReader.markSupported();
        System.out.println( supported );
        System.out.println("----------------");
        if( supported ){
            bufferedReader.mark( 123456789 );
        }
        s = bufferedReader.readLine() ;
        System.out.println( s );
        System.out.println("----------------");
        bufferedReader.reset();
        s = bufferedReader.readLine() ;
        System.out.println( s );

        System.out.println( bufferedReader );
        bufferedReader.close();
        in.close();
    }
}
java.io.BufferedWriter
內部設計
// 字符輸出流
private Writer out;
// 緩衝數組
private char cb[];
// 寫出字符存儲的最末下標+1 ; 寫出字符存儲的起始下標
private int nChars, nextChar;
// 默認大小
private static int defaultCharBufferSize = 8192;
構造方法
  • BufferedWriter(Writer out) : 創建使用默認大小的輸出緩衝區的緩衝字符輸出流。
  • BufferedWriter(Writer out, int sz) : 創建一個使用給定大小的輸出緩衝區的新緩衝字符輸出流。

示例如下:

public class TestBufferedWriter {
    public static void main(String[] args) throws Exception {
        String pathName = "./baseJava/src/cn/lujiapeng/io_stream/TestWriter.txt" ;
        File file = new File(pathName );
        Writer out = new FileWriter(file);
        // 使用默認大小:8192 進行構建對象
        BufferedWriter bufferedWriter = new BufferedWriter(out);
        System.out.println( bufferedWriter );
        // 使用指定的大小:4096進行構建對象
        bufferedWriter = new BufferedWriter( out , 4096 );
        System.out.println( bufferedWriter );
        bufferedWriter.close();
        out.close();
    }
}

該類中並沒有值得特別關注的方法。

結合使用
public class TestBufferReaderWriter {
    public static void main(String[] args) throws Exception {
        String basePath = "./baseJava/src/cn/lujiapeng/io_stream/" ;
        String pathName = basePath + "TestReader.txt" ;
        Reader in = new FileReader( pathName);
        BufferedReader bufferedReader = new BufferedReader(in);
        String destName = basePath + "TestWriter.txt" ;
        File file = new File(destName) ;
        Writer out = new FileWriter(file);
        BufferedWriter bufferedWriter = new BufferedWriter(out);

        String s ;
        while( (s = bufferedReader.readLine()) != null ){
            bufferedWriter.write( s +"\n");
        }

        bufferedWriter.close();
        out.close();
        bufferedReader.close();
        in.close();
    }
}

序列化

把序列化單獨拿出來,那麼就表示這對流比較特殊。

  • 序列化:用ObjectOutputStream類 保存基本類型數據或對象的機制
  • 反序列化:用ObjectInputStream類 讀取基本類型數據或對象的機制

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

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

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

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

  • Serializable
  • Externalizable

示例如下:

  • 自定義一個類,用於序列化測試

    public class Student implements Serializable{
        private String name ; 
        private int age ; 
        private double weight ; 
        private Clazz clazz ;
    
        public Student(String name, int age, double weight, Clazz clazz) {
            this.name = name;
            this.age = age;
            this.weight = weight;
            this.clazz = clazz;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", weight=" + weight +
                    ", clazz=" + clazz +
                    '}';
        }
    
    // getter and setter
    }
    
    class  Clazz implements Serializable{
        private Integer id ;
    
        public Clazz(Integer id) {
            this.id = id;
        }
    
        public Clazz() {
        }
    
        @Override
        public String toString() {
            return "Clazz{" +
                    "id=" + id +
                    '}';
        }
    // getter and setter
    }
    
  • 進行序列化操作

    public class TestObjectOutputStream {
        public static void main(String[] args) throws Exception {
            File file = new File("./baseJava/src/cn/lujiapeng/io_stream/model/object.dat");
            OutputStream out = new FileOutputStream(file);
            ObjectOutputStream outputStream = new ObjectOutputStream(out);
    
            Student student = new Student("張三" , 18 , 150.6 , new Clazz()) ;
            outputStream.writeObject( student );
            outputStream.close();
            out.close();
        }
    }
    
  • 進行反序列化操作

    public class TestObjectInputStream {
        public static void main(String[] args) throws Exception{
            File file = new File("./baseJava/src/cn/lujiapeng/io_stream/model/object.dat") ;
            InputStream in = new FileInputStream( file );
            ObjectInputStream objectInputStream = new ObjectInputStream(in);
    
            Object o = objectInputStream.readObject();
            if( o instanceof Student ){
                Student student = (Student) o ;
                System.out.println( student );
            }
            objectInputStream.close();
            in.close();
    
        }
    }
    
注意
  1. ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量
  2. 凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量:private static final long serialVersionUID;
  3. 如果類沒有顯示定義這個靜態常量,它的值是Java運行時環境根據類的內部細節自動生成的。若類的實例變量做了修改,serialVersionUID 可能發生變化。故建議,顯式聲明
  4. Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認爲是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常。(InvalidCastException)
  5. 除了當前類要實現序列化接口,那麼其中的字段除了statictransient修飾的字段,都要實現可序列化接口。(默認情況下,基本數據類型可以序列化)

RandomAccessFile類

RandomAccessFile 聲明在java.io包下,但直接繼承於java.lang.Object類。並且它實現了DataInput、DataOutput這兩個接口,也就意味着這個類既可以讀也 可以寫。

RandomAccessFile 類支持 “隨機訪問” 的方式,程序可以直接跳到文件的任意地方來 讀、寫文件;支持只訪問文件的部分內容,可以向已存在的文件後追加內容。

RandomAccessFile 對象包含一個記錄指針,用以標示當前讀寫處的位置。RandomAccessFile 類對象可以自由移動記錄指針:

  • long getFilePointer():獲取文件記錄指針的當前位置
  • void seek(long pos):將文件記錄指針定位到 pos 位置

構造方法

  • RandomAccessFile(File file, String mode) : 創建隨機訪問文件流,以便從File參數指定的文件中讀取,也可以選擇寫入。
  • RandomAccessFile(String name, String mode) : 創建隨機訪問文件流,以便從具有指定名稱的文件進行讀取,並可選擇寫入該文件。

其中的mode指定了RandomAccessFile的訪問方式:

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

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

具體示例如下:

public class TestRandomAccessFile {
    public static void main(String[] args) throws IOException {
        String path = "./baseJava/src/cn/lujiapeng/io_stream/test_random_access_file.txt" ;
        RandomAccessFile raf = new RandomAccessFile(path, "rw");
        String s = raf.readLine();
        System.out.println( new String( s.getBytes()  ));
        raf.seek( 20 ) ;
        s = raf.readLine();
        System.out.println( s );
        raf.write("哈哈,沒想到吧!我又回來了!".getBytes());
        raf.close();
    }
}

Path、Files的使用

java.nio.file.Path

官方聲明

public interface Path extends Comparable<Path>, Iterable<Path>, Watchable

Path是一個接口,可以用於在文件系統中定位文件的對象。它通常代表一個系統相關的文件路徑。

獲取實例

可以使用static修飾的方法進行獲取對應的實例。不建議使用java.nio.file.Paths進行獲取,在JDK11的官方文檔中已經描述:在以後可能會被廢棄。

  • of(String first, String... more) : 通過轉換路徑字符串或連接時形成路徑字符串的字符串序列,返回 Path 。
  • of(URI uri) : 通過轉換URI返回 Path 。

具體示例如下:

public class TestPath {
    public static void main(String[] args) {
        Path path = Path.of("./baseJava") ;
        System.out.println( path );
        path = Path.of("./baseJava/" , "src","cn","lujiapeng","io_stream","TestInput.txt") ;
        System.out.println( path );
       
        path = Path.of( URI.create("file:/E:/IdeaProject/JavaSystem/baseJava/src/cn/lujiapeng/io_stream/TestInput.txt"));
        System.out.println( path );
    }
}

但是在使用的時候,一般都是選擇使用字符串獲取對應的一個路徑,通過可變長參數進行控制下層目錄。

實例方法

to方法系列
  • toFile() : 返回表示此路徑的File對象。
  • toRealPath(LinkOption... options) : 返回現有文件的 實際路徑。
  • toString() : 返回此路徑的字符串表示形式。
  • toUri() : 返回表示此路徑的URI。
  • toAbsolutePath() : 返回表示此路徑的絕對路徑的 Path對象。

具體示例如下:

public class TestPathToMethod {
    public static void main(String[] args) throws IOException {
        Path     path = Path.of("./baseJava/" , "src","cn","lujiapeng","io_stream","TestInput.txt") ;
        File file = path.toFile();
        System.out.println( file );

        Path path1 = path.toAbsolutePath();
        System.out.println( path1 );

        Path path2 = path.toRealPath(LinkOption.NOFOLLOW_LINKS);
        System.out.println( path2 );

        URI uri = path.toUri();
        System.out.println( uri );
    }
}
get方法系列
  • getFileName() : 返回此路徑表示爲 Path對象的文件或目錄的名稱。
  • getFileSystem() : 返回創建此對象的文件系統。
  • getName(int index) : 以 Path對象的形式返回此路徑的名稱元素。
  • getNameCount() : 返回路徑中的名稱元素數。
  • getParent() : 返回 父路徑 ,如果此路徑沒有 父路徑 ,則返回 null 。
  • getRoot() : 返回此路徑的根組分作爲 Path對象,或 null如果該路徑不具有根組件。

具體示例如下:

public class TestPathGetMethod {
    public static void main(String[] args) throws IOException {
        Path path = Path.of(".","baseJava", "src", "cn", "lujiapeng", "io_stream", "TestInput.txt");
        Path name = path.getName(0);
        System.out.println( name );
        Path fileName = path.getFileName();
        System.out.println( fileName );

        int nameCount = path.getNameCount();
        System.out.println( nameCount );

        FileSystem fileSystem = path.getFileSystem();
        System.out.println( fileSystem );

        Path parent = path.getParent();
        System.out.println( parent );

        Path root = path.getRoot();
        System.out.println( root );
    }
}
resolve系列方法
  • resolve(String other) : 一個給定的路徑字符串轉換爲 Path並解析它針對此 Path在完全按規定的方式 resolve方法。
  • resolve(Path other) : 根據此路徑解析給定路徑。
  • resolveSibling(String other) : 將給定的路徑字符串轉換爲 Path並按照 resolveSibling方法指定的方式將其解析爲此路徑的 parent路徑。
  • resolveSibling(Path other) : 根據此路徑的路徑 parent解析給定路徑。

示例如下:

public class TestPathResolveMethod {
    public static void main(String[] args) throws IOException {
        Path path = Path.of(".","baseJava", "src", "cn", "lujiapeng", "io_stream", "TestInput.txt");
        Path resolve = path.resolve("./baseJava/src/cn/lujiapeng/io_stream/TestWriter.txt");
        System.out.println( resolve );

        Path resolve1 = path.resolve(resolve);
        System.out.println( resolve1 );

        Path path1 = path.resolveSibling(resolve);
        System.out.println( path1 );

        Path path2 = path.resolveSibling("./baseJava/src/cn/lujiapeng/io_stream/TestWriter.txt");
        System.out.println( path2 );
    }
}
strat && end

該系列方法用於判斷是否以XXX開頭或以XXX結尾的操作。

  • endsWith(String other) : 測試此路徑是否以 Path ,通過轉換給定的路徑字符串構造,完全按照 endsWith(Path)方法指定的方式。
  • endsWith(Path other) : 測試此路徑是否以給定路徑結束。
  • startsWith(String other) : 測試此路徑是否以 Path ,通過轉換給定的路徑字符串構造,完全按照 startsWith(Path)方法指定的方式。
  • startsWith(Path other) : 測試此路徑是否以給定路徑開頭。

示例如下:

public class TestPathStrartAndEndMethod {
    public static void main(String[] args) throws IOException {
        Path     path = Path.of(".","baseJava" , "src","cn","lujiapeng","io_stream","TestInput.txt") ;

        boolean b = path.endsWith(".txt");
        System.out.println( b );
        b = path.endsWith( Path.of("TestInput.txt")) ;
        System.out.println( b );

        b = path.startsWith(".");
        System.out.println( b );

        b = path.startsWith(Path.of(".")) ;
        System.out.println( b );
    }
}
其他方法
  • compareTo(Path other) : 按字典順序比較兩條抽象路徑。
  • equals(Object other) : 測試此路徑是否與給定對象相等
  • isAbsolute() : 判斷此路徑是否絕對。
  • iterator() : 返回此路徑的name元素的迭代器。
  • normalize() : 返回此路徑的路徑,其中刪除了冗餘名稱元素。
  • relativize(Path other) : 構造此路徑與給定路徑之間的相對路徑。
  • subpath(int beginIndex, int endIndex) : 返回一個相對 Path ,它是此路徑的name元素的子序列。

示例如下:

public class TestOtherMethod {
    public static void main(String[] args) {
        Path path = Path.of(".","baseJava", "src", "cn", "lujiapeng", "io_stream", "TestInput.txt");
        boolean absolute = path.isAbsolute();
        System.out.println( absolute );

        Path subPath = path.subpath(0, 5);
        System.out.println( subPath);

        Path normalize = path.normalize();
        System.out.println( normalize );

        Path basePath = Path.of("E:","IdeaProject" , "JavaSystem") ;
        int i = path.compareTo(basePath);
        System.out.println( i );

        boolean equals = path.equals(normalize);
        System.out.println( equals );
        // 如果想要構建路徑的話,那麼兩者的類型要一致:比如都是ABSOLUTE 或 RELATIVE
        // 同時還要有相同的根路徑
        Path relativize = path.relativize( normalize );
        System.out.println( relativize );
        System.out.println("------------");
        Iterator<Path> iterator = path.iterator();
        while( iterator.hasNext() ){
            Path next = iterator.next();
            System.out.println( next );
        }
    }
}

如果想要使用relativize方法的話,那麼就要求類型一致,並且有相同的根路徑(windows環境下)。

java.nio.file.Files

官方聲明

This class consists exclusively of static methods that operate on files, directories, or other types of files.
In most cases, the methods defined here will delegate to the associated file system provider to perform the file operations.

此類僅包含對文件,目錄或其他類型文件進行操作的靜態方法。 在大多數情況下,此處定義的方法將委派給關聯的文件系統提供程序以執行文件操作。

注意,該類中的方法都是static修飾的方法,那麼也就是說,可以不用創建實例,從而進行使用。

方法使用

copy方法

該系列方法有重載:

  • copy(InputStream in, Path target, CopyOption... options) : 將輸入流中的所有字節複製到文件
  • copy(Path source, OutputStream out) : 將文件中的所有字節複製到輸出流。
  • copy(Path source, Path target, CopyOption... options) : 將文件複製到目標文件

示例如下:

  • copy(InputStream in, Path target, CopyOption... options)

    public class TestCopyMethod {
        public static void main(String[] args) throws IOException {
            String sourcePath = "./baseJava/src/cn/lujiapeng/io_stream/TestReader.txt" ;
            Path target = Path.of(".","baseJava", "src", "cn", "lujiapeng", "io_stream", "TestWriterOfFiles.txt");
            InputStream inputStream = new FileInputStream(sourcePath) ;
            long copy = Files.copy(inputStream, target, StandardCopyOption.REPLACE_EXISTING);
            System.out.println( copy );
        }
    }
    
  • copy(Path source, OutputStream out)

    public class TestCopyMethod02 {
        public static void main(String[] args) throws IOException {
            String destPath = "./baseJava/src/cn/lujiapeng/io_stream/TestWriterOfFiles.txt" ;
            Path source = Path.of(".","baseJava", "src", "cn", "lujiapeng", "io_stream", "TestReader.txt");
            OutputStream outputStream = new FileOutputStream(destPath);
            long copy = Files.copy( source , outputStream );
            System.out.println( copy );
        }
    }
    
  • copy(Path source, Path target, CopyOption... options) 最常用的一種複製

    public class TestCopyMethod03 {
        public static void main(String[] args) throws IOException {
            Path source = Path.of(".","baseJava", "src", "cn", "lujiapeng", "io_stream", "TestReader.txt");
            Path target = Path.of(".","baseJava", "src", "cn", "lujiapeng", "io_stream", "TestWriterOfFiles2.txt");
            Path copy = Files.copy( source , target , StandardCopyOption.REPLACE_EXISTING );
            System.out.println( copy );
        }
    }
    
create方法

該系列方法表示需要創建文件夾或者目錄所進行的操作。

  • createDirectories(Path dir, FileAttribute<?>... attrs) : 首先通過創建所有不存在的父目錄來創建目錄
  • createDirectory(Path dir, FileAttribute<?>... attrs) : 創建一個新目錄。
  • createFile(Path path, FileAttribute<?>... attrs) : 創建一個新的空文件,如果該文件已存在則失敗。
  • createLink(Path link, Path existing) : 爲現有文件創建新鏈接(目錄條目) (可選操作) 。
  • createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs) : 創建指向目標的符號鏈接 (可選操作)
  • createTempDirectory(String prefix, FileAttribute<?>... attrs) : 在默認臨時文件目錄中創建一個新目錄,使用給定的前綴生成其名稱。
  • createTempDirectory(Path dir, String prefix, FileAttribute<?>... attrs) : 在指定目錄中創建一個新目錄,使用給定前綴生成其名稱。
  • createTempFile(String prefix, String suffix, FileAttribute<?>... attrs) : 在默認臨時文件目錄中創建一個空文件,使用給定的前綴和後綴生成其名稱。
  • createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>... attrs) : 在指定目錄中創建一個新的空文件,使用給定的前綴和後綴字符串生成其名稱。

其中 FileAttribute可以通過PosixFilePermissions#asFileAttribute方法進行創建,其中傳遞的參數是一個Set<PosixFilePermission>類型的數據,其中PosixFilePermission是一個枚舉類,那麼創建方式如下:

public class TestFileAttribute {
    public static void main(String[] args) {

        PosixFilePermission[] values = PosixFilePermission.values();
        Set<PosixFilePermission> perms = new HashSet<>(Arrays.asList( values )) ;
        FileAttribute<Set<PosixFilePermission>> setFileAttribute = PosixFilePermissions.asFileAttribute(perms);
        System.out.println( setFileAttribute );
    }
}

這裏使用數組的方式將所有的相關權限都填充進set中,那麼也就是說,如果使用該FileAttribute那麼就會有所有的方法。可以考慮使用的方法將其封裝。但是在Windows中式不支持 Posix的。

public class GetFileAttribute {
    public static FileAttribute<Set<PosixFilePermission>>  getAllFileAttribute() {
        PosixFilePermission[] values = PosixFilePermission.values();
        Set<PosixFilePermission> perms = new HashSet<>(Arrays.asList( values )) ;
        FileAttribute<Set<PosixFilePermission>> setFileAttribute = PosixFilePermissions.asFileAttribute(perms);
        return setFileAttribute ; 
    }
}

那麼創建文件的方法就簡單了,示例如下:

public class TestCreateMethod {
    @Test
    public void test01() throws IOException {
        Path path = Path.of("." , "baseJava","create_directories01","create_directories02") ;
        System.out.println( path );
        // 在 windows 的環境下,是不支持第二個參數
        Path directories = Files.createDirectories( path ) ;
        System.out.println( directories );
    }

    @Test
    public void test02() throws IOException {
        Path path = Path.of("." , "baseJava" , "create_directory") ;
        // 如果文件已經被創建則拋出異常
        // 同時 createDirectory 只能創建一層目錄
        Path directory = Files.createDirectory(path);
        System.out.println( directory );
    }

    @Test
    public void test03() throws IOException {
        // 如果文件已經被創建則拋出異常
        // 同時 createDirectory 只能創建一層目錄
        Path path = Path.of("." , "baseJava" , "create_directory") ;
        Path directory = Files.createDirectory(path);
        System.out.println( directory );
    }

    @Test
    public void test04() throws IOException {
        Path path = Path.of( "." , "baseJava" , "create_directory" , "create_file.txt" );
        Path file = Files.createFile(path);
        System.out.println( file );
    }

    @Test
    public void test05() throws IOException {
        Path file = Files.createTempDirectory("test");
        System.out.println( file );
        file = Files.createTempDirectory( Path.of(".") , "testTemp");
        System.out.println( file );
    }

    @Test
    public void test06() throws IOException {
        Path file = Files.createTempFile(Path.of(".") , "test" , ".log");
        System.out.println( file );
    }
}

注:createLinkcreateSymbolicLink這兩個方法在windows系統下可以操作,但是看不出效果,所以在這裏沒有進行測試。

delete 方法

該系列方法表示刪除指定路徑下的文件。

  • delete(Path path) : 刪除文件。
  • deleteIfExists(Path path) : 刪除文件(如果存在)。

示例如下:

public class TestDeleteMethod {
    @Test
    public void test01(){
        Path path =  Path.of("src","cn","lujiapeng","io_stream","TestReader.txt") ;
        try {
            // 當文件不存在的時候拋出異常
            Files.delete( path );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test02(){
        Path path =  Path.of("src","cn","lujiapeng","io_stream","TestWriterOfFiles.txt") ;
        try {
            // 當文件不存在,返回false
            boolean b = Files.deleteIfExists(path);
            System.out.println( b );
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
get方法

該系列方法主要式獲取對應的一些屬性等內容。

  • getAttribute(Path path, String attribute, LinkOption... options) : 讀取文件屬性的值。
  • getFileAttributeView(Path path, Class<V> type, LinkOption... options) : 返回給定類型的文件屬性視圖。
  • getFileStore(Path path) : 返回表示文件所在文件存儲的FileStore 。
  • getLastModifiedTime(Path path, LinkOption... options) : 返回文件的上次修改時間。
  • getOwner(Path path, LinkOption... options) : 返回文件的所有者。
  • getPosixFilePermissions(Path path, LinkOption... options) : 返回文件的POSIX文件權限(針對於Linux和Unix系統)。

具體示例如下:

public class GetMethodTest {
    Path path = Path.of("src","cn","lujiapeng","io_stream","TestOutput.txt");
    @Test
    public void test01() throws IOException {
        // 獲取文件屬性的視圖 : 可以使用子類 BasicFileAttributeView
        BasicFileAttributeView basicFileAttributeView = Files.getFileAttributeView(path, BasicFileAttributeView.class);
        System.out.println(basicFileAttributeView);
        // 在獲取屬性的時候,不知道如何去寫,其實就是 BasicFileAttributes 中的方法名稱(僅在windows中進行支持並測試)
        BasicFileAttributes basicFileAttributes = basicFileAttributeView.readAttributes();
        long size = basicFileAttributes.size();
        System.out.println( size );
        boolean directory = basicFileAttributes.isDirectory();
        System.out.println( directory );
        boolean regularFile = basicFileAttributes.isRegularFile();
        System.out.println(regularFile );
        boolean other = basicFileAttributes.isOther();
        System.out.println( other );
        boolean symbolicLink = basicFileAttributes.isSymbolicLink();
        System.out.println( symbolicLink );
        FileTime fileTime2 = basicFileAttributes.creationTime();
        System.out.println( fileTime2 );
        Object o = basicFileAttributes.fileKey();
        System.out.println( o );
        FileTime fileTime = basicFileAttributes.lastModifiedTime();
        System.out.println( fileTime );
        FileTime fileTime1 = basicFileAttributes.lastAccessTime();
        System.out.println( fileTime1 );


        Object attribute = Files.getAttribute(path, "lastAccessTime");
        System.out.println( attribute );

        FileStore fileStore = Files.getFileStore(path);
        System.out.println( fileStore );

        FileTime lastModifiedTime = Files.getLastModifiedTime(path);
        System.out.println( lastModifiedTime );

        UserPrincipal owner = Files.getOwner(path);
        System.out.println( owner );
        // 這裏運行失敗,java.lang.UnsupportedOperationException
        // 間接證明 createLink 與 createSymbolicLink 在windows下是運行會有問題的。
        Set<PosixFilePermission> posixFilePermissions = Files.getPosixFilePermissions(path);
        System.out.println( posixFilePermissions );
    }
}
判斷方法

該系列方法是對指定的文件進行判斷一些屬性等內容。

  • isDirectory(Path path, LinkOption... options) : 測試文件是否是目錄。
  • isExecutable(Path path) : 測試文件是否可執行。
  • isHidden(Path path) : 判斷文件是否被視爲 隱藏 。
  • isReadable(Path path) : 測試文件是否可讀。
  • isRegularFile(Path path, LinkOption... options) : 測試文件是否是具有不透明內容的常規文件。
  • isSameFile(Path path, Path path2) : 測試兩個路徑是否找到相同的文件。
  • isSymbolicLink(Path path) : 測試文件是否是符號鏈接。
  • isWritable(Path path) : 測試文件是否可寫。
  • equals( Path path ) : 判斷兩個path是否相等。
  • exists(Path path, LinkOption... options) : 測試文件是否存在。
  • notExists(Path path, LinkOption... options) : 測試此路徑所在的文件是否不存在。

具體示例如下:

public class IsMethodTest {
    Path path = Path.of("src","cn","lujiapeng","io_stream","TestOutput.txt");
    @Test
    public void test01() throws IOException {
        boolean directory = Files.isDirectory(path);
        System.out.println( directory );
        boolean executable = Files.isExecutable(path);
        System.out.println( executable );

        boolean hidden = Files.isHidden(path);
        System.out.println( hidden );

        boolean readable = Files.isReadable(path);
        System.out.println( readable );

        boolean regularFile = Files.isRegularFile(path);
        System.out.println( regularFile );
        Path path2 = Path.of("src","cn","lujiapeng","io_stream","TestInput.txt");
        boolean sameFile = Files.isSameFile(path, path2);
        System.out.println( sameFile );

        boolean symbolicLink = Files.isSymbolicLink(path);
        System.out.println( symbolicLink );

        boolean writable = Files.isWritable(path);
        System.out.println( writable );

        System.out.println( path2.equals( path ));
        
		System.out.println( Files.exists( path2 ));

        System.out.println( Files.notExists( path2 ));
    }
}
lines

該方法有重載,用於讀取所有的行,並返回一個Stream

  • lines(Path path) : 從文件中讀取所有行,返回Stream 。
  • lines(Path path, Charset cs) : 從文件中讀取所有行,並指定編碼返回 Stream 。

示例如下:

public class LinesMethodTest {
    Path path = Path.of("src","cn","lujiapeng","io_stream","TestOutput.txt");
    @Test
    public  void testLines(){
        try (Stream<String> lines = Files.lines(path) ){
            System.out.println( lines );
            lines.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try( Stream<String> lines = Files.lines(path , StandardCharsets.US_ASCII)){
            lines.filter(s -> s.length()>4).forEach(System.out::println);
        }catch (Exception e ){
            e.printStackTrace();
        }

    }
}
newXXX

該系列方法返回一個流 或一個Channel ,具體如下:

  • newBufferedReader(Path path) : 打開文件進行讀取,返回 BufferedReader以高效方式從文件中讀取文本。
  • newBufferedReader(Path path, Charset cs) : 打開文件進行讀取,返回 BufferedReader ,可用於以高效的方式從文件中讀取文本。
  • newBufferedWriter(Path path, Charset cs, OpenOption... options) : 打開或創建用於寫入的文件,返回可用於以高效方式將文本寫入文件的 BufferedWriter 。
  • newBufferedWriter(Path path, OpenOption... options) : 打開或創建用於寫入的文件,返回 BufferedWriter以便以有效的方式將文本寫入文件。
  • newByteChannel(Path path, OpenOption... options) : 打開或創建文件,返回可搜索的字節通道以訪問該文件。
  • newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) : 打開或創建文件,返回可搜索的字節通道以訪問該文件。
  • newDirectoryStream(Path dir) : 打開一個目錄,返回DirectoryStream以遍歷目錄中的所有條目。
  • newDirectoryStream(Path dir, String glob) : 打開一個目錄,返回DirectoryStream以遍歷目錄中的條目。
  • newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) : 打開一個目錄,返回DirectoryStream以遍歷目錄中的條目。
  • newInputStream(Path path, OpenOption... options) : 打開文件,返回輸入流以從文件中讀取。
  • newOutputStream(Path path, OpenOption... options) : 打開或創建文件,返回可用於將字節寫入文件的輸出流。

示例如下:

public class NewMethodTest {
    Path file = Path.of("src","cn","lujiapeng","io_stream","TestOutput.txt");
    Path dir = Path.of("src","cn" ,"lujiapeng") ;
    @Test
    public void test01() throws IOException {
        BufferedReader bufferedReader = Files.newBufferedReader(file);
        System.out.println( bufferedReader );
    }
    @Test
    public void test02() throws IOException {
        BufferedReader bufferedReader = Files.newBufferedReader(file, StandardCharsets.UTF_8);
        System.out.println( bufferedReader );
    }

    @Test
    public void test03() throws IOException {
        BufferedWriter bufferedWriter = Files.newBufferedWriter(file);
        System.out.println( bufferedWriter );
    }

    @Test
    public void test04() throws IOException {
        BufferedWriter bufferedWriter = Files.newBufferedWriter(file, StandardCharsets.UTF_8);
        System.out.println( bufferedWriter );
    }

    @Test
    public void test05() throws IOException {
        SeekableByteChannel seekableByteChannel = Files.newByteChannel(file);
        System.out.println( seekableByteChannel );
    }

    @Test
    public void test06() throws IOException {
        DirectoryStream<Path> paths = Files.newDirectoryStream(dir);
        Iterator<Path> iterator = paths.iterator();
        while( iterator.hasNext() ){
            Path next = iterator.next();
            System.out.println( next );
        }
        System.out.println("----------------");

        paths = Files.newDirectoryStream( dir , "single") ;
        iterator = paths.iterator();
        while( iterator.hasNext() ){
            Path next = iterator.next();
            System.out.println( next );
        }

        System.out.println("--------------------");
        paths = Files.newDirectoryStream(dir, entry -> entry.toFile().isDirectory()) ;
        iterator = paths.iterator();
        while( iterator.hasNext() ){
            Path next = iterator.next();
            System.out.println( next );
        }
    }
    @Test
    public void test07() throws IOException {
        InputStream inputStream = Files.newInputStream(file);
        System.out.println( inputStream );

        OutputStream outputStream = Files.newOutputStream(file);
        System.out.println( outputStream );
    }

}
read 方法

該系列方法用於讀取數據或屬性,具體如下:

  • readAllBytes(Path path) : 從文件中讀取所有字節。
  • readAllLines(Path path) : 從文件中讀取所有行。
  • readAllLines(Path path, Charset cs) : 從文件中讀取所有行。
  • readAttributes(Path path, Class<A> type, LinkOption... options) : 將文件的屬性讀取爲批量操作。
  • readAttributes(Path path, String attributes, LinkOption... options) : 將一組文件屬性讀取爲批量操作。
  • readString(Path path) : 將文件中的所有內容讀入字符串,使用UTF-8 charset從字節解碼爲字符。
  • readString(Path path, Charset cs) : 將文件中的所有字符讀入字符串,使用指定的charset從字節解碼爲字符。
  • readSymbolicLink(Path link) : 讀取符號鏈接的目標 (可選操作) 。

具體示例如下:

public class ReadMethodTest {
    Path file = Path.of("src","cn","lujiapeng","io_stream","TestReader.txt");
    @Test
    public void test01() throws IOException {
        byte[] bytes = Files.readAllBytes(file);
        System.out.println( new String( bytes ));

        List<String> list = Files.readAllLines(file);
        list.forEach(System.out::println);

        List<String> list1 = Files.readAllLines(file, StandardCharsets.UTF_8);
        list1.forEach(System.out::println );

        BasicFileAttributes basicFileAttributes = Files.readAttributes(file, BasicFileAttributes.class);
        System.out.println( basicFileAttributes );

        String s = Files.readString(file);
        System.out.println( s );

        String s1 = Files.readString(file, StandardCharsets.UTF_8);
        System.out.println( s1 );
    }
}
set方法

該系列方法用於設置文件的屬性值

  • setAttribute(Path path, String attribute, Object value, LinkOption... options) : 設置文件屬性的值
  • setLastModifiedTime(Path path, FileTime time) : 更新文件的上次修改時間屬性。
  • setOwner(Path path, UserPrincipal owner) : 更新文件所有者。
  • setPosixFilePermissions(Path path, Set<PosixFilePermission> perms) : 設置文件的POSIX權限。
public class SetMethodTest {
    Path file = Path.of("src","cn","lujiapeng","io_stream","TestOutput.txt");
    @Test
    public void test01() throws IOException {

        Path path1 = Files.setLastModifiedTime(file, FileTime.from(Instant.now()));
        System.out.println( path1 );

    }
}
walk 方法

該系列方法用於遍歷指定文件夾下的文件

  • walk(Path start, int maxDepth, FileVisitOption... options) : 返回 Stream ,它通過遍歷以給定起始文件爲根的文件樹來延遲填充 Path 。
  • walk(Path start, FileVisitOption... options) : 通過遍歷以給定起始文件爲根的文件樹,返回 Stream ,其中包含 Path 。
  • walkFileTree(Path start, FileVisitor<? super Path> visitor) :遍歷文件
  • walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor) : 遍歷文件

示例如下:

public class WalkMethodTest {
    Path dir = Path.of("E:" , "IdeaProject","JavaSystem","baseJava" ) ;
    @Test
    public void test_01() throws IOException {
        Stream<Path> walk = Files.walk(dir);
        walk.forEach(System.out::println);
        System.out.println("-------------");
        Stream<Path> walk1 = Files.walk(dir, 7);
        walk1.forEach(System.out::println );
        System.out.println("--------------");
        Path path = Files.walkFileTree(dir , new SimpleFileVisitor<Path>(){
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println( file );
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                System.out.println( dir );
                return FileVisitResult.CONTINUE ;
            }
        });

        System.out.println( path );
        System.out.println("----------------");

        Path path1 = Files.walkFileTree(dir, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println(file);
                return FileVisitResult.CONTINUE;
            }
            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                System.out.println(dir);
                return FileVisitResult.CONTINUE;
            }
        });
        System.out.println( path1 );
    }
}
write方法

通常與read方法一起連用,從而實現複製文件的效果。

  • write(Path path, byte[] bytes, OpenOption... options) : 將字節寫入文件。
  • write(Path path, Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options) : 將文本行寫入文件。
  • write(Path path, Iterable<? extends CharSequence> lines, OpenOption... options) : 將文本行寫入文件。
  • writeString(Path path, CharSequence csq, Charset cs, OpenOption... options) : 將CharSequence寫入文件。
  • writeString(Path path, CharSequence csq, OpenOption... options) : 寫一個CharSequence到一個文件。

具體示例如下:

public class WriteMethodTest {
    Path file = Path.of("src","cn","lujiapeng","io_stream","TestWriter.txt");
    @Test
    public void testWrite() throws IOException {
        Path write = Files.write(file, new byte[]{97, 98, 99, 100});
        System.out.println( write );

        List<String> list = new ArrayList<>();
        list.add("你好");
        list.add("都挺好");
        list.add("大家好");

        Path path = Files.write(file, list );
        System.out.println( path );

        path = Files.write(file, list, StandardCharsets.UTF_8);
        System.out.println( path );

        path = Files.writeString( file , list.toString() ) ;
        System.out.println( path );

        path = Files.writeString( file , list.toString() , StandardCharsets.UTF_8 ) ;
        System.out.println( path );
    }
}

每次寫入都會造成覆蓋效果。

其他方法
  • find(Path start, int maxDepth, BiPredicate<Path,BasicFileAttributes> matcher, FileVisitOption... options) : 通過搜索以給定起始文件爲根的文件樹中的文件,返回 Stream ,其中包含 Path
  • list(Path dir) : 通過搜索以給定起始文件爲根的文件樹中的文件,返回 Stream ,其中包含 Path
  • probeContentType(Path path) : 探測文件的內容類型。
  • move(Path source, Path target, CopyOption... options) : 將文件移動或重命名爲目標文件
  • size(Path path) : 返回文件的大小(以字節爲單位)。

示例如下:

public class OtherMethodTest {
    @Test
    public void test01() throws IOException {
        Path path = Path.of(".") ;
        Stream<Path> pathStream = Files.find(path, Integer.MAX_VALUE, (path1, basicFileAttributes) -> path1.toFile().isFile());

        pathStream.forEach(System.out::println );

        Stream<Path> list = Files.list(path);
        list.forEach(System.out::println );

        String s = Files.probeContentType(path);
        System.out.println( s );

        Path source = Path.of("src/cn/lujiapeng/io_stream/TestInput.txt") ;

        Path dest = Path.of( "src/cn/lujiapeng/io_stream/test_path_files/TestInput.txt") ;

        Path move = Files.move(source, dest);
        System.out.println( move );

        long size = Files.size(path);
        System.out.println( size  );
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章