Java中文件的操作與輸入輸出流舉例詳解
文件
1.狹義上的文件:
硬盤上保存的數(shù)據(jù),都是“文件”來組織的,本質(zhì)上都是二進制或是字符組織的數(shù)組,被打包成一個文件存在硬盤上。常見的文件有圖片,文本,可執(zhí)行文件,音頻,視頻…文件夾也是一種特殊的文件,也叫目錄通常所說的文件都是存儲在硬盤上面的,硬盤的特點:1硬盤容量大,內(nèi)存容量小。2.硬盤讀寫速度慢,內(nèi)存讀寫速度快。3.硬盤造價低,內(nèi)存成本比較高。4.硬盤上的數(shù)據(jù)斷電不丟失,內(nèi)存中的數(shù)據(jù)斷電丟失。
2..廣義上的文件:
操作系統(tǒng)的主要功能就是對計算機資源進行統(tǒng)一管理與分配。對于Linux來講,所有的計算設(shè)備(網(wǎng)卡、鍵盤、打印機…)都會被描述(抽象)成文件。當(dāng)一個進程啟動后去申請計算機資源時,系統(tǒng)會把他所有用到的資源以文件的形式分配給進程,并加入到對應(yīng)的文件描述符表中。
3.樹形結(jié)構(gòu)和目錄通過 tree /F
在命令行查看指定目錄的樹形結(jié)構(gòu)。
4.絕對路徑從根目錄開始一直到目標(biāo)程序的表示方式。
5.相對路徑從當(dāng)前目錄開始表示目標(biāo)程序路徑的方式。如果要通過相對路徑的方式訪問到目標(biāo)文件,那么就得先確認(rèn)自己當(dāng)前的工作目錄。對于ideal來說,起始工作目錄就是工程的根目錄。
??注意
平時使用的時候可以使用絕對,工作和項目中盡量使用相對路徑。
Java操作文件
操作系統(tǒng)的一個重要功能就是對文件的管理,每個操作系統(tǒng)都有自己的一套系統(tǒng)API調(diào)用,Java作為一個跨平臺的語言,JVM針對不同的操作系統(tǒng)做了一層封裝,我們只需要使用JDK提供的關(guān)于文件操作的API就可以完成不同系統(tǒng)上的文件操作。
File類
用來操作文件的類,位于java.io包下。I:input,O: output。輸入輸出以內(nèi)存為參照物的。輸入指的是從外部輸入到內(nèi)存,輸出指的是把內(nèi)存的數(shù)據(jù)輸出外部(磁盤)。
屬性
修飾符及類型 | 屬性 | 說明 |
---|---|---|
static String | pathSeparator | 依賴于系統(tǒng)的路徑分隔符,String 類型的表示 |
static char | pathSeparator | 依賴于系統(tǒng)的路徑分隔符,char 類型的表示 |
構(gòu)造方法
簽名 | 說明 |
---|---|
File(File parent, String child) | 根據(jù)父目錄 + 孩子文件路徑,創(chuàng)建一個新的 File 實例 |
File(String pathname) | 根據(jù)文件路徑創(chuàng)建一個新的 File 實例,路徑可以是絕對路徑或者相對路徑 |
File(String parent, String child) | 根據(jù)父目錄 + 孩子文件路徑,創(chuàng)建一個新的 File 實例,父目錄用路徑表示 |
public class Demo01_File { public static void main(String[] args) { //通過指定文件路徑來創(chuàng)建一個File對象 File file = new File("D:\\test\\hello.txt"); System.out.println(file); File file1 = new File("D:/test/hello.txt"); System.out.println(file1); //這只是java層面的一個對象,并不一定必須在系統(tǒng)中真實存在 File file2 = new File("D:/test/test.txt"); System.out.println(file2); } }
注意斜杠與反斜杠的區(qū)別,反斜杠需要轉(zhuǎn)義。
常用方法
修飾符及返回值類型 | 方法簽名 | 說明 |
---|---|---|
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() | 根據(jù) File 對象,自動創(chuàng)建一個空文件。成功創(chuàng)建后返回 true |
boolean | delete() | 根據(jù) File 對象,刪除該文件。成功刪除后返回 true |
void | deleteOnExit() | 根據(jù) File 對象,標(biāo)注文件將被刪除,刪除動作會到JVM 運行結(jié)束時才會進行 |
String[] | list() | 返回 File 對象代表的目錄下的所有文件名 |
File[] | listFiles() | 返回 File 對象代表的目錄下的所有文件,以 File 對象表示 |
boolean | mkdir() | 創(chuàng)建 File 對象代表的目錄 |
boolean | mkdirs() | 創(chuàng)建 File 對象代表的目錄,如果必要,會創(chuàng)建中間目錄 |
boolean | renameTo(File dest) | 進行文件改名,也可以視為我們平時的剪切、粘貼操作 |
boolean | canRead() | 判斷用戶是否對文件有可讀權(quán)限 |
boolean | canWrite() | 判斷用戶是否對文件有可寫權(quán)限 |
public class Demo02_FileUsae { public static void main(String[] args) throws IOException { //指定絕對路徑來創(chuàng)建一個File對象 File file = new File("D:/test/test.txt"); // 獲取父目錄 System.out.println(file.getParent()); // 獲取文件名 System.out.println(file.getName()); // 獲取路徑 System.out.println(file.getPath()); // 獲取絕對路徑 System.out.println(file.getAbsolutePath()); // 獲取一個標(biāo)準(zhǔn)路徑 System.out.println(file.getCanonicalPath()); // 是否存在 System.out.println(file.exists()); // 是不是一個目錄 System.out.println(file.isDirectory()); // 是不是一個文件 System.out.println(file.isFile()); // // // 創(chuàng)建文件 // boolean result1 = file.createNewFile(); // if (result1) { // System.out.println("創(chuàng)建成功"); // } else { // System.out.println("創(chuàng)建失敗"); // } // // // 刪除 // boolean result2 = file.delete(); // if (result2) { // System.out.println("刪除成功"); // } else { // System.out.println("刪除失敗"); // } // // 指定一個目錄的路徑 // File file = new File("d:/test"); // // 獲取目錄下的文件和子目錄 // String[] list = file.list(); // System.out.println(Arrays.toString(list)); // // // 獲取目錄下的文件對象數(shù)組 // File[] files = file.listFiles(); // System.out.println(Arrays.toString(files)); // // 指定要創(chuàng)建的目錄 // File file = new File("D:/test/java"); // // 創(chuàng)建單個目錄 // boolean result = file.mkdir(); // if (result) { // System.out.println("創(chuàng)建成功"); // } else { // System.out.println("創(chuàng)建失敗"); // } // // 指定要創(chuàng)建的目錄 // File file = new File("D:/test/java/a/b/c"); // // 創(chuàng)建單個目錄 // boolean result = file.mkdirs(); // if (result) { // System.out.println("創(chuàng)建成功"); // } else { // System.out.println("創(chuàng)建失敗"); // } // // 定義源文件 // File sourceFile = new File("D:/test/hello.txt"); // // 定義目標(biāo)文件 // File destFile = new File("D:/test/haha.txt"); // // 重命名 // boolean result = sourceFile.renameTo(destFile); // if (result) { // System.out.println("修改成功"); // } else { // System.out.println("修改失敗"); // } // // File file = new File("D:/test/haha.txt"); // // 是否可寫 // System.out.println(file.canWrite()); // // 是否可讀 // System.out.println(file.canRead()); // //指定相對路徑來創(chuàng)建一個File對象 // 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()); // // 獲取一個標(biāo)準(zhǔn)路徑 // System.out.println(file.getCanonicalPath()); // // 是否存在 // System.out.println(file.exists()); // // 是不是一個目錄 // System.out.println(file.isDirectory()); // // 是不是一個文件 // System.out.println(file.isFile()); } }
文件內(nèi)容的讀寫-數(shù)據(jù)流
字節(jié)流(處理二進制文件)
InputStream和FileInputStream
??InputStream中的方法
修飾符及返回值類型 | 方法 | 說明 |
---|---|---|
int | read() | 讀取一個字節(jié)的數(shù)據(jù),返回 -1 代表已經(jīng)完全讀完了 |
int | read(byte[] b) | 最多讀取 b.length 字節(jié)的數(shù)據(jù)到 b 中,返回實際讀到的數(shù)量;-1 代表以及讀完了 |
int | read(byte[] b,int off, int len) | 最多讀取 len - off 字節(jié)的數(shù)據(jù)到 b 中,放在從 off 開始,返回實際讀到的數(shù)量;-1 代表以及讀完了 |
void | close() | 關(guān)閉字節(jié)流 |
InputStream 只是一個抽象類,要使用還需要具體的實現(xiàn)類。我們現(xiàn)在只關(guān)心從文件中讀取,所以使用 FileInputStream類。
??FileInputStream類的構(gòu)造方法
方法 | 說明 |
---|---|
FileInputStream(File file) | 利用 File 構(gòu)造文件輸入流 |
FileInputStream(String name) | 利用文件路徑構(gòu)造文件輸入流 |
示例:讀取文件
public class Demo03_InputStream_Read01 { public static void main(String[] args) throws IOException { // 創(chuàng)建一個文件對象 File file = new File("d:/test/haha.txt"); // 創(chuàng)建一個輸入流 InputStream inputStream = new FileInputStream(file); // 讀取文件內(nèi)容 while (true) { int read = inputStream.read(); // 是否讀完 if (read == -1) { break; } System.out.println(read); } // 關(guān)閉 inputStream.close(); } }
示例:用一個數(shù)組用來保存讀取到的數(shù)據(jù),遍歷數(shù)組即可讀取到數(shù)據(jù)。
public class Demo04_InputStream_Read02 { public static void main(String[] args) throws IOException { // 創(chuàng)建一個文件對象 File file = new File("d:/test/haha.txt"); // 創(chuàng)建一個輸入流 InputStream inputStream = new FileInputStream(file); // 定義一個數(shù)組用來保存讀取到的數(shù)據(jù) byte[] bytes = new byte[1024]; // 讀取文件內(nèi)容 while (true) { // 讀到的數(shù)據(jù)會被填充到bytes數(shù)據(jù)中,返回讀取數(shù)據(jù)的長度 int len = inputStream.read(bytes); // 判斷是否讀完 if (len == -1) { break; } // 打印讀到的內(nèi)容 for (int i = 0; i < len; i++) { System.out.println(bytes[i]); } } // 關(guān)閉 inputStream.close(); } }
在這個示例中,傳入read()方法的是一個空數(shù)組,讀文件時,讀數(shù)組長度個字節(jié),并返回讀取到的字節(jié)數(shù)供調(diào)用方做判斷。
打開一個文件相當(dāng)于把文件放入文件描述符表中,本質(zhì)上是一個數(shù)組。用完一定要關(guān)閉,如果不關(guān)閉,文件描述符表就會被填滿,導(dǎo)致以后可能無法再打開文件。
OutputStream和FileOutputStream
OutputStream和FileOutputStream分別作為字節(jié)流中輸出流的抽象類和實現(xiàn)類。
??OutputStream的方法
修飾符及返回值類型 | 方法 | 說明 |
---|---|---|
viod | write(int b) | 將數(shù)據(jù)寫入指定的文件 |
viod | write(byte[] b) | 將 b 這個字符數(shù)組中的數(shù)據(jù)全部寫入 os 中 |
int | write(byte[] b, int off,int len) | 將 b 這個字符數(shù)組中從 off 開始的數(shù)據(jù)寫入 os 中,一共寫 len 個 |
viod | close() | 關(guān)閉字節(jié)流 |
viod | flush() | 重要:我們知道 I/O 的速度是很慢的,所以,大多的 OutputStream 為了減少設(shè)備操作的次數(shù),在寫數(shù)據(jù)的時候都會將數(shù)據(jù)先暫時寫入內(nèi)存的一個指定區(qū)域里,直到該區(qū)域滿了或者其他指定條件時才真正將數(shù)據(jù)寫入設(shè)備中,這個區(qū)域一般稱為緩沖區(qū)。但造成一個結(jié)果,就是我們寫的數(shù)據(jù),很可能會遺留一部分在緩沖區(qū)中。需要在最后或者合適的位置,調(diào)用 flush(刷新)操作,將數(shù)據(jù)刷到設(shè)備中。 |
public class Demo05_OutputStream { public static void main(String[] args) throws IOException { // 先創(chuàng)建一個File對象 File file = new File("d:/test/haha.txt"); // 根據(jù)File對象創(chuàng)建一個輸出流 FileOutputStream outputStream = new FileOutputStream(file); // 向文件中寫入內(nèi)容 outputStream.write(100); outputStream.write(101); outputStream.write(102); // 刷新緩沖區(qū) outputStream.flush(); // 關(guān)閉流 outputStream.close(); } }
調(diào)用write()方法,就表示通過輸出流把內(nèi)容寫到指定的文件中。
緩沖區(qū)本身是內(nèi)存中的一片區(qū)域,寫的文件內(nèi)容一般是先寫到緩沖區(qū)中,緩沖區(qū)的內(nèi)容什么時候?qū)懙轿募惺怯刹僮飨到y(tǒng)決定的。如果緩沖區(qū)的內(nèi)容還沒寫滿就要強制寫入文件時,可以使用flush()方法。
在完成寫操作之后,建議強制調(diào)用flush()方法刷新緩沖區(qū),確保文件內(nèi)容被立即寫入。
用輸出流的方式去寫文件內(nèi)容,會把之前的內(nèi)容全部覆蓋掉。
字符流(處理文本文件)
Reader和FileReader
Reader和FileReader分別是字符流中輸入流的抽象類和實現(xiàn)類。
public class Demo06_FileReader { public static void main(String[] args) throws IOException { // 創(chuàng)建一個File對象 File file = new File("d:/test/haha.txt"); // 根據(jù)File對象創(chuàng)建一個Reader(面向字符的輸入流) FileReader reader = new FileReader(file); // 循環(huán)讀取 while (true) { // 一次讀一個字符 int read = reader.read(); if (read == -1) { break; } // 打印 System.out.println((char) read); } // 關(guān)閉流 reader.close(); } }
read()方法每次只讀一個字符。
Writer和FileWriter
Writer和FileWriter分別是字符流中輸出流的抽象類和實現(xiàn)類。
public class Demo07_FileWriter { public static void main(String[] args) throws IOException { // 創(chuàng)建一個File對象 File file = new File("d:/test/haha.txt"); // 根據(jù)文件對象創(chuàng)建一個字符輸出流 FileWriter writer = new FileWriter(file); // 寫入內(nèi)容 writer.write("你好世界\n"); writer.write("hello world"); // 強制刷新緩沖區(qū) writer.flush(); // 關(guān)閉流 writer.close(); } }
write()方法每次寫入一個字符串,寫入時不會自動換行,需要換行時要手動添加換行符。
其他方法
Scanner(通過輸入流讀)
public class Demo08_Scanner { public static void main(String[] args) throws IOException { // 創(chuàng)建一個輸入流 FileInputStream inputStream = new FileInputStream("d:/test/hello.txt"); // 根據(jù)創(chuàng)建輸入流創(chuàng)建Scanner對象 Scanner scanner = new Scanner(inputStream, "UTF-8"); // 循環(huán)讀取內(nèi)容 while (scanner.hasNextLine()) { String next = scanner.nextLine(); System.out.println(next); } scanner.close(); inputStream.close(); } }
讀數(shù)據(jù)時,調(diào)用nextLine()方法讀取一行。
PrintWriter(通過輸出流寫)
public class Demo09_PrintWiter { public static void main(String[] args) throws FileNotFoundException { // 創(chuàng)建一個輸出流 FileOutputStream outputStream = new FileOutputStream("d:/test/hello.txt"); // 根據(jù)輸出流,創(chuàng)建一個PrintWriter PrintWriter printWriter = new PrintWriter(outputStream); // 寫入文件 printWriter.println("你好世界!?。?); printWriter.println("hello world."); printWriter.println("我是用PrintWriter寫入的內(nèi)容"); // 強制刷新緩沖區(qū) printWriter.flush(); // 關(guān)閉流 printWriter.close(); } }
寫入字符串時,調(diào)用 println()方法會自動換行。
練習(xí)
1.掃描指定目錄,并找到名稱中包含指定字符的所有普通文件(不包含目錄),并且后續(xù)詢問用戶是否要刪除該文件。
1.用戶輸入一個路徑;
2.檢查路徑是否有效;
3.用戶輸入目標(biāo)字符;
4.獲取路徑下的文件和目錄;
5.如果是目錄,遞歸;
6.如果是文件檢查文件名是否包含要用戶輸入的字符。
public class Ex01 { public static void main(String[] args) throws IOException { // 1. 接收用戶輸入的掃描路徑 System.out.println("請輸入要掃描的路徑(絕對路徑):"); Scanner scanner = new Scanner(System.in); String rootPath = scanner.next(); // 2. 判斷路徑是否有效 File root = new File(rootPath); // 2.1 路徑是否存在 if (!root.exists()) { System.out.println("路徑不存在"); return; } // 2.2 判斷File是不是一個目錄 if (!root.isDirectory()) { System.out.println("指定的路徑不是一個有效目錄"); return; } // 3. 接收關(guān)鍵字 System.out.println("請輸入關(guān)鍵字"); String key = scanner.next(); if (key == null || "".equals(key)) { System.out.println("關(guān)鍵字不能為為"); return; } // 4. 掃描目錄下的所有文件 scan(root, key); } private static void scan(File root, String key) throws IOException { // 1. 先獲取root下的所有文件,包括目錄 File[] files = root.listFiles(); // 遞歸的終止條件 if (files == null || files.length == 0) { return; } // 遍歷數(shù)組中的每個文件 for (int i = 0; i < files.length; i++) { // 取出每一個文件 File tempFile = files[i]; // 判斷是文件還是目錄 if (tempFile.isFile()) { // 如果是文件,判斷文件名中是否包含關(guān)鍵字 String fileName = tempFile.getName(); // 如果在文件名中找到關(guān)鍵字 if (fileName.contains(key)) { System.out.println("找到文件:" + tempFile.getCanonicalPath() + ", 是否刪除(Y/N)"); // 接收用戶的輸入,根據(jù)輸入判斷是否刪除 Scanner scanner = new Scanner(System.in); String order = scanner.next(); // 刪除操作 if (order.equalsIgnoreCase("y")) { tempFile.delete(); System.out.println(tempFile.getCanonicalPath() + " 刪除成功."); } } } else { // 如果是目錄則遞歸 scan(tempFile, key); } } } }
2.對普通文件進行復(fù)制
1.用戶輸入源文件的路徑;
2.檢查源文件是否存在,并且是一個文件;
3.用戶輸入目標(biāo)文件的路徑;
4.檢查目標(biāo)文件是否存在,并校驗?zāi)夸浕蛭募?br />5.完成復(fù)制。
public class Ex02 { public static void main(String[] args) { // 1 . 接收用戶輸入的源文件路徑 System.out.println("請輸入源文件路徑(絕對路徑):"); Scanner scanner = new Scanner(System.in); String sourcePath = scanner.next(); // 2. 判斷源文件路徑是否有效 File sourceFile = new File(sourcePath); // 2.1 文件是否存在 if (!sourceFile.exists()) { System.out.println("源文件不存在"); return; } // 2.2 判斷是不是一個文件 if (!sourceFile.isFile()) { System.out.println("源文件不是一個有效的文件"); return; } // 3. 接收用戶輸入的目標(biāo)文件路徑 System.out.println("請輸入目標(biāo)文件路徑(絕對路徑)"); String destPath = scanner.next(); File destFile = new File(destPath); // 3.1 判斷目標(biāo)文件是否存在 if (destFile.exists()) { System.out.println("目標(biāo)文件已存在"); return; } // 3.2 判斷目標(biāo)文件的父目錄是否存在 if (!destFile.getParentFile().exists()) { System.out.println("目標(biāo)文件的父目錄不存在"); return; } // 循環(huán)讀取源文件的內(nèi)容并寫到目標(biāo)文件中 try (FileInputStream inputStream = new FileInputStream(sourceFile); FileOutputStream outputStream = new FileOutputStream(destFile)) { // 定義一個byte數(shù)組用來做為輸出型參數(shù),保存每次讀到的文件內(nèi)容 byte [] bytes = new byte[1024]; // 循環(huán)讀取內(nèi)容 while (true) { int len = inputStream.read(bytes); if (len == -1) { break; } // 寫義目標(biāo)文件 outputStream.write(bytes); // 強制刷新緩沖區(qū) outputStream.flush(); } System.out.println("復(fù)制成功"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
由于InputStream和OutputStream實現(xiàn)了Closeable類,所以可以在try()中完成聲明,當(dāng)代碼退出try的代碼塊時,會自動調(diào)用close()方法。
繼續(xù)加油~
總結(jié)
到此這篇關(guān)于Java中文件的操作與輸入輸出流的文章就介紹到這了,更多相關(guān)Java文件操作與輸入輸出流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中Hashtable類與HashMap類的區(qū)別詳解
Hashtable的應(yīng)用非常廣泛,HashMap是新框架中用來代替Hashtable的類,也就是說建議使用HashMap,不要使用Hashtable??赡苣阌X得Hashtable很好用,為什么不用呢?這里簡單分析他們的區(qū)別。2016-01-01解決RestTemplate 請求url中包含百分號 會被轉(zhuǎn)義成25的問題
這篇文章主要介紹了解決RestTemplate 請求url中包含百分號 會被轉(zhuǎn)義成25的問題,具有很好的參考價值,希望對大家有所幫助。2021-10-10springcloud gateway設(shè)置context-path的操作
這篇文章主要介紹了springcloud gateway設(shè)置context-path的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07Java中的FileWriter用法詳解與實戰(zhàn)記錄
這篇文章主要給大家介紹了關(guān)于Java中FileWriter用法的相關(guān)資料,包括寫入字符數(shù)據(jù)到文件、字符數(shù)組和部分字符寫入、配合BufferedWriter使用等方法,同時也解釋了其與OutputStreamWriter,BufferedWriter的異同特性,適合簡單的文件寫入操作,需要的朋友可以參考下2024-10-10