IO操作
Flie類
-
介紹:
File物件表示路徑,可以是檔案、也可以是資料夾。
這個路徑可以是存在的,也可以是不存在的
絕對路徑是帶磁碟機代號的。相對路徑是不帶磁碟機代號的,預設到當前專案下去找
-
File物件代表磁碟中實際存在的檔案和目錄。透過以下構造方法建立一個File物件:
- 透過給定的父抽象路徑名和子路徑名字串建立一個新的File例項。
File(File parent, String child); File(String parent,String child);
- 把字串表示的路徑
File(String pathname) ;
-
建立File物件成功後,可以使用以下列表中的方法操作檔案。
- public String getName():返回由此抽象路徑名錶示的檔案或目錄的名稱。
- public String getPath():將此抽象路徑名轉換為一個路徑名字串。
- public boolean canRead():測試應用程式是否可以讀取此抽象路徑名錶示的檔案。
- public boolean canWrite():測試應用程式是否可以修改此抽象路徑名錶示的檔案
- public boolean exists():測試此抽象路徑名錶示的檔案或目錄是否存在
- public boolean isDirectory():測試此抽象路徑名錶示的檔案是否是一個目錄。
- public boolean isFile():測試此抽象路徑名錶示的檔案是否是一個標準檔案
- public long lastModified():返回此抽象路徑名錶示的檔案最後一次被修改的時間。
- public boolean mkdir():建立此抽象路徑名指定的目錄。
- public boolean renameTo(File dest): 重新命名此抽象路徑名錶示的檔案
- public boolean setReadOnly():標記此抽象路徑名指定的檔案或目錄,以便只可對其進行讀操作。
-
createNewFile 建立一個新的空的檔案
- 如果當前路徑表示的檔案是不存在的,則建立成功,方法返回true,如果當前路徑表示的檔案是存在的,則建立失敗,方法返回false
- 如果父級路徑表示的檔案是存在的,那麼方法會有異常IOException
- createNewFile方 法建立的一定是檔案,如果路徑中不包含字尾名,則建立一個沒有字尾的檔案。
-
mkdirs 建立多級資料夾
- windows當中路徑是唯一的,如果當前路徑已經存在,則建立失敗,返回false
- midir方法只能建立單級資料夾,無法建立多級資料夾。
- midirs既可以建立單級資料夾,也可以建立多級資料夾。
-
delete方法
- 如果刪除的是檔案,則直接刪除,不走回收站
- 如果刪除的是空資料夾,則直接刪除,不走回收站。
- 如果刪除的是有內容的檔案,則刪除失敗。
-
listFiles()方法
- 當呼叫者File表示的路徑不存在時,返回null
- 當呼叫者File表示的路徑時檔案時,返回null
- 當呼叫者File表示的路徑時一個空檔案時,返回一個長度為0的陣列
- 當呼叫者File表示的路徑時一個有內容的資料夾時,將裡面所有檔案和資料夾的路徑放在File陣列中放回
- 當呼叫者File表示的路徑是一個有隱藏檔案的資料夾時,將裡面所有檔案和資料夾的路徑放在File陣列中返回,包含隱藏檔案
- 當呼叫者File表示的路徑時需要許可權才能訪問的資料夾時,返回null
IO流
-
IO的初步瞭解
-
什麼是io流
儲存和讀取資料的解決方案
I:input O : output
-
IO流的作用?
用於讀寫資料(本地檔案,網路)
-
IO流按照流向可以分類哪兩種流?
輸出流:程式-> 檔案
輸入流:檔案-> 程式
-
IO流按照操作檔案的型別可以分類哪兩種流?
位元組流:可以操作所有型別的檔案
字元流:只能操作純文字檔案
-
什麼是純文字檔案?
用windows系統自帶的記事本開啟並且能夠讀懂的檔案
txt檔案,md檔案,xml檔案,lrc檔案等
純文字檔案可以使用字元流去讀取操作,而非純文字檔案如word,excel檔案不能使用字元流,需要使用位元組流。
-
-
位元組輸出流的細節
- 建立位元組輸出流物件
- 引數是字串表示的路徑或者是File物件都是可以的
- 如果檔案不存在會建立一個新的檔案,但是要保證父級路徑是存在的
- 如果檔案已經存在,則會清空檔案
- 寫資料:
- write方法的引數是整數,但是實際上寫到本地檔案中的是整數在ASCII上對應的字元
- 釋放資源:
- 每次使用完流之後都要釋放資源,解除資源的佔用
- 建立位元組輸出流物件
-
位元組輸入流的細節:
- 建立位元組輸入流物件
- 如果檔案不存在,就直接報錯
- 寫資料
- 一次讀一個位元組,讀出來的是資料在ASCII上對應的數字’
- 讀到檔案末尾了,read方法返回-1
- 釋放資源
- 每次使用完流之後都要釋放資源,解除資源佔用
- 建立位元組輸入流物件
-
copy大檔案時
public class ByteStreamDemo3 { public static void main(String[] args) throws IOException { FileInputStream fileInputStream = new FileInputStream("D:\\BaiduNetdiskDownload\\影片.mp4"); FileOutputStream fileOutputStream = new FileOutputStream("data/copy.mp4"); int len ; byte[] bytes = new byte[1024 * 1024 * 5]; while ((len = fileInputStream.read(bytes))!=-1){ fileOutputStream.write(bytes,0,len); } fileOutputStream.close(); fileInputStream.close(); } }
-
如何不產生亂碼?
- 不要用位元組流讀取文字檔案
- 編碼解碼時使用同一個碼錶,同一個編碼方式
-
字元流讀取
- 空參讀取
- 預設也是一個位元組一個位元組的讀取的,如果遇到中文就會一次讀取多個,在讀取之後,方法的底層還會進擊解碼並轉成十進位制
- 有參讀取
- 讀取資料,解碼,強轉三步合併了,把強轉之後的字元放到陣列當中。相當於空參的read+強轉型別轉換。
- 空參讀取
-
位元組流和字元流的使用場景
- 位元組流:
- 複製任意型別的檔案
- 字元流:
- 讀取純文字檔案中的資料
- 往純文字檔案中寫出資料
- 位元組流:
-
實列從一個資料夾複製到另一個資料夾
public class test1 { public static void main(String[] args) throws IOException { File src = new File("D:\\蘭智數加\\aaa\\src"); File dest = new File("D:\\蘭智數加\\aaa\\dest"); copydir(src,dest); } private static void copydir(File src, File dest) throws IOException { dest.mkdirs(); // 1.進入資料來源 File[] files = src.listFiles(); // 2.遍歷陣列 for (File file : files) { //3.判斷是否為檔案,然後複製 if(file.isFile()){ FileInputStream fileInputStream = new FileInputStream(file); FileOutputStream fileOutputStream = new FileOutputStream(new File(dest, file.getName())); byte[] bytes = new byte[1024]; int len; while ((len=fileInputStream.read(bytes))!=-1){ fileOutputStream.write(bytes,0,len); } fileOutputStream.close(); fileInputStream.close(); }else { //4.判斷是否為資料夾,然後遞迴 copydir(file,new File(dest,file.getName())); } } } }
-
緩衝流
- 緩衝流有幾種?
- 位元組緩衝輸入流:BufferedInputStream
- 位元組緩衝輸出流:BufferedOutputStream
- 字元緩衝輸入流:BufferedReader
- 字元緩衝輸出流:BufferedWriter
- 緩衝流為什麼能提高效能
- 緩衝流自帶長度為8192的緩衝區
- 可以顯著提高位元組流的讀寫效能
- 對於字元流提升不明顯,對於字元緩衝流而言關鍵點是兩個特有的方法
- 字元緩衝流兩個特有的方法是什麼?
- 字元緩衝輸入流 readLine()
- 字元緩衝輸出流newLine()
下面是一個緩衝流的簡單應用
import java.io.*; public class BufferedStreamDemo1 { /*TODO 節約的時間是在讀和寫時與硬碟打交道的時間 */ public static void main(String[] args) throws IOException { // 建立緩衝流讀取資料 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("data/a.txt")); // 建立緩衝流寫出資料 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("data/copy.txt")); int readLine; while ((readLine = bis.read()) != -1){ bos.write(readLine); } bos.close(); bis.close(); } }
- 緩衝流有幾種?
-
轉換流
在 Java 中,轉換流主要用於在位元組流和字元流之間進行轉換。常用的轉換流類有
InputStreamReader
和OutputStreamWriter
。這些類提供了將位元組流轉換為字元流,或者將字元流轉換為位元組流的功能。這對於處理不同編碼格式的資料特別有用。// 這是一個簡單轉換流應用 import java.io.*; public class ConvertStreamDemo1 { public static void main(String[] args) throws IOException { // 建立位元組輸入流讀取資料 FileInputStream fileInputStream = new FileInputStream("data/GBKfileText.txt"); // 建立轉換流 讀取GBK檔案的內容 InputStreamReader isr = new InputStreamReader(fileInputStream, "GBK"); // 建立緩衝流 BufferedReader br = new BufferedReader(isr); // 建立位元組輸出流寫出資料 FileOutputStream fileOutputStream = new FileOutputStream("data/GBKfile.txt"); // 建立轉換流寫出GBK檔案 OutputStreamWriter osw = new OutputStreamWriter(fileOutputStream, "GBK"); // 建立緩衝流 BufferedWriter bw = new BufferedWriter(osw); // 讀取資料並寫出到新的地址 String line; while ((line = br.readLine()) != null){ bw.write(line); bw.newLine(); } bw.close(); br.close(); } }
-
序列化流
序列化流在 Java 中用於將物件的狀態轉換為位元組流,以便可以將物件的狀態儲存到檔案中、透過網路傳輸或儲存在資料庫中。反之,反序列化流則用於將位元組流恢復為物件。
序列化是將物件的狀態轉換為位元組流的過程,反序列化是將位元組流恢復為物件的過程。在 Java 中,序列化是透過實現
Serializable
介面來實現的。- ObjectOutputStream:用於將物件寫入輸出流(序列化)。
- ObjectInputStream:用於從輸入流讀取物件(反序列化)。
下面是一個簡單的應用:
# 建立一個標準的Student類 import java.io.Serializable; /** * Serializable介面裡面沒有抽象方法,是標記型介面 * 一旦實現這個介面,那麼就表示當前的Student類可以被序列化 * 理解: * 可以是一個物品的合格證 */ public class Student implements Serializable { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public Student(){} public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; }
# 建立一個序列化流把檔案寫道本地 import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class ObjectStreamDemo1 { public static void main(String[] args) throws IOException { /* 需求: 利用序列化流/物件操作輸出流,把一個物件寫本地檔案中 構造方法: public ObjectOutputStream(OutputStream out)把基本流變成高階流 成員方法: public final void writeObject(Object obj) 把物件序列化(寫出)到檔案中去 */ // 建立物件 Student student = new Student("EzReal", 23); // 建立序列化流的物件/物件操作輸出流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data/a.txt")); // 寫出資料 oos.writeObject(student); // 釋放資源 oos.close(); } }
# 建立一個反序列化流讀取檔案 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; public class ObjectStreamDemo2 { public static void main(String[] args) throws IOException, ClassNotFoundException { // 建立反序列化流的物件 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data/a.txt")); // 讀取資料 Object o = ois.readObject(); // 列印物件 System.out.println(o); // 釋放資源 ois.close(); } }
序列化流/反序列化流的細節彙總
- 使用序列化流將物件寫到檔案時,需要讓Javabean類實現Serializable介面。否則,會出現notSerializableException異常
- 序列化流寫到檔案中的資料是不能被修改的,一旦修改了就無法再次讀取回來了
- 序列化物件後,修改了JavaBean類,再次反序列化,會不會有問題?
- 會出問題,會丟擲InvalidClassException異常
- 解決方案:給javabean類新增SerialVersionUID(序列號、版本號)
- 如果一個物件的某個成員變數的值不想被序列化,又該怎麼實現呢?
- 解決方案:給該成員變數加transient關鍵字修飾,該關鍵字標記的成員變數不參與序列化過程
使用序列化流一次讀取多個物件
// 序列化流 import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class ObjectStreamTestOutput { public static void main(String[] args) throws IOException { Student stu1 = new Student("zhangsan", 21, "nanjin"); Student stu2 = new Student("lisi", 22, "shanghai"); Student stu3 = new Student("wangwu", 23, "shenzhen"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data/a.txt")); oos.writeObject(stu1); oos.writeObject(stu2); oos.writeObject(stu3); oos.close(); } }
// 反序列化流 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; public class ObjectStreamTestInput { public static void main(String[] args) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data/a.txt")); ArrayList<Student> stuList = new ArrayList<>(); try { while (true){ Student stu = (Student)ois.readObject(); stuList.add(stu); } }catch (Exception e){ System.out.println("檔案已經讀取到末尾,開始列印資料:"); } System.out.println(stuList); ois.close(); } }