Java IO系統
File類
用來處理文件目錄,既可以代表一個特定文件的名稱,也可以代表一組文件的名稱,如果代表的是一個文件組,可以調用File.list()
方法返回一個字符數組。
list()
不傳遞任何參數時返回該目錄下所有文件或文件名的字符數組(不會遞歸遍歷目錄里面的內容【只返回第一層】)如果想要過濾返回結果,可以傳遞給它一個FilenameFilter
對象,該接口只有一個方法accept, 接收一個代表某個特定文件所在目錄的File對象 dir 和一個包含了文件名的String name, list會對dir中的每個文件執行accept ,如果accept結果為true, 就把這個name加入list的結果中。
@FunctionalInterface
public interface FilenameFilter {boolean accept(File dir, String name);
}
public String[] list(FilenameFilter filter) {// 策略模式,根據filter是否為null,具有不同的策略String names[] = list();if ((names == null) || (filter == null)) {return names;}// 內部使用了ArrayListList<String> v = new ArrayList<>();for (int i = 0 ; i < names.length ; i++) {if (filter.accept(this, names[i])) {v.add(names[i]);}}return v.toArray(new String[v.size()]);}
例:
package Note.iosystem;import java.io.File;
import java.io.FilenameFilter;
import java.util.regex.Pattern;class DirFilter implements FilenameFilter {private Pattern pattern;DirFilter (String regex){pattern = Pattern.compile(regex);}@Overridepublic boolean accept(File dir, String name) {return pattern.matcher(name).matches();}
}public class DirList {public static void main(String[] args) {File file = new File("./src/Note/iosystem");String filter = ".*\\.java";String [] filenames = file.list(new DirFilter(filter));assert filenames != null;for (String filename:filenames) {System.out.println(filename);}}
}
使用匿名內部類使得代碼更加簡潔
package Note.iosystem;import java.io.File;
import java.io.FilenameFilter;
import java.util.regex.Pattern;public class DirList2 {public static void main(String[] args) {File file = new File("./src/Note/iosystem");String filter = ".*\\.java";String [] filenames = file.list(new FilenameFilter() {private Pattern pattern = Pattern.compile(filter);@Overridepublic boolean accept(File dir, String name) {return pattern.matcher(name).matches();}});assert filenames != null;for (String filename:filenames) {System.out.println(filename);}}
}
其他常用方法
1. 構造方法
File(String pathname) 通過將給定的路徑名字符串轉換為抽象路徑名來創建新的 File實例。 通過將給定的路徑名字符串轉換為抽象路徑名來創建新的File實例。 如果給定的字符串是空字符串,則結果是空的抽象路徑名。
public static void main(String[] args) {// Java 中一個 “\” 表示轉義開始File file = new File("E:\\桌面文件\\JAVA\\src\\demo.txt");}
File(String parent, String child) 從父路徑名字符串和子路徑名字符串創建新的 File實例。
File file1 = new File("E:\\桌面文件\\JAVA\\src", "demo.txt");
第一個參數傳入父級路徑字符串,第二個參數傳入相對父級路徑的子路徑名
File(File parent, String child) 從父抽象路徑名和子路徑名字符串創建新的 File實例。
File file2 = new File("E:\\桌面文件\\JAVA\\src");
File file3 = new File(file2, "demo.txt");
File(URI uri) 通過將給定的 file: URI轉換為抽象路徑名來創建新的 File實例。
2 成員方法
2.1 創建
成員方法 | 功能 | 參數介紹 | 返回值介紹 | 異常 | 備注 |
---|---|---|---|---|---|
public boolean createNewFile() | 創建文件,如果存在就不創建 | —— | 創建成功返回true,文件存在或創建失敗返回false | IOException | 路徑不存在拋出IOException異常 |
public boolean mkdir() | 創建文件夾 | 無 | 返回是否創建成功 | IOException | 父路徑不存在返回false |
public boolean mkdirs() | 創建多級目錄 | 無 | 返回是否成功 | IOException | 路徑不存在就創建 |
2.2 刪除
成員方法 | 功能 | 參數介紹 | 返回值介紹 | 異常 | 備注 |
---|---|---|---|---|---|
public boolean delete() | 刪除文件或文件夾 | 無 | 返回是否刪除成功 | 1. 文件不存在返回false 2. 刪除文件夾時只能刪除空文件夾 |
2.3 重命名或移動
成員方法 | 功能 | 參數介紹 | 返回值介紹 | 異常 | 備注 |
---|---|---|---|---|---|
public boolean renameTo(File dest) | 重命名文件 | dest:重命名文件的新的抽象路徑名 | 返回是否重命名成功 | 可以使用這個方法實現移動(剪貼)功能 |
2.4 判斷
成員方法 | 功能 | 參數介紹 | 返回值介紹 | 異常 | 備注 |
---|---|---|---|---|---|
public boolean isDirectory() | 判斷是否是目錄 | 無 | 返回是否是目錄 | 只有是目錄且目錄存在時返回true | |
public boolean isFile() | 判斷是否是文件 | 無 | 返回是否是文件 | ||
public boolean isHidden() | 判斷是否是隱藏文件 | 無 | ·· | UNIX中,以. 開頭的是隱藏文件,而window中,特殊標記過的是隱藏文件 | |
public boolean exists() | 判斷文件或目錄是否存在 | 無 | 返回是否存在 | ||
public boolean canWrite() | 判斷文件是否可寫 | 無 | 返回是否可寫 | ||
public boolean canRead() | 判斷文件是否可讀 | 無 | 返回是否可讀 | ||
public boolean isAbsolute() | 判斷路徑是否是絕對路徑 | 無 | 在UNIX系統上,如果前綴為"/" ,路徑名是絕對的。 在Windows系統上,前面是盤符或/// 為絕對路徑 |
2.5 獲取功能
成員方法 | 功能 | 參數介紹 | 返回值介紹 | 異常 | 備注 |
---|---|---|---|---|---|
public String getName() | 返回文件或目錄名稱 | 無 | String | 這個方法只是對路徑字符串的分割操作,不檢查路徑是否存在 | |
public String getParent() | 返回文件或文件夾父路徑名字符串 | 無 | String | 也只是字符串的分割操作,不檢查路徑或文件是否真實存在 | |
public File getParentFile() | 返回文件或文件夾的父路徑的File對象 | 無 | File | 內部調用的是getParent()方法 | |
public String getPath() | 返回文件路徑 | 無 | String | ||
public String getAbsolutePath() | 返回絕對路徑 | 無 | String | 同樣不關心文件是否存在 | |
public File getAbsoluteFile() | 返回絕對形式的File對象 | 無 | File | ||
public String getCanonicalPath() | 返回文件規范路徑名字符串 | 無 | String | IOException | 先轉換成絕對路徑,然后刪除. ,.. 等冗余名稱等。。 |
public File getCanonicalFile() | 返回文件規范路徑名的File對象 | IOException | |||
public long lastModified() | 返回文件上次修改時間 | 無 | Long 返回一個時間戳 | 如果文件不存在返回0 | |
public long length() | 返回文件長度 | 無 | Long 文件長度,以字節為單位 | 文件不存在返回0 | |
public String[] list([FilenameFilter filter]) | 返回該目錄下所有文件和目錄的數組 | 可以傳入一個FilenameFilter filter,表示列出滿足過濾器的文件或目錄名 | |||
public File[] listFiles([FilenameFilter filter]) | 類似于上面 |
流總覽
流對象代表任何有能力產出數據的源對象或任何有能力消費數據的目標對象,Java中IO類分為輸入和輸出兩部分,對應輸入流和輸出流任何繼承自InputStream
或Reader
的類都包含基本方法read()
用來讀字節或字節數組(字符),任何繼承自OutputStream
或Writer
的類都包含基本方法write()
用來寫字節或字節數組。
輸入輸出是相對于當前程序而言的
InputStream和OutputStream
Java1.0中,所有輸入相關的類都從InputStream
繼承而來,所有輸出相關的類都從OutputStream
繼承而來,也就是字節流。
InputStream
InputStream用來表示從不同輸入源產生輸入的類,這些輸入源包括:
- 字節數組
- String對象
- 文件
- 管道
- 一個由其他種類的流組成的序列,我們可以把它們合并到同一個流里
- 其他數據源,如Interest連接等
每種數據源都對應一個具體的InputStream的子類
OutputStream
他的子類決定了輸出要去往的目標,包括:
- 字節數組
- 管道
- 文件
Reader 和 Writer
Java1.1 中加入了 Reader 和 Writer類,來提供兼容Unicode和面向字符的IO功能,對于數據的來源和去向,字節流中有的字符流差不多都有對應的。
因此,最明智的做法是盡量嘗試使用Reader和Writer,一旦編譯無法通過,我們會發現不得不使用面向字節的類庫。
——《Java編程思想》
常用流
文件流
FileInputStream,FileOutputStream,FileReader, FileWriter
package Note.iosystem;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class CopyFile {private String sourcePath, targetPath;CopyFile (String source, String target) {sourcePath = source;targetPath = target;}public void copy() throws IOException {FileInputStream fis = new FileInputStream(this.sourcePath);// 構造器第二個參數append傳遞true表示開啟追加寫模式FileOutputStream fos = new FileOutputStream(this.targetPath, true);byte [] bytes = new byte[1024];int readResult = 0;while(readResult >= 0) {// read方法傳遞一個長度為n的字節數組,每次讀取n位, 返回實際讀取的位數,讀到// 文件結束符返回 -1readResult = fis.read(bytes);if(readResult > 0) {// write方法可以傳遞一個偏移量和長度,表示寫比特數組的0位開始,// 長度為readResult的數據fos.write(bytes, 0, readResult);}}// 記得要關閉流對象fis.close();fos.close();}public static void main(String[] args) throws IOException {CopyFile copyFile = new CopyFile("E:\\桌面文件\\媒體\\生而為人.m4a","E:\\桌面文件\\生而為人.m4a");copyFile.copy();}}
package Note.iosystem;import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;public class CopyFileByChar {private String sourcePath, targetPath;CopyFileByChar (String source, String target) {sourcePath = source;targetPath = target;}public void copy() throws IOException {FileReader fr = new FileReader(this.sourcePath);FileWriter fw = new FileWriter(this.targetPath, true);int readResult = 0;char [] chars = new char[1024];while(readResult >= 0) {readResult = fr.read(chars);if(readResult > 0){fw.write(chars, 0, readResult);}}fr.close();fw.close();}public static void main(String[] args) throws IOException {CopyFileByChar copyFileByChar = new CopyFileByChar("./src/Note/iosystem/DirList.java","./src/Note/iosystem/DirListCopyByChar.txt");copyFileByChar.copy();}
}
緩沖流
BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream
package Note.iosystem;import java.io.*;public class BufferDemo {private String from, to;public BufferDemo(String from, String to) {this.from = from;this.to = to;}public void copy() throws IOException {BufferedReader bfr = new BufferedReader(new FileReader(this.from));
// char [] chars = new char[1024];
// bfr.read(chars);BufferedWriter bfw = new BufferedWriter(new FileWriter(this.to));String line = bfr.readLine();while (line != null) {bfw.write(line);bfw.newLine();line = bfr.readLine();}bfr.close();bfw.close();}public static void main(String[] args) throws IOException {BufferDemo bd = new BufferDemo("./src/Note/iosystem/DirList.java","./src/Note/iosystem/DirListCopyByChar.txt");bd.copy();}
}
轉化流
InputStreamReader, OutputStreamWriter 允許設置編碼方式,將字節流轉換為字符流
package Note.iosystem;import java.io.*;public class ConversionStream {public static void main(String[] args) throws IOException {String filePath = "./src/Note/iosystem/DirList.java";String filePathGBK = "./src/Note/iosystem/DirListGBK.java";InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath));OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePathGBK), "GBK");char [] chars = new char[1024];int result = isr.read(chars);while (result >= 0) {osw.write(chars);result = isr.read(chars);}isr.close();osw.close();}
}
序列化流
-
想要將一個對象序列化,必須實現Serializable接口(他是一個標記接口)
-
反序列化時,對象對應的class文件必須存在,否則拋出ClassNotFoundException
-
類實現Serializable接口后,Java文件編譯成class文件時,會添加一個作為唯一標識的serialVersionUID,這個序列號在序列化時會寫入序列化文件,用來在反序列化時判斷class文件是否一致, 如果在序列化之后修改了類的定義但沒有重新序列化對象,在反序列化時就會拋出InvalidClassException異常,因為修改類定義會重新生產序列號。
-
可以給定一個確定的序列化來解決這個問題,必須是static final long 的:
private final static long serialVersionUID = 1L;
-
-
用static修飾的屬性值不會被序列化(靜態屬性優先加載),除此之外如果不想序列化某個屬性的值,可以使用transient修飾
package Note.iosystem.serialization;import java.io.Serializable;public class Person implements Serializable {private String name;private transient int age;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}public Person(String n, int a) {this.age = a;this.name = n;}
}
package Note.iosystem.serialization;import java.io.*;public class ObjectOSDemo {public static void main(String[] args) throws IOException, ClassNotFoundException {String outputPath = "./src/Note/iosystem/objectOutput";Person person = new Person("zhangSan", 17);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(outputPath));oos.writeObject(person);oos.close();ObjectInputStream ois = new ObjectInputStream(new FileInputStream(outputPath));Person p = (Person) ois.readObject();System.out.println(p);ois.close();}
}
… more …