Java I/O

IO的核心組成就是五個類(FileOutputStreamInputStreamReaderWriter) 一個接口(Serializable)

File文件操作類

在Java.io包之中,File類是唯一一個與文件本身操作(創建、刪除、取得信息…)有關,與文件內容無關的的程序類
File類即可以描述真實文件,也可以是個文件夾

File類使用

  • File類的兩種實例化方式:
public File(String pathname) 
public File(String parent, String child) 
  • 創建新文件
public boolean createNewFile() throws IOException 
  • 判斷文件是否存在
public boolean exits()
  • 刪除文件
public boolean delete()

範例:編寫文件的基本操作(如果文件不存在則進行創建;存在則刪除)

package www.bit.FileTest;

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

public class MyFile {
    public static void main(String[] args) {
        // 定義要操作的文件路徑
        // 路徑分隔符:File.separator
        File file = new File("C:"+File.separator+"Users"+File.separator
                +"DELL"+File.separator+"Desktop"+File.separator+"TestIO.java");
        if (file.exists()){
            file.delete();
        }else{
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

有關目錄的操作

  • 取得父路徑與父File對象
public String getParent()
public File getParentFile()
  • 創建目錄(無論有多少級父目錄,都會一次性創建)
public boolean mkdirs()

範例:Java文件目錄操作

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

public class MyFile {
    public static void main(String[] args) throws IOException{
        File file = new File("C:"+File.separator+"Users"+File.separator
                +"DELL"+File.separator+"Desktop"+File.separator+"Test"+
                File.separator+"Java IO"+File.separator+"TestIO.java");
        if (!file.getParentFile().exists()){  // 創建父目錄
            file.getParentFile().mkdirs();  // 有多少級父目錄就創建多少級
        }
        if (file.exists()){
            // 文件存在,進行刪除 
            file.delete();
        }else {
            file.createNewFile();
        }
    }
}

文件信息

  • 判斷File對象是否是文件
public boolean isFile()
  • 判斷File對象是否是路徑
public boolean isDirectory()
  • 取得文件大小
public long length()
  • 取得最後修改日期
public long lastModified()

範例:取得文件信息

import java.io.File;
import java.io.IOException;
import java.util.Date;

public class MyFile {
    public static void main(String[] args) throws IOException{
        File file = new File("C:"+File.separator+"Users"+File.separator
                +"DELL"+File.separator+"Desktop"+File.separator+"sifanchao.jpg");
        if (file.exists() && file.isFile()){
            System.out.println("文件大小:" + file.length()/1024 + "Kb");
            System.out.println("最後一次修改日期: " + new Date(file.lastModified()));
        }
    }
}
  • 列出一個目錄的全部組成:
public File[] listFiles()

範例:列出C盤目錄中的全部組成

import java.io.File;

public class MyFile {
    public static void main(String[] args){
        new Thread(()-> {
            File file = new File("C:");
            // 列出桌面目錄中的全部組成
            // +File.separator+"Users"+File.separator+"DELL"+File.separator+"Desktop"
            System.out.println("遍歷文件開始...");
            long start = System.currentTimeMillis();
            listAllFiles(file);
            long end = System.currentTimeMillis();
            System.out.println("遍歷文件結束。共耗時:" + (end-start) + "毫秒");
        }).start();
    }
    public static void listAllFiles(File file){
        if (file.exists() && file.isFile()){
            System.out.println(file);
        }else {
            File[] files = file.listFiles();
            if (files != null){
                for (File file1 : files){
                    listAllFiles(file1);
                }
            }
        }
    }
}

IO相關處理屬於阻塞式耗時操作,一般放在子線程中進行

字節流與字符流

File類不支持文件內容處理,如果要處理文件內容,必須要通過流的操作模式來完成。流分爲輸入流和輸出流。 在java.io包中,流分爲兩種:字節流與字符流

  • 字節流:InputStream、OutputStream
  • 字符流:Reader、Writer
    在這裏插入圖片描述
    在這裏插入圖片描述

字節流與字符流操作的本質區別只有一個:字節流是原生的操作,而字符流是經過處理後的操作

一般使用字節流(無論是網絡傳輸還是磁盤數據保存均以字節爲單位)。
而所有磁盤中的數據必須先讀取到內存後才能進行操作,內存中會幫助我們把字節變爲字符。所以,只有處理中文文本時纔會用到字符流。

流操作流程

無論是字節流還是字符流,操作流程幾乎一樣,以文件操作爲例:

  1. 取得File對象
  2. 取得File對象的輸入、輸出流
  3. 進行數據的讀取或寫入
  4. 關閉流(close)

對於IO操作屬於資源處理,所有的資源處理操作(IO操作、數據庫操作、網絡)後必須要進行關閉

字節輸出流(OutputStream)

如果要想通過程序進行內容輸出,則可以使用java.io.OutputStream

public abstract class OutputStream implements Closeable, Flushable

OutputStream類實現了Closeable,Flushable兩個接口,這兩個接口中的方法:

  1. Closeable: public void close() throws IOException;
  2. Flushable: public void flush() throws IOException;

在OutputStream類中還定義有其他方法:

  • 將指定的字節數組全部輸出
public void write(byte[] b)throws IOException
  • 將部分字節數組輸出
public void write(byte[] b,int offset,int len)throws IOException
  • 輸出單個字節
public abstract void write(int b)throws IOException

由於OutputStream是一個抽象類,所以要想爲父類實例化,就必須要使用子類。由於方法名稱都由父類聲明好 了,所以我們在此處只需要關心子類的構造方法。如果要進行文件的操作,可以使用FileOutputStream類來處理, 這個類的構造方法如下:

  • 文件內容覆蓋
public FileOutputStream(File file) throws FileNotFoundException
  • 文件內容追加
public FileOutputStream(File file, boolean append) throws FileNotFoundException

範例:實現文件的內容輸出

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class MyFile {
    public static void main(String[] args) throws Exception{
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){  // 必須保證父目錄存在
            file.getParentFile().mkdirs();  // 創建多級父目錄
        }
        // OutputStream是一個抽象類,所以需要通過子類進行實例化,
        // 此時只能操作File類
        OutputStream outputStream = new FileOutputStream(file);
        // 要求輸出到文件的內容
        String msg = "你好,中國!";
        outputStream.write(msg.getBytes());
        outputStream.close();
    }
}

當使用FileOutputStream進行文件內容輸出時時候,只要文件的父路徑存在,所有的文件會自動幫助用戶創建,不在需要調用createFile()方法手工創建

這個時候程序如果重複執行,並不會出現內容追加的情況而是一直在覆蓋。如果需要文件內容追加,則需要調用 FileOutputStream提供的另外一種構造方法。

範例:文件內容追加

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class MyFile {
    public static void main(String[] args) throws Exception{
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){  
            file.getParentFile().mkdirs(); 
        }
        // true表示允許內容的追加操作
        OutputStream outputStream = new FileOutputStream(file,true);
        String msg = "我愛你\r\n";
        outputStream.write(msg.getBytes());
        outputStream.close();
    }
}

AutoCloseable自動關閉支持

從JDk1.7開始追加了一個AutoCloseable接口,這個接口的主要目的是自動進行關閉處理,但是這種處理一般不好用,因爲使用自動關閉接口有一個前提,需要結合try…catch…代碼塊

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class MyFile {
    public static void main(String[] args) throws Exception{
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        try (OutputStream outputStream = new
                FileOutputStream(file,true)){
            String msg = "改革開放40週年\r\n";
            outputStream.write(msg.getBytes());
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

字節輸入流:InputStream

利用了OutputStream實現了程序輸出內容到文件的處理,下面使用InputStream類在程序中讀取文件內容。 InputStream類的定義如下:

public abstract class InputStream implements Closeable
  • 讀取數據到字節數組b中
public int read(byte b[]) throws IOException

返回值三種情況:

  1. 返回b長度:當讀取的數據大小>字節數組大小,返回字節數組大小
  2. 返回大於0但是小於b長度:當讀取的數據大小<字節數組大小,返回真正讀取大小
  3. 返回-1:數據讀取完畢
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class MyFile {
    public static void main(String[] args) throws Exception{
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (file.exists()){
            InputStream inputStream = new FileInputStream(file);
            // 每次可以讀取的大數量
            byte[] data = new byte[1024];
            // 此時的數據讀取到了數組之中
            int len = inputStream.read(data);
            System.out.println(new String(data,0,len));
            inputStream.close();
        }
    }
  • 讀取單個字節
public int read() throws IOException

字符輸出流Writer

字符適合於處理中文數據,Writer是字符輸出流的處理類,這個類的定義如下:

public abstract class Writer implements Appendable, Closeable, Flushable

OutputStream相比多了一個Appendable接口。 在Writer類裏面也提供write()方法,而且該方法接收的類提供了一個直接輸出字符串的方法:

public void write(String str) throws IOException

範例:通過Writer實現輸出

import java.io.*;

public class MyFile {
    public static void main(String[] args) throws Exception {
        // 取得File對象
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        // 取得輸出流
        Writer out = new FileWriter(file);
        // 寫入數據
        String msg = "你好,世界!" ;
        out.write(msg);
        // 關閉
        out.close();
    }
}

Writer類的結構與方法的使用與OutputStream非常相似,只是Writer類對於中文的支持很好並且提供了直接寫入 String的方法而已。

字節的輸入流Reader

Reader依然也是一個抽象類。如果要進行文件讀取,同樣的,使用FileReader。

在上面講到的Writer類中提供有方法直接向目標源寫入字符串,Reader類中沒有方法可以直接讀取字符串,只能通過字符數組來讀取

import java.io.*;

public class MyFile {
    public static void main(String[] args) throws Exception {
        // 取得File對象
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        // 取得輸入流
        Reader reader = new FileReader(file);
        // 讀入數據
        char[] data = new char[1024];
        int len = reader.read(data);
        System.out.println(len);
        System.out.println(new String(data,0,len));
        reader.close();
    }
}

字符流適合處理中文,字節流適合處理一切數據類型(對中文支持不好)

字符流VS字節流

  1. 從實際開發來講,字節流優先考慮,只有處理中文時纔會考慮使用字符流
  2. 所有字符流操作,無論是寫入還是輸出,數據都先保存在緩存中

如果字符流不關閉,數據就有可能保存在緩存中並沒有輸出到目標源。這種情況下就必須強制刷新才能夠得到完整數據。

import java.io.*;

public class MyFile {
    public static void main(String[] args) throws Exception {
        // 取得File對象
        File file = new File("C:" + File.separator + "Users" + File.separator
                + "DELL" + File.separator + "Desktop" + File.separator + "Test.txt");
        if (!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        // 取得輸出流
        Writer out = new FileWriter(file);
        // 寫入數據
        String msg = "你好,世界!" ;
        out.write(msg);
        out.flush();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章