Java 文件 IO 操作
- 2020 年 10 月 7 日
- 筆記
window 路徑分割符:
\ 表示 windows 系統文件目錄分割符
java 程式碼在 windows 下寫某個文件的話需要下面的方式
D:\\soft\\sdclass.txt 其中一個單斜杠是用來轉義的
程式碼和文件目錄的關係: 對文件和目錄增刪改查
IO,輸入和輸出 Input/Output
把持久化設備上的數據讀取到記憶體中的動作稱為輸入, Input 操作
記憶體中的數據持久化到設備上的動作, Output 輸出操作
一般把輸入和輸出動作稱為 IO 操作, IO 分為網路 IO 和文件 IO
java 文件類 File :
主要是對電腦文件目錄的操作,對文件和目錄的增刪改查, File 類表示磁碟中存在的文件和目錄
實現了 Serializable, Comparable 兩大介面,可進行序列化和比較
File.separator 目錄分隔符,在不同的系統下不一樣, windows 下是 “\\” , mac/Linux 下是 “/”,操作文件時可以用來連接目錄的分隔符
常見的構造函數:
//路徑和文件名的拼接
public File(String pathname)
//父路徑,子路徑
public File(String parent, String child)
// 獲取帶文件名的文件路徑,即 new File 構造函數傳入的路徑
String getPath()
String dir = “C:\\Users\\79466\\Desktop\\”;
String name = “a.txt”;
File file = new File(dir, name);
// File file = new File(dir); 目錄對象
System.out.println(file.getPath()); // 列印文件的路徑和文件名
System.out.println(File.separator); // 列印不同系統的文件分隔符
// 常用的文件操作 api
file.getPath(); // 獲取帶文件名的文件路徑, C:\Users\79466\Desktop\a.txt
file.getName(); // 獲取文件名, a.txt
file.getAbsolutePath(); // 獲取文件的絕對路徑 C:\Users\79466\Desktop\a.txt
file.getParent(); // 獲取文件的父路徑 C:\Users\79466\Desktop
file.exists(); // 文件或者目錄是否存在
file.isFile(); // 是否是一個文件
file.isDirectory(); // 是否是一個目錄
file.isAbsolute(); //是否是絕對路徑
// 如果 file 是目錄,獲取文件目錄下所有的文件及目錄的名稱,操作對象是目錄,如果是文件會報錯
String[] arr = file.list();
for (String temp : arr) {
System.out.println(temp);
}
// 創建指定目錄
File mkdir = new File(dir + “\\xd”);
mkdir.mkdir(); //創建一級目錄
File mkdirs = new File(dir + “\\xd\\aa\\bb\\cc”); // 或者 dir + “\\xd\\aa\\bb\\cc\\”
mkdirs.mkdirs(); //創建多級目錄
File newFile = new File(dir + “\\xxxx.txt”);
// 如果 dir 不存在或者創建文件失敗需要捕獲異常
try {
newFile.createFile();
} catch (IOException e) {
e.printStackTrace();
}
newFile.delete(); //刪除操作,當前文件如果是最終的文件才可以刪除,如果是目錄,裡面還有文件,需要先刪除文件才能刪除該目錄
File 的構造函數只是創建一個 File 實例,即使目錄錯誤也不會報錯,因為沒有對文件進行操作
輸出流: 程式到外界設備 輸入流: 外界設備到程式
處理數據類型分類
字元流: 處理字元相關,如文本數據( txt 文件), Reader / Writer
位元組流: 處理位元組相關,聲音或者圖片等二進位, InputStream/OutputStream
兩者區別:
位元組流以位元組(8bit)為單位,字元流以字元為單位,根據碼錶映射字元,一次可能讀多個位元組
位元組流可以處理幾乎所有文件,字元流只能處理字元類型的數據,如果文件都是中文文本的話可以使用字元流,速度更快,更省空間
功能不同,但是具有共性內容,抽象成4個抽象類
字元流 Reader/Writer
位元組流 InputStream/OutputStream
使用的時候都不會使用抽象類進行實現,開發使用對應的子類
位元組流:
InputStream: 實現類及子類有 FileInputStream (用的最多, BufferedInputStream 提高性能)、 ObjectInputStream (對象輸入流,序列化的時候) 、 ByteArrayInputStream
OutputStream 和 InputStream 一樣
int read(byte[] buf) // 從輸入流中讀取一定數量的位元組,並將其存儲在緩衝區數組 buf 中,返回實際讀取的位元組數
int available() // 返回這個流中有多少個位元組數,可以把 buf 數組長度定為這個
void close() throws IOException // 關閉輸入流並釋放與該流關聯的系統資源
FileInputStream 位元組輸入流:
// 傳入文件所在地址
public FileInputStream(String name) throws FileNotFoundException
// 傳入文件對象
public FileInputStream(File file) throws FileNotFoundException
public static void main (String [] args) {
File file = new File(dir, name);
InputStream inputStream = new FileInputStream(file);
// 讀取一個位元組
int read = inputStream.read();
// 位元組對應的 ASCII 碼
System.out.println(read);
// 強轉成字元
System.out.println((char)read);
}
inputStream.skip(); // 跳過,從輸入流中跳過並丟棄 n 個位元組的數據
byte[] buf = new byte[1024];
int length;
// 一次性讀取 buf.length 個位元組並放到 buf 數組中,返回類型是讀取到的位元組數
while ((length = inputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, length)); // 從0開始,長度是3
System.out.println(new String(buf, 0, length, “UTF-8”));
}
FileOutputStream 位元組輸出流:
構造:
// 傳入輸出的文件地址
public FileOutputStream(String name)
// 傳入目標輸出的文件對象
public FileOutputStream(File file)
// 傳入目標輸出的文件對象,是否可以追加內容
public FileOutputStream(File file, boolean append)
public static void main(String [] args) {
String target = “a.txt”;
InputStream inputStream = new FileInputStream(file);
// 會創建文件,但是不會創建多級目錄
// OutputStream outputStream = new FileOutputStream(dir + File.separator + target);
// 不覆蓋文件,只追加數據
OutputStream outputStream = new FileOutputStream(dir + File.separator + target, true);
byte[] buf = new byte[1024];
int length;
// 一次性讀取 buf.length 個位元組並放到 buf 數組中,返回類型是讀取到的位元組數
while ((length = inputStream.read(buf)) != -1) {
// 按位元組數組的長度寫出
outputStream.write(buf, 0, length);
}
inputStream.close();
outputStream.close();
}
緩衝 Buffer :
記憶體空間的一部分,在記憶體空間預留了一定的存儲空間,這些存儲空間用來緩衝輸入或輸出的數據,這部分空間就叫做緩衝區,緩衝區默認大小是8k,使用緩衝區暫存數據,可以減少和磁碟的交互,讀入時與磁碟連接後讀入較多的數據到緩衝區,記憶體再慢慢去消耗,
BufferInputStream 緩衝位元組輸入流,讀取數據時,與磁碟連接一次讀取到記憶體,緩衝區滿時會再讀取下一截數據填充到緩衝區
構造函數:
// 對輸入流進行包裝,裡面默認的緩衝區是8k
public BufferedInputStream(InputStream in);
// 對輸入流進行包裝,創建具有指定緩衝區大小的 Buffer
public BufferedInputStream(InputStream in, int size);
方法:
// 從輸入流中讀取一個位元組
public int read();
// 從位元組輸入流中給定偏移量處開始將各位元組讀取到指定的 byte 數組中
public int read(byte[] buf, int off, int len);
// 關閉資源,關閉這個流即可, InputStream 會在裡面被關閉
void close();
BufferOutputStream 緩衝位元組輸出流,當緩衝區滿時,會自動寫出到磁碟
構造同上
常用方法:
// 向輸出流中輸出一個位元組
public void write(int b);
// 將指定 byte 數組中從偏移量 off 開始的 len 個位元組寫入緩衝的輸出流
public void write(byte[] buf, int off, int len);
// 刷新此緩衝的輸出流,強制使所有緩衝的輸出位元組被寫出到底層輸出流中,當緩衝區的大小未滿時,需要手動刷到磁碟
public void flush();
// 關閉釋放資源, OutputStream 會在裡面被關閉, JDK7 新特性 try (在這裡聲明的 流 會自動關閉){}
void close();
緩衝輸入輸出流進行文件拷貝:
try {
FileInputStream fis = new FileInputStream(“C:\\Users\\79466\\Desktop\\test\\a.txt”);
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(“C:\\Users\\79466\\Desktop\\test\\copy.txt”);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int size;
byte[] buf = new byte[1024];
while (( size = bis.read(buf)) != -1) {
// 將位元組輸出流寫到緩衝區裡面,等緩衝區滿後自動寫出
bos.write(buf, 0, size);
}
// 刷新此緩衝區的輸出流,才可以保證數據全部輸出完成,關閉的時候也會進行刷新,寫了也不要緊,也就是多刷一次, close 方法的關閉前會先進行刷新
// bos.flush();
// 內部會關掉 InputStream 和 OutputStream
bis.close();
// close 源碼裡面會有 flush ,可以不用單獨調用 flush ,jdk7 之後 close 源碼里的 try 裡面聲明了 OutputStream ,會自動關閉 outputStream 流
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
流的關閉順序,後開的先關,如果A依賴B,先關閉B
IO 的異常處理:
大部分公司的做法: 在 finally 裡面進行關閉
catch (Exception e) {
e.printStackTrace();
} finally {
if(bis != null) {
try {
bis.close();
}catch () {
e.printStackTrace();
}finally {
if(bos != null) {
try {
bos.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
jdk7 之後的做法: try-with-resource
try 裡面聲明的 OutputStream 和 InputStream 會自動關閉, jdk7 之後的 InputStream 都實現了 AutoCloseable
在 try 裡面定義多個資源,關閉的順序是最後在 try() 定義的資源最先關閉
try (
FileInputStream fis = new FileInputStream(“C:\\Users\\79466\\Desktop\\test\\a.txt”);
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(“C:\\Users\\79466\\Desktop\\test\\copy.txt”);
BufferedOutputStream bos = new BufferedOutputStream(fos);) {
int size;
byte[] buf = new byte[1024];
while(( size = bis.read(buf)) != -1 ) {
bos.write(buf, 0, size);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
}