目錄
一、三種路徑的分類:
1、絕對路徑:
2、相對路徑:
3、基準目錄:
二、文件的種類:
三、利用JAVA操作文件:
1、File類的構造方法:
2、File 類方法的使用:
使用例子:
四、利用JAVA操作文件內容:
1、字節流:
讀取操作:
實例化對象:
?FileInputStream 核心方法:
輸出操作:
實例化對象?
?FileOutputStream 核心方法:
2、字符流:
讀取操作:
實例化對象:
?FileReader 核心方法:
輸出操作:
實例化對象:
?FileWriter 核心方法:
五、使用文件操作的案例:
1、根據用戶輸入的目錄和文件名,來進行文件的查找和刪除
2、基根據用戶輸入的源文件路徑,復制源文件到指定目錄
一、三種路徑的分類:
1、絕對路徑:
?絕對路徑是從文件系統的根目錄開始,完整地描述文件或目錄位置的路徑。
例如,在windows系統中,有個具體文件是 report.txt :
c:\User\user\docs\report.txt
2、相對路徑:
?相對路徑不包含完整的路徑信息,而是根據當前工作目錄來確定目標文件或目錄的位置。
(? .? )? :表示當前目錄。例如,.\example.txt 表示當前目錄下的example.txt 文件。
(? ..? ) :表示上級目錄。例如,..\Documents\example.txt 表示當前目錄的上級目錄下的Documents文件夾的 example.txt 文件。
假如當前目錄是home,..\..\表示的是當前home目錄的上上級目錄。
例子,假設當前的工作目錄是 john,目標文件是c:\home\john\Documents\example.txt 。
絕對路徑:c:\home\john\Documents\example.txt 。
相對路徑:.\Documents\example.txt 。
在實際的開發中,絕對路徑和相對路徑用到的會更多。(尤其是相對路徑,用的會更多)。
3、基準目錄:
基準路徑也就是當前工作目錄。
基準路徑 + 相對路徑 = 絕對路徑。
????????基準路徑是指當前程序或者操作所基于的目錄。在進行文件操作時,相對路徑的計算就以這個基準路徑為起點。例如,若基準路徑是c:\User\john,相對路徑Documents\example.txt (省略了前面的??.\? )就表示的絕對路徑是 c:\User\john\Documents\example.txt 。
二、文件的種類:
文件分為兩大類:文本文件?和?二進制文件?。
判斷當前文件是文本文件還是二進制文件,初步手段是把文件拖入記事本里,如果是亂碼就是二進制文件。反之是文本文件。(此方法有局限性)。
特性 | 文本文件 | 二進制文件 |
底層存儲 | 由可讀字符組成,使用字符編碼(如 ASCII、UTF-8) | 由任意二進制數據組成(0 和 1 的序列),無需遵循字符編碼規則。 |
人類可讀性 | 可直接用文本編輯器查看和編輯(如記事本)。 | 無法直接閱讀(顯示為亂碼),需專用程序解析。 |
文件示例 | .txt ,?.csv ,?.html ,?.py | .exe ,?.jpg ,?.mp3 ,?.docx |
三、利用JAVA操作文件:
在JAVA中,我們使用?File 類和進行文件的操作:
????????File類主要作用于文件或目錄,它不僅可以用于創建文件和目錄,還能進行一些與文件和目錄相關的操作,比如獲取文件或目錄的屬性、刪除文件或目錄等。
1、File類的構造方法:
注意,由于 .\ 會發生轉移字符的情況,所以使用? ./? 也可以(windows支持)。
有兩種方法構造 File 類實例比較常用:
第一種(? ? ?File(String pathname)? ?):
????????通過指定的路徑名字符串創建一個 File 實例。這個路徑名可以是絕對路徑,也可以是相對路徑。
// 使用絕對路徑創建 File 對象File absoluteFile = new File("C:/Users/example.txt");// 使用相對路徑創建 File 對象File relativeFile = new File("./test.txt");
?absoluteFile?
依據絕對路徑構建,而?relativeFile
?則是基于相對路徑構建,相對路徑是相對于當前工作目錄而言的。
第二種(? ?File(String parent , String child )? ?):
????????根據父路徑名字符串和子路徑名字符串創建一個 File?實例。系統會將父路徑和子路徑拼接起來,形成完整的路徑。
String parent = "C:/Users";String child = "./example.txt";File file = new File(parent, child);
? ? ? ? parent 代表父路徑,child 代表子路徑,二者組合后生成完整路徑 c:/Users/example.txt 。
2、File 類方法的使用:
修飾符及返回值類型 | ?法簽名 | 說明 |
String | getParent() | 返回 File 對象的父?錄?件路徑 |
String | getName() | 返回 FIle 對象的純?件名稱 |
String | getPath() | 返回 File 對象的?件路徑 |
String | getAbsolutePath() | 返回 File 對象的絕對路徑 |
String | getCanonicalPath() | 返回 File 對象的修飾過的絕對路徑 |
boolean | exists() | 判斷 File 對象描述的?件是否真實存在 |
boolean | isDirectory() | 判斷 File 對象代表的?件是否是?個?錄 |
boolean | isFile() | 判斷 File 對象代表的?件是否是?個普通?件 |
boolean | createNewFile() | 根據 File 對象,?動創建?個空?件。成功創建后返回 true |
boolean | delete() | 根據 File 對象,刪除該?件。成功刪除后返回 true |
void | deleteOnExit() | 根據 File 對象,標注?件將被刪 除,刪除動作會到 JVM 運?結束時才會進? |
String[ ] | list() | 返回 File 對象代表的?錄下的所有 ?件名 |
File[ ] | listFiles() | 返回 File 對象代表的?錄下的所有?件,以 File 對象表? |
boolean | mkdir() | 創建 File 對象代表的?錄 |
boolean | mkdirs() | 創建 File 對象代表的?錄,如果必 要,會創建中間?錄 |
boolean | renameTo(File dest) | 進??件改名,也可以視為我們平時的剪切、粘貼操作 |
boolean | canRead() | 判斷??是否對?件有可讀權限 |
boolean | canWrite() | 判斷??是否對?件有可寫權限 |
使用例子:
我的 java 工程目錄:
?例子1:
File file = new File("./test.txt");System.out.println(file.getParent());System.out.println(file.getName());System.out.println(file.getPath());System.out.println(file.getAbsolutePath());System.out.println(file.getCanonicalPath());System.out.println(file.exists());System.out.println(file.isDirectory());System.out.println(file.isFile());
代碼運行結果(結合上面表格方法介紹看):
?例子2:
File file = new File("./test.txt");// 創建文件,成功創建返回true,若存在返回falsefile.createNewFile();// 進程退出之后(代碼運行結束), 才觸發刪除.file.deleteOnExit();Scanner scanner = new Scanner(System.in);System.out.println("輸入任意內容, 退出程序");scanner.next(); // 阻塞
?代碼運行結果(結合上面表格方法介紹看):
再看我們當前的工作目錄:(test.txt文件已被刪除)
例子3:
File file = new File("./");System.out.println(Arrays.toString(file.list()));System.out.println(Arrays.toString(file.listFiles()));
?代碼運行結果(結合上面表格方法介紹看):
例子4:
File file = new File("./test/aaa/bbb");// 創建一級目錄System.out.println(file.mkdir()); // false
? ? ./test/aaa/bbb?
?是指定的路徑。其中?./
?代表當前目錄,整體意思是要在當前目錄下的?test
?目錄中的?aaa
?目錄里創建?bbb
?目錄。
????????如果當前目錄下已經有?test
?目錄,并且?test
?目錄下有?aaa
?目錄,而?aaa
?目錄中沒有?bbb
?目錄,那么?mkdir()
?方法會成功創建?bbb
?目錄,并且返回?true
。
? ? ? ? 要注意的是,如果當前目錄下沒有test 目錄,或者 test 目錄下沒有aaa目錄,mkdir()
?方法無法創建父目錄,也就不能創建?bbb
?目錄,此時會返回?false
。(因為我的工作目錄沒有當前的test目錄)。
例子5:
File file = new File("./test/aaa/bbb");// 創建多級目錄file.mkdirs();
? ? ? ? ?mkdirs()這個方法,它會檢查路徑中各級目錄是否存在,若不存在就會依次創建這些目錄。例如,如果?test
?目錄不存在,它會先創建?test
?目錄;接著檢查?aaa
?目錄,若不存在就創建?aaa
?目錄;最后檢查并創建?bbb
?目錄。
例子6:
我的工程目錄:
File file = new File("./test/test.txt");File file2 = new File("./hello.txt");file.renameTo(file2);
?
此時test目錄下的test.txt文件已經沒了。
這里實現了兩個操作。
????????一是把 當前工作目錄下的 test 目錄 里的test.txt文件名字改為hello.txt,二是把名字改成 hello.txt 的文件移動到當前工作目錄下。
? ? ? ? 但是如果當前目錄存在hello.txt文件,調用?file.renameTo(file2)
?方法進行重命名和移動操作時會失敗,renameTo()
?方法會返回?false
。
????????
四、利用JAVA操作文件內容:
???????在 Java 里,操作文件內容時,有字節流和字符流兩種不同的輸入輸出方式。
字節流:
????????以字節(Byte)作為處理單位。一個字節為 8 位(bit),可處理任意類型的文件,像圖片、音頻、視頻等二進制文件,也能處理文本文件。
字符流:
????????以字符(Character)作為處理單位。在 Java 中,一個字符通常是 16 位(2 字節),采用 Unicode 編碼,適合處理文本文件,能直接處理字符數據,避免了字節流處理文本時的編碼轉換問題。
1、字節流:
讀取操作:
????????使用 InputStream 類來讀取,但時,InputStream 是一個抽象類,它是所有字節輸入流類的超類(超類是一種位于繼承層次結構較高位置的類,其他類可以從它繼承屬性和方法),不能直接實例化,通常需要使用它的具體子類來完成實例化。
實例化對象:
我們使用?FileInputStream 這個類來創建實例對象:
第一種:(? ??FileInputStream( String name )? ??)
InputStream inputStream = new FileInputStream("./test.txt");
????????在上述代碼中,使用?FileInputStream("./test.txt")
?創建了一個輸入流對象,用于讀取當前目錄下的?test.txt
?文件。如果文件不存在,會拋出?FileNotFoundException
?異常。
第二種:(? ???FileInputStream( File file?)?? ? )
File file = new File("./test.txt");
InputStream inputStream = new FileInputStream(file);
????????此代碼先創建了一個?File
?對象,然后使用?FileInputStream(file)
?創建輸入流對象。用于讀取當前目錄下的?test.txt
?文件。如果文件不存在,會拋出?FileNotFoundException
?異常。
?FileInputStream 核心方法:
方法 | 說明 |
int read( ) | 此方法從輸入流一次讀取讀取一個字節的數據,并將其作為一個?0 ?到?255 ?之間的整數返回。若到達輸入流的末尾,返回?-1 。 |
int read(byte[ ] b) | 嘗試從輸入流中讀取最多?b.length ?個字節的數據,并將其存儲在字節數組?b ?中。返回實際讀取的字節數。若到達輸入流的末尾,返回?-1 。 |
int read(byte[ ] b, int off, int len) | 從輸入流中讀取最多?len ?個字節的數據,并將其存儲在字節數組?b ?中,從索引?off ?開始存儲。返回實際讀取的字節數。若到達輸入流的末尾,返回?-1 |
使用例子1:
InputStream inputStream = new FileInputStream("./test.txt");int data;while ((data = inputStream.read()) != -1) {System.out.print((char) data);}// 讀取完畢, 循環 break 之后, 需要關閉文件.inputStream.close();
? ? ? ? 上述代碼中,(data = inputStream.read()) 這個表達式的結果就是賦給 data 的值,通過?while
?循環不斷調用?read()
?方法讀取文件內容,直到返回?-1
?表示文件讀取完畢。每次讀取的字節數據被轉換為字符并輸出。
使用例子2:
InputStream inputStream = new FileInputStream("./test.txt");while (true) {byte[] bytes = new byte[1024];int n = inputStream.read(bytes);if (n == -1) {// 讀取完畢了.break;}// 處理讀取到的數據for (int i = 0; i < n; i++) {System.out.print((char)bytes[i]);}}// 讀取完畢, 循環 break 之后, 需要關閉文件.inputStream.close();
? ? ? ? 當文件剩余字節數大于字節數組長度,read方法就會嘗試讀取 bytes.length 個字節到 bytes 數組中,并返回 bytes.length 個字節個數給到 n 。
????????當文件剩余字節數小于或等于字節數組長度,返回當前的有效字節的個數,再下一次循環就返回-1。
使用例子3:
InputStream inputStream = new FileInputStream("./test.txt");byte[] buffer = new byte[1024];int offset = 0;int length = 512;int bytesRead;while(true) {bytesRead = inputStream.read(buffer, offset, length);if(bytesRead == -1) {//讀取完畢了.break;}// 處理讀取到的數據for (int i = offset; i < offset + bytesRead; i++) {System.out.print((char) buffer[i]);}//下一次獲取文件字節起始位置offset += bytesRead;}// 讀取完畢, 循環 break 之后, 需要關閉文件.inputStream.close();
? ? ? ? 此read方法從文件中最多讀取len個字節的數據,從索引 offset 處開始存儲,同理,與上述的例子2一樣,讀取到文件,末尾返回-1。
輸出操作:
??使用?OutputStream?類來輸出,但時,OutputStream 是一個抽象類,不能直接實例化,通常需要使用它的具體子類來完成實例化。
實例化對象?
? ? ? ?我們使用 FileOutputStream 這個類來創建實例對象。
第一種:(? ??FileOutputStream(Sting name)? ? )
OutputStream?fos = new FileOutputStream("./test.txt");
name 就是要打開的具體文件路徑和文件名稱。
第二種:(? ??FileOutputStream(Sting name , boolean append)? ? )
OutputStream fos = new FileOutputStream("./test.txt", true);
? ? ? ? name 就是要打開的具體文件路徑和文件名稱。
? ? ? ? append 如果為true,則將字節數據從文件末尾處開始寫入;如果為false,則會覆蓋原文件內容。
?FileOutputStream 核心方法:
方法 | 解釋 |
write ( int a) | 寫?要給字節的數據 |
write(byte[ ] b)? | 將字符數組 b 中的數據全部寫入文件中 |
write(byte[ ] c , int off, int len) | 將 c 這個字符數組中從 off 開始的 數據寫?文件 中,?共寫 len 個 |
flush() | 我們知道 I/O (可以理解為從磁盤讀取數據和把數據寫入磁盤)的速度是很慢的,所以,?多的 OutputStream 為了減少設備操作的次數,在寫數 據的時候都會將數據先暫時寫?內 存的?個指定區域?,直到該區域 滿了或者其他指定條件時才真正將 數據寫?設備中,這個區域?般稱 為緩沖區。但造成?個結果,就是 我們寫的數據,很可能會遺留?部 分在緩沖區中。需要在最后或者合適的位置,調? flush(刷新)操 作,將數據刷到設備中。 |
使用例子:
OutputStream fos = new FileOutputStream("./test.txt");int a = 'A';fos.write(a);byte[] arr = {'a',68,69};fos.write(arr);//刷新緩沖區fos.flush();
寫入后,對應文件的內容。
2、字符流:
讀取操作:
基于 Reader 這個抽象類來進行字符流讀取,不能直接實例化,通常需要使用它的具體子類來完成實例化。
實例化對象:
使用 FileReader 這個子類來進行實例化:
第一種:(? ?FileReader(String? name)? ?)
Reader reader = new FileReader("./test.txt")
name 為具體的文件路徑和文件名稱。
第二種:(? ?FileReader(File file)? ?)
File file = new File("./test.txt");
Reader reader = new FileReader(file);
????????指定的?File
?對象創建一個新的?FileReader
?對象。若指定的?File
?對象表示的文件不存在、是一個目錄而非普通文件,或者由于其他原因無法打開該文件,會拋出?FileNotFoundException
?異常。
?FileReader 核心方法:
方法 | 介紹 |
int read( ) | 讀取單個字符,返回一個 0 到 65535 之間的整數,表示讀取的字符。 如果已經到達流的末尾,則返回 -1。 |
int read(char[ ] arr ) | 將字符讀入數組,返回讀取的字符數。 如果已經到達流的末尾,則返回 -1。 |
int read(char[ ] arr , int off , int len) | 將字符讀入數組的一部分,數組從偏移量? 返回實際讀取的字符數。 如果已經到達流的末尾,則返回 -1。 |
使用例子1:
文件含有內容:
Reader reader = new FileReader("./test.txt");while (true) {int ch = reader.read();if (ch == -1) {break;}char c = (char) ch;System.out.println(c);}
運行結果:
使用例子2:
文件含有內容:
Reader reader = new FileReader("./test.txt");while (true) {char[] chars = new char[1024];int n = reader.read(chars);if (n == -1) {break;}for (int i = 0; i < n; i++) {System.out.println(chars[i]);}}
運行結果:
輸出操作:
使用?Writer 類來輸出,因為它是抽象類,所以不能直接實例化,通常要使用它的具體子類來完成實際的字符寫入操作。
實例化對象:
使用 FileWriter 這個子類來實例化對象。
第一種:(? ?FileWriter(String? name)? ?)
Writer writer = new FileWriter("./test.txt");
name 就是要打開的具體文件路徑和文件名稱。
第二種:(? ?FileWriter(File file ,boolean append)? ?)
Writer writer = new FileWriter("./test.txt", true);
? ? ? ? name 就是要打開的具體文件路徑和文件名稱。
? ? ? ? append 如果為true,則將字節數據從文件末尾處開始寫入;如果為false,則會覆蓋原文件內容。
?FileWriter 核心方法:
方法 | 解釋 |
write( ) | 寫入單個字符,或者字符串 |
write(char[ ] arr ) | 將字符數組中的所有字符寫入文件。 |
write(char[ ] arr ,int off , int len) | 將字符數組的 off 位置開始寫入,最多寫入 len 個 |
flush( ) | 刷新緩沖區 |
使用例子:
Writer writer = new FileWriter("./test.txt");writer.write("你好世界");char[] arr = {'z','k'};writer.write(arr);writer.flush();
代碼運行結果:
五、使用文件操作的案例:
1、根據用戶輸入的目錄和文件名,來進行文件的查找和刪除
public static void main(String[] args) {//用戶輸入要查詢的文件名Scanner scanner = new Scanner(System.in);System.out.println("溫馨提示,輸入的目錄要符合d:/ 或者 d:/User/...的格式");System.out.println("請輸入要查詢的目錄: ");String dir = scanner.nextLine();System.out.println("請輸入要查詢的文件名: ");String filename = scanner.nextLine();//判斷目錄是否存在File rootFile = new File(dir);if(!rootFile.isDirectory()) {System.out.println("目錄不存在!");return;}//進行搜索,遞歸遍歷目錄中所有的文件和子目錄scanDir(rootFile,filename);}private static void scanDir(File rootFile, String filename) {//列出 rootFile 中的內容File[] files = rootFile.listFiles();if(files == null) {//空目錄return;}//遍歷 files 數組,判斷每個元素的類型for (File file : files) {if(file.isDirectory()) {//是一個目錄,遞歸調用 scanDir 方法.scanDir(file,filename);}else if(file.isFile()) {//是一個文件,判斷文件名是否匹配。if(file.getName().contains(filename)) {tryDelete(file);}}}}private static void tryDelete(File file) {System.out.println("已找到改文件,文件路徑為:" + file.getAbsolutePath());System.out.println("是否刪除該文件(Y/N)");Scanner scanner = new Scanner(System.in);String choice = scanner.next();if(choice.equals("Y") || choice.equals("y")) {file.delete();System.out.println("刪除成功!");}}
進階版:
public class Demo25 {//記錄文件是否存在public static boolean count = true;public static void main(String[] args) {while(true) {// 每次查找前重置 count 變量count = true;//用戶輸入要查詢的文件名Scanner scanner = new Scanner(System.in);System.out.println("此程序用來進行文件的查找和刪除");System.out.println("溫馨提示,輸入的目錄要符合d:/ 或者 d:/User/...的格式");System.out.println("請輸入要查詢的目錄: ");String dir = scanner.next();scanner.nextLine();System.out.println("請輸入要查詢的文件名(文件名可以是部分名稱): ");String filename = scanner.next();scanner.nextLine();//判斷目錄是否存在File rootFile = new File(dir);if(!rootFile.isDirectory()) {System.out.println("目錄不存在!");System.out.println();continue;}//進行搜索,遞歸遍歷目錄中所有的文件和子目錄scanDir(rootFile,filename);if(count == true) {System.out.println("文件不存在,或者文件名輸入錯誤!");}System.out.println("輸入 1 繼續查找,輸入 0 退出程序");int a = 0;while(true) {if(scanner.hasNextInt()) {a = scanner.nextInt();if(a == 1) {break;}else if(a == 0) {return;}else {System.out.println("輸入的數字無效,請重新輸入: ");// 除去無效輸入的內容scanner.nextLine();}}else {System.out.println("輸入錯誤,請輸入數字: ");//除去無效輸入的內容scanner.nextLine();}}}}private static void scanDir(File rootFile, String filename) {//列出 rootFile 中的內容File[] files = rootFile.listFiles();if(files == null) {//空目錄return;}//遍歷 files 數組,判斷每個元素的類型for (File file : files) {if(file.isDirectory()) {//是一個目錄,遞歸調用 scanDir 方法.scanDir(file,filename);}else if(file.isFile()) {//是一個文件,判斷文件名是否匹配。if(file.getName().contains(filename)) {tryDelete(file);count = false;}}}}private static void tryDelete(File file) {System.out.println("已找到該文件,文件路徑為:" + file.getAbsolutePath());System.out.println("是否刪除該文件(Y/N)");Scanner scanner = new Scanner(System.in);String choice = scanner.next();if(choice.equals("Y") || choice.equals("y")) {file.delete();System.out.println("刪除成功!");}}
}
2、基根據用戶輸入的源文件路徑,復制源文件到指定目錄
public static void main(String[] args) {//輸入源文件路徑和目標目錄路徑Scanner scanner = new Scanner(System.in);System.out.println("請輸入想要復制的文件的路徑(要輸入文件后綴): ");String srcPath = scanner.next();System.out.println("請輸入要復制到的目標目錄(如果目標目錄和原文件目錄相同,文件名字必須不同): ");String destPath = scanner.next();//判斷源文件是否存在File srcFile = new File(srcPath);if(!srcFile.isFile()) {System.out.println("該文件不存在!");return;}// 因為destPath最后包含了文件名,而我們所需要的只是前面的目錄File destFile = new File(destPath);//得到用戶輸入的目標目錄的父目錄File parentFile = destFile.getParentFile();//判斷得到的目標目錄的父目錄計算機中是否存在if(!parentFile.isDirectory()) {System.out.println("目標父目錄不存在");return;}//進行拷貝copy(srcFile,destFile);}private static void copy(File srcFile, File destFile) {try(InputStream inputStream = new FileInputStream(srcFile);OutputStream outputStream = new FileOutputStream(destFile)) {while(true) {byte[] arr = new byte[1024];int len = inputStream.read(arr);if(len == -1) {break;}outputStream.write(arr,0,len);}}catch (IOException e){e.printStackTrace();}}