Java檔案和輸入和輸出(I/O)


java.io包幾乎包含了在Java中執行輸入和輸出(I/O)所需的所有類。 所有這些流代表輸入源和輸出目的地。 java.io包中的流支援許多資料,如:原始,物件,在地化字元等。

1. 流(Streams)

流(Streams)可以定義為資料序列,它有兩種 -

  • InPutStream - 它用於從源讀取資料。
  • OutPutStream - 它用於將資料寫入目標。

Java流

Java為與檔案和網路相關的I/O提供強大而靈活的支援,但本教學只涵蓋了流和I/O相關的非常基本的功能。下面將看到一些最常用的例子 -

1.1. 位元組流
Java位元組流用於執行8位位元組的輸入和輸出。儘管有許多與位元組流相關的類,但最常用的類是FileInputStreamFileOutputStream。以下範例使用這兩個類將輸入檔案的內容複製到輸出檔案中 -

import java.io.*;
public class CopyFile {

   public static void main(String args[]) throws IOException {  
      FileInputStream in = null;
      FileOutputStream out = null;

      try {
         in = new FileInputStream("D:\\input.txt");
         out = new FileOutputStream("D:\\output.txt");
         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }
   }
}

假設在D盤下有一個檔案:input.txt,它的內容如下 -

This is test for copy file.
power by tw511.com

下一步,編譯上面的程式並執行它,它將建立一個:D:/output.txt檔案,內容與D:/input.txt中的相同。

1.2. 字元流

Java位元組流用於執行8位位元組的輸入和輸出,而Java字元流用於執行16位unicode的輸入和輸出。 儘管有許多與字元流相關的類,但最常用的類是FileReaderFileWriter。 雖然FileReader內部使用FileInputStream類,而FileWriter內部使用FileOutputStream類,但主要區別在於FileReader一次讀取兩個位元組,而FileWriter一次寫入兩個位元組。

可以重新編寫上面的例子,它使用這兩個類將輸入檔案(具有unicode字元)複製到輸出檔案中 -

import java.io.*;
public class CopyFile {

   public static void main(String args[]) throws IOException {
      FileReader in = null;
      FileWriter out = null;

      try {
         in = new FileReader("D:/input.txt");
         out = new FileWriter("D:/output.txt");

         int c;
         while ((c = in.read()) != -1) {
            out.write(c);
         }
      }finally {
         if (in != null) {
            in.close();
         }
         if (out != null) {
            out.close();
         }
      }
   }
}

假設在D盤下有一個檔案:input.txt,它的內容如下 -

This is test for copy file.
power by tw511.com

下一步,編譯上面的程式並執行它,它將建立一個:D:/output.txt檔案,內容與D:/input.txt中的相同。

2. 標準流

所有程式設計語言都支援標準I/O,使用者的程式可以從鍵盤輸入,然後在計算機螢幕上產生輸出。 如果您了解C或C++程式設計語言,那麼應該了解三個標準流:STDINSTDOUTSTDERR。 同樣,Java提供以下三個標準流 -

  • 標準輸入 - 用於將資料提供給使用者程式,通常鍵盤用作標準輸入流並表示為System.in
  • 標準輸出 - 用於輸出使用者程式生成的資料,通常計算機螢幕用於標準輸出流並表示為System.out
  • 標準錯誤 - 用於輸出使用者程式生成的錯誤資料,通常計算機螢幕用於標準錯誤流並表示為System.err

以下是一個簡單的程式,它使用InputStreamReader來讀取標准輸入流,直到使用者鍵入:q -

import java.io.*;
public class ReadConsole {

   public static void main(String args[]) throws IOException {
      InputStreamReader cin = null;

      try {
         cin = new InputStreamReader(System.in);
         System.out.println("Enter characters, 'q' to quit>");
         char c;
         do {
            c = (char) cin.read();
            System.out.print(c);
         } while(c != 'q');
      }finally {
         if (cin != null) {
            cin.close();
         }
      }
   }
}

將上面的程式碼儲存在ReadConsole.java檔案中,並嘗試編譯並執行它,如下面的程式所示。 程式繼續讀取並輸出使用者輸入的字元,直到按q退出 -

$javac ReadConsole.java
$java ReadConsole
Enter characters, 'q' to quit>
1
1
a
a
C
C

3. 讀寫檔案

如前所述,流可以定義為資料序列。 InputStream用於從源讀取資料,OutputStream用於將資料寫入目標。

以下是處理輸入和輸出流的類層次結構。

輸入和輸出流

兩個重要的流是:FileInputStreamFileOutputStream,將在本教學中討論。

3.1. FileInputStream

此流用於從檔案中讀取資料。 可以使用關鍵字new建立物件,並且有幾種型別的建構函式可用。

以下建構函式將檔案名作為字串來建立輸入流物件以讀取檔案 -

InputStream f = new FileInputStream("D:/java/hello.txt");

以下建構函式採用檔案物件來建立輸入流物件以讀取檔案。 首先,使用File()方法建立一個檔案物件,如下所示 -

File f = new File("D:/java/hello.txt");
InputStream f = new FileInputStream(f);

當建立了InputStream物件,就可以使用一些輔助方法來讀取流或在流上執行其他操作。

編號 方法 描述
1 public void close() throws IOException{} 此方法關閉檔案輸出流。 釋放與該檔案關聯的所有系統資源,丟擲IOException
2 protected void finalize()throws IOException {} 此方法清除與檔案的連線。 確保在沒有對此流的參照時呼叫此檔案輸出流的close()方法,丟擲IOException
3 public int read(int r)throws IOException{} 此方法從InputStream讀取指定的資料位元組,並返回一個int值。 返回資料的下一個位元組,如果它是檔案的末尾,則返回-1
4 public int read(byte[] r) throws IOException{} 此方法將輸入流中的r.length個位元組讀入陣列。返回讀取的總位元組數。 如果它到達檔案的結尾,則返回-1
5 public int available() throws IOException{} 給出可以從此檔案輸入流中讀取的位元組數。 返回一個int值。

還有其他重要的輸入流可用,有關更多詳細資訊,請參閱以下連結 -

3.2. FileOutputStream

FileOutputStream用於建立檔案並將資料寫入檔案。 如果檔案尚不存在,則會在開啟檔案以進行輸出之前建立該檔案。

這裡有兩個建構函式,可用於建立FileOutputStream物件。

以下建構函式將檔案名作為字串來建立輸入流物件以寫入檔案 -

OutputStream f = new FileOutputStream("D:/java/hello.txt")

下面的建構函式接受一個檔案物件來建立一個輸出流物件來寫入該檔案。 首先,使用File()方法建立一個檔案物件,如下所示 -

File f = new File("D:/java/hello.txt");
OutputStream f = new FileOutputStream(f);

當建立了OutputStream物件,就使用它的一些輔助方法來寫入流或在流上執行其他操作。

編號 方法 描述
1 public void close() throws IOException{} 此方法關閉檔案輸出流,釋放與該檔案關聯的所有系統資源。丟擲IOException
2 protected void finalize()throws IOException {} 此方法清除與檔案的連線,確保在沒有對此流的參照時呼叫此檔案輸出流的close()方法。丟擲IOException
3 public void write(int w)throws IOException{} 此方法將指定的位元組寫入輸出流。
4 public void write(byte[] w) 將長度為w.length的位元組從位元組陣列寫入OutputStream

還有其他重要的輸出流,有關更多詳細資訊,請參閱以下連結 -

範例

以下是演示如何使用InputStreamOutputStream類物件的範例 -

import java.io.*;
public class fileStreamTest {

   public static void main(String args[]) {

      try {
         byte bWrite [] = {11,21,3,40,5};
         OutputStream os = new FileOutputStream("D:/test.txt");
         for(int x = 0; x < bWrite.length ; x++) {
            os.write( bWrite[x] );   // writes the bytes
         }
         os.close();

         InputStream is = new FileInputStream("D:/test.txt");
         int size = is.available();

         for(int i = 0; i < size; i++) {
            System.out.print((char)is.read() + "  ");
         }
         is.close();
      } catch (IOException e) {
         System.out.print("Exception");
      }    
   }
}

上面的程式碼將建立檔案test.txt並將以二進位制格式寫入給定的數位資料,同樣也會在螢幕上輸出。

4. 檔案導航和I/O

可通過其他幾個類來了解檔案導航和I/O的基礎知識。如下 -

4.1. 目錄操作

目錄是一個檔案,它可以包含其他檔案和目錄的列表。 使用File物件建立目錄,列出目錄中可用的檔案。 有關完整的詳細資訊,請檢視在File物件上呼叫的所有方法的列表以及與目錄相關的內容。

4.1.1. 建立目錄

有兩種File類的方法,可用於建立目錄 -

  • mkdir()方法建立一個目錄,建立成功時返回true,失敗時返回false。 失敗表示File物件中指定的路徑已存在,或者由於整個路徑尚不存在或許可權問題而無法建立目錄。
  • mkdirs()方法建立目錄和目錄的所有上級目錄。

以下範例建立一個目錄:D:/tmp/user/java/bin -

範例

import java.io.File;
public class CreateDir {

   public static void main(String args[]) {
      String dirname = "D:/tmp/user/java/bin";
      File d = new File(dirname);

      // 建立目錄及父級目錄
      d.mkdirs();
   }
}

編譯並執行上面的程式碼來建立目錄:D:/tmp/user/java/bin

註 - Java會根據約定自動處理UNIX和Windows上的路徑分隔符。如果在Windows版本的Java上使用正斜槓(/),則路徑仍將正確解析。

4.1.2. 列出目錄

可以使用File物件的list()方法列出目錄中可用的所有檔案和目錄,如下所示 -

import java.io.File;
public class ReadDir {

   public static void main(String[] args) {
      File file = null;
      String[] paths;

      try {      
         // 建立一個File物件
         file = new File("D:/software");

         // 檔案和目錄的陣列
         paths = file.list();

         // 對於路徑陣列中的名稱
         for(String path:paths) {
            // 列印檔案名和目錄名
            System.out.println(path);
         }
      } catch (Exception e) {
         // if any error occurs
         e.printStackTrace();
      }
   }
}

執行上面程式碼,它將根據D:/software目錄中目錄和檔案產生以下結果 -

apache-maven-3.5.4
apache-tomcat-9.0.14
Aptana_Studio
eclipse
EditPlusPortable
javajars
kafka_2.11-2.0.0
mysql-5.7.23-winx64
Navicat Premium 11
php-cs-fixer.phar
spring-2.0.5.RELEASE
... ...