JavaSE14(IO流與檔案讀寫)

2020-08-09 12:29:32

一、檔案讀寫

Java中通過流來讀寫檔案,流是指一連串流動的字元,是以先進先出方式發送資訊的通道。

在这里插入图片描述

輸入/輸出流與數據源:
在这里插入图片描述

Java流的分類:
在这里插入图片描述

輸入輸出流是相對於計算機記憶體來說的。

在这里插入图片描述

1、位元組流與字元流的區別

字元流的底層就是位元組流。而字元流主要是讀取文字檔案內容的,可以一個字元一個字元的讀取,也可以一行一行的讀取文字檔案內容,而位元組流讀取單位爲byte。byte作爲計算機儲存最基本單位,可以用位元組流來讀取很多其他格式的檔案,比如圖片視訊等等。基於B/S和C/S的檔案傳輸都可以採用位元組流的形式。在讀寫檔案需要對內容按行處理,比如比較特定字元,處理某一行數據的時候一般會選擇字元流。只是讀寫檔案,和檔案內容無關的,一般選擇位元組流。
位元組流就是按照位元組來進行傳輸,字元流是按照字元來傳輸.最基本的是位元組流,字元流可以說是對位元組流的一個包裝流,比如你知道了一個字元是8個位元組,那麼你讓位元組流一次傳輸8個位元組,那不就相當於一次傳輸一個字元,也就是字元流了。

位元組流與和字元流的使用非常相似,兩者除了操作程式碼上的不同之外,是否還有其他的不同呢?
實際上位元組流在操作時本身不會用到緩衝區(記憶體),是檔案本身直接操作的,而字元流在操作時使用了緩衝區,通過緩衝區再操作檔案,如圖:

下面 下麪以兩個寫檔案的操作爲主進行比較,但是在操作時位元組流和字元流的操作完成之後都不關閉輸出流。
範例:使用位元組流不關閉執行:

// 通過位元組流 寫檔案
public static void ByteWrite() {
    File file = new File("d:\\test\\test.txt");
    try {
        OutputStream outputStream = new FileOutputStream(file);
        String textString = "Hello World!!!";
        byte[] data = textString.getBytes();
        outputStream.write(data);
        //outputStream.close();
    } catch (IOException e) {
        System.out.println("位元組流寫入檔案出錯。");
        e.printStackTrace();
    }
}

在这里插入图片描述

此時沒有關閉位元組流操作,但是檔案中也依然存在了輸出的內容,證明位元組流是直接操作檔案本身的。而下面 下麪繼續使用字元流完成,再觀察效果。
範例:使用字元流不關閉執行:

// 通過字元流 寫檔案
public static void StringWrite() {
    File file = new File("d:\\test\\test.txt");
    try {
        FileWriter writer = new FileWriter(file);
        String textString = "Hello World!!!";
        writer.write(textString);
        // writer.flush();
        // writer.close();
    } catch (IOException e) {
        System.out.println("字元流寫入檔案出錯.");
        e.printStackTrace();
    }
}

程式執行結果:
在这里插入图片描述

程式執行後會發現檔案中沒有任何內容,這是因爲字元流操作時使用了緩衝區,而 在關閉字元流時會強制性地將緩衝區中的內容進行輸出,但是如果程式沒有關閉,則緩衝區中的內容是無法輸出的,所以得出結論:字元流使用了緩衝區,而位元組流沒有使用緩衝區。

在開發中是使用位元組流好還是字元流好呢?
回答:使用位元組流更好。所有的檔案在硬碟或在傳輸時都是以位元組的方式進行的,包括圖片等都是按位元組的方式儲存的,而字元是隻有在記憶體中纔會形成,所以在開發中,位元組流使用較爲廣泛。
如果要java程式實現一個拷貝功能,應該選用位元組流進行操作(可能拷貝的是圖片),並且採用邊讀邊寫的方式(節省記憶體)。

2、使用FileInputStream讀取文字檔案

範例程式碼:

/**
 * 檔案讀取
*/
public static void readFile(){
	File file=new File("D:/test/students.txt");
    try {
      InputStreamReader read = new InputStreamReader(new FileInputStream(file), "utf8");
      BufferedReader bufferedReader = new BufferedReader(read);
      String lineTxt = null;
      //回圈輸出每一行內容
      while ((lineTxt = bufferedReader.readLine()) != null) {
        System.out.println(lineTxt);
      }
      read.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
}

或者:

  /*
   * 讀取檔案
   */
  public static String read(String fileName) {
      File f = new File(fileName);
      if (!f.exists()) {
          return "File not found!";
      }
      FileInputStream fs;
      String result = null;
      try {
          fs = new FileInputStream(f);
          byte[] b = new byte[fs.available()];
          fs.read(b);
          fs.close();
          result = new String(b);
      } catch (Exception e) {
          e.printStackTrace();
      }

      return result;
  }

InputStream類常用方法及解析:
public void close() throws IOException{}
關閉此檔案輸入流並釋放與此流有關的所有系統資源。拋出IOException異常。
protected void finalize()throws IOException {}
這個方法清除與該檔案的連線。確保在不再參照檔案輸入流時呼叫其 close 方法。拋出IOException異常。
public int read(int r)throws IOException{}
這個方法從 InputStream 物件讀取指定位元組的數據。返回爲整數值。返回下一位元組數據,如果已經到結尾則返回-1。
public int read(byte[] r) throws IOException{}
這個方法從輸入流讀取r.length長度的位元組。返回讀取的位元組數。如果是檔案結尾則返回-1。
public int available() throws IOException{}
返回下一次對此輸入流呼叫的方法可以不受阻塞地從此輸入流讀取的位元組數。返回一個整數值。

3、使用FileOutputStream 寫文字檔案

範例程式碼:

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

public class FileOutputStreamTest {

	public static void main(String[] args) {
		FileOutputStream fos=null;
		 try {
			 String str ="好好學習Java";
	         byte[] words  = str.getBytes();
	         fos = new FileOutputStream("D:\\myDoc\\hello.txt");
	         fos.write(words, 0, words.length);
	         System.out.println("hello檔案已更新!");
	      }catch (IOException obj) {
	    	  System.out.println("建立檔案時出錯!");
	      }finally{
	    	  try{
	    		  if(fos!=null)
	    			  fos.close();
	    	  }catch (IOException e) {
		    	 e.printStackTrace();
	    	  }
	      }
	}
}

OutputStream類常用方法及解析:
public void close() throws IOException{}
關閉此檔案輸入流並釋放與此流有關的所有系統資源。拋出IOException異常。
protected void finalize()throws IOException {}
這個方法清除與該檔案的連線。確保在不再參照檔案輸入流時呼叫其 close 方法。拋出IOException異常。
public void write(int w)throws IOException{}
這個方法把指定的位元組寫到輸出流中。
public void write(byte[] w)
把指定陣列中w.length長度的位元組寫到OutputStream中。

二、File類

Java程式通過java.io.File 類對檔案進行存取。File 類的常用方法如下:

方法名稱 說 明
boolean exists( ) 判斷檔案或目錄是否存在
boolean isFile( ) 判斷是否是檔案
boolean isDirectory( ) 判斷是否是目錄
String getPath( ) 返回此物件表示的檔案的相對路徑名
String getAbsolutePath( ) 返回此物件表示的檔案的絕對路徑名
String getName( ) 返回此物件表示的檔案或目錄的名稱
boolean delete( ) 刪除此物件指定的檔案或目錄
boolean createNewFile( ) 建立名稱的空檔案,不建立資料夾
long length() 返迴檔案的長度,單位爲位元組, 如果檔案不存在,則返回 0L

File類的操作範例如下:

import  java.io.*;
public class FileMethods {
	public static void main(String[] args) {
	    FileMethods fm=new FileMethods();
	    File file=null;
	    file=new File("D:\\myDoc\\test.txt");
	    //fm.create(file);
	    fm.showFileInfo(file);
	    //fm.delete(file); 
   }
   /**
    * 建立檔案的方法
    * @param file 檔案物件
    */
   public void create(File file){
	   if(!file.exists()){
		   try {
			   file.createNewFile();
			   System.out.println("檔案已建立!");
		   } catch (IOException e) {
			   e.printStackTrace();
		   }
	   }
   }
   /**
    * 刪除檔案
    * @param file 檔案物件
    */
   public void delete(File file){
	   if(file.exists()){
		   file.delete();
		   System.out.println("檔案已刪除!");
	   }
   }
   
   /**
    * 顯示檔案資訊
    * @param file 檔案物件
    */
   public void showFileInfo(File file){
	   if(file.exists()){ //判斷檔案是否存在
		   if(file.isFile()){ //如果是檔案
			   System.out.println("名稱:" +  file .getName());
		       System.out.println("相對路徑: " + file.getPath());
		       System.out.println("絕對路徑: " + file.getAbsolutePath());   
		       System.out.println("檔案大小:" + file.length()+ " 位元組");   
		   } 
		   if(file.isDirectory()){
			   System.out.println("此檔案是目錄");
		   }
	   }else
		   System.out.println("檔案不存在");
   }
}

1、建立目錄

File類中有兩個方法可以用來建立資料夾:
mkdir( )方法建立一個資料夾,成功則返回true,失敗則返回false。失敗表明File物件指定的路徑已經存在,或者由於整個路徑還不存在,該資料夾不能被建立。
mkdirs()方法建立一個資料夾和它的所有父資料夾。

下面 下麪的例子建立 "/tmp/user/java/bin"資料夾:

import java.io.File;
public class CreateDir {
    public static void main(String args[]) {
        String dirname = "/tmp/user/java/bin";
        File d = new File(dirname);
        // 現在建立目錄
        d.mkdirs();
    }
}

編譯並執行上面程式碼來建立目錄 「/tmp/user/java/bin」。
注意:Java 在 UNIX 和 Windows 自動按約定分辨檔案路徑分隔符。如果你在 Windows 版本的 Java 中使用分隔符 (/) ,路徑依然能夠被正確解析。

2、讀取目錄

一個目錄其實就是一個 File 物件,它包含其他檔案和資料夾。
如果建立一個 File 物件並且它是一個目錄,那麼呼叫 isDirectory() 方法會返回 true。可以通過呼叫該物件上的 list() 方法,來提取它包含的檔案和資料夾的列表。下面 下麪展示的例子說明如何使用 list() 方法來檢查一個資料夾中包含的內容:

import java.io.File;
public class DirList {
    public static void main(String args[]) {
        String dirname = "/tmp";
        File f1 = new File(dirname);
        if (f1.isDirectory()) {
            System.out.println("目錄 " + dirname);
            String s[] = f1.list();
            for (int i = 0; i < s.length; i++) {
                File f = new File(dirname + "/" + s[i]);
                if (f.isDirectory()) {
                    System.out.println(s[i] + " 是一個目錄");
                } else {
                    System.out.println(s[i] + " 是一個檔案");
                }
            }
        } else {
            System.out.println(dirname + " 不是一個目錄");
        }
    }
}

##3、 刪除目錄或檔案
刪除檔案可以使用 java.io.File.delete() 方法。
以下程式碼會刪除目錄 /tmp/java/,需要注意的是當刪除某一目錄時,必須保證該目錄下沒有其他檔案才能 纔能正確刪除,否則將刪除失敗。

import java.io.File;
 
public class DeleteFileDemo {
    public static void main(String args[]) {
        // 這裏修改爲自己的測試目錄
        File folder = new File("/tmp/java/");
        deleteFolder(folder);
    }
 
    // 刪除檔案及目錄
    public static void deleteFolder(File folder) {
        File[] files = folder.listFiles();
        if (files != null) {
            for (File f : files) {
                if (f.isDirectory()) {
                    deleteFolder(f);
                } else {
                    f.delete();
                }
            }
        }
        folder.delete();
    }
}