1. 程式人生 > >Java(8)I/O

Java(8)I/O

[TOC] ## 一、File類 ### 1、File類概述 - **java.io.File類**:一個java.io.File類的物件,表示檔案和檔案目錄路徑(就是資料夾) - File 能新建、刪除、重新命名檔案和目錄,但 File 不能訪問檔案內容本身。如果需要訪問檔案內容本身,則需要使用輸入/輸出流。 - 想要在Java程式中表示一個真實存在的檔案或目錄,那麼必須有一個File對 象,但是Java程式中的一個File物件,可能沒有一個真實存在的檔案或目錄。 ![](https://img2020.cnblogs.com/blog/2031463/202011/2031463-20201126005707349-645424871.png) - **經典應用場景:**File物件可以作為引數傳遞給流的構造器。 ### 2、File類例項化 - **構造器** | 構造器 | 描述 | | :-------------------------------: | :-----------------------------: | | File(String pathname) | 由**路徑名稱**來建立 | | File(String parent, String child) | 由**上層目錄路徑+檔名**來建立 | | File(File parent, String child) | 由**上層檔名+檔名**來建立 | | File(URI uri) | 由**uri**來建立 | - **路徑** - 絕對路徑:是一個固定的路徑,從碟符開始 - 相對路徑:是相對於某個位置開始。在IDEA中是相對於當前的module - **路徑分隔符** - windows和DOS系統預設使用“\”來表示 - UNIX和URL使用“/”來表示 - Java程式支援跨平臺執行,因此路徑分隔符要慎用。為了解決這個隱患,File類提供了一個常量:`public static final String separator`,根據作業系統,動態的提供分隔符。 - 舉例 ```java File file1 = new File("d:\\atguigu\\info.txt"); File file2 = new File("d:" + File.separator + "atguigu" + File.separator + "info.txt"); File file3 = new File("d:/atguigu"); ``` ### 3、File類常用方法 - **獲取 | 方法 | 描述 | | :------------------------ | :----------------------------------------------- | | getAbsolutePath() | 獲取絕對路徑 | | getPath() | 獲取路徑 | | getName() | 獲取名 | | getParent() | 獲取上層檔案目錄路徑。若無,返回null | | length() | 獲取檔案長度(即:位元組數)。不能獲取目錄的長度。 | | lastModified() | 獲取最後一次的修改時間,毫秒值 | | 下面兩個是針對目錄的 | | | public String[] list() | 獲取指定目錄下的所有檔案或者檔案目錄的名稱陣列 | | public File[] listFiles() | 獲取指定目錄下的所有檔案或者檔案目錄的File陣列 | - **重新命名** `public boolean renameTo(File dest)`:把檔案重新命名為指定的檔案路徑。(實際上就是把file1的內容複製到file2,並把file1刪除) 對於 `file1.renameTo(file2)`要求:file1存在,file2不存在 - **判斷** | 方法 | 描述 | | ------------- | ------------------ | | isDirectory() | 判斷是否是檔案目錄 | | isFile() | 判斷是否是檔案 | | exists() | 判斷是否存在 | | canRead() | 判斷是否可讀 | | canWrite() | 判斷是否可寫 | | isHidden() | 判斷是否隱藏 | - **建立和刪除** | 方法 | 描述 | 注意事項 | | ------------------------------ | ------------------ | ------------------------------------------------------------ | | public boolean createNewFile() | 建立檔案 | 若檔案存在,則不建立,返回false | | public boolean mkdir() | 建立檔案目錄 | 如果此檔案目錄存在,就不建立;
如果此檔案目錄的上層目錄不存在,也不建立 | | public boolean mkdirs() | 建立檔案目錄 | 如果上層檔案目錄不存在,一併建立 | | public boolean delete() | 刪除檔案或者資料夾 | Java中的刪除不走回收站
要刪除的檔案目錄內不能包含檔案或檔案目錄 | **如果你建立檔案或者 檔案 目錄沒有寫碟符路徑 , 那麼 ,預設在專案路徑下。** ## 二、IO流的原理 ### 1、IO流的原理 - **I/O**是input/output的縮寫,IO技術用於**裝置之間的資料傳輸**。(如。**讀/寫檔案、網路通訊**) - Java程式中,資料的輸入/輸出操作以**“流(stream)”** 的方式進行。 - **java.io包下提供了各種“流”類和介面**,用以獲取不同種類的資料,並通過標準的方法輸入或輸出資料。 ### 2、input和output的理解 - 首先對於入和出,我們是站在程式的角度來說的,**想象自己身處程式內部。** - input:磁碟、光碟等儲存裝置的資料----->
程式、記憶體 - output:程式、記憶體中的資料----->磁碟、光碟等儲存裝置 ## 三、IO流的分類 ### 1、分類 - √√√按**操作的資料單位**不同分為:**位元組流(8bit)、字元流(16bit)**。位元組流適合操作圖片、視訊等檔案,字元流適合操作文字檔案。 - 按資料**流的流向**不同分為:**輸入流、輸出流。** - 按**流的角色**不同分為:**節點流、處理流。 - **節點流:**直接從資料來源或目的地讀寫資料。也叫**檔案流** ![](https://img2020.cnblogs.com/blog/2031463/202011/2031463-20201126005745176-1812936854.png) - **處理流:**不直接連線到資料來源或目的地,而是“連線”在已存 在的流(節點流或處理流)之上,通過對資料的處理為程式提 供更為強大的讀寫功能 ![](https://img2020.cnblogs.com/blog/2031463/202011/2031463-20201126005756209-569026929.png) ### 2、圖示 ![](https://img2020.cnblogs.com/blog/2031463/202011/2031463-20201126005814987-631981059.png) ### 3、四個抽象基類 | 抽象基類 | 位元組流 | 字元流 | | :------: | :----------: | :----: | | 輸入流 | InputStream | Reader | | 輸出流 | OutputStream | Writer | ### 4、IO流體系 ![](https://img2020.cnblogs.com/blog/2031463/202011/2031463-20201126005835858-212857294.png) ## 四、FileReader和FileWriter ### 1、IDEA中單元測試方法和main()下相對路徑對比 - 單元測試方法下的相對路徑是:相較於當前module而言 - main()下的相對路徑:相較於當前工程而言 ### 2、使用FileReader讀入資料 - 最初的程式碼實現 ```java public void test1() throws IOException { //1.例項化File類,指明要操作的物件.這一步的目的是建立硬碟中的檔案和Java中類的對應關係. File file = new File("hello1.txt"); //2.提供具體的流.引數的作用就是幫助我們並連線上檔案這個"大水庫" FileReader fileReader = new FileReader(file); //3.用流讀取到記憶體 //read():返回讀入的字元,是int需要轉換為char.到了檔案結尾返回-1 int read = fileReader.read(); while (read != -1) { System.out.print((char) read); read = fileReader.read(); } //4.關閉流 fileReader.close(); } //整個過程結合圖示去理解很合理 ``` - 改進後的程式碼實現 ```java /* 優化: 1.第三部可以在語法上的優化,但是效率其實是一樣的 2.為了保證關閉操作一定執行,使用try-catch-finally 3.讀入的檔案一定要存在,否則會出現:FileNotFoundException */ public void test2() { FileReader fileReader = null; try { File file = new File("hello1.txt"); fileReader = new FileReader(file); //改進1 int read; while ((read = fileReader.read()) != -1){ System.out.print((char) read); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fileReader != null) fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } ``` - **使用緩衝流改進**(**這個是用的最多的**★★★★★) ````java //使用陣列 char[] charBuffer = new char[5]; int len;//記錄每次讀入到charBuffer陣列中的字元個數 while ((len = fileReader.read(charBuffer)) != -1){ for (int i = 0; i < len; i++) {//這裡要用len(讀取的字元數)二不是陣列的長度 System.out.print(charBuffer[i]); } } //當然for迴圈也可以換位String的構造器來把字串陣列轉換為String String string = new String(charBuffer, 0, len); System.out.print(string); ```` ### 3、使用FileWriter寫出資料 - **程式碼實現** ````java File file = new File("hello2.txt"); FileWriter fw = new FileWriter(file); fw.write("i have a dream!"); fw.close(); //最後用try-catch處理一下異常,上面的步驟更清晰一些 ```` - 說明 - 輸出時,File可以不存在,不會報異常。 - File對應的硬碟的檔案如果不存在,自動建立 - File對應的硬碟的檔案如果存在 - 如果流使用的構造器是FileWriter(file, false)/FileWriter(file),對原有的檔案進行覆蓋 - 如果流使用的構造器是FileWriter(file, true),對原有的檔案進行追加 ### 4、使用FileReader和FileWriter複製文字檔案 - 程式碼實現 ````java public void test5() throws IOException { File srcFile = new File("hello2.txt"); File destFile = new File("hello3.txt"); FileReader fr = new FileReader(srcFile); FileWriter fw = new FileWriter(destFile); char[] charBuffer = new char[5]; int len; while ((len = fr.read(charBuffer)) != -1) { fw.write(charBuffer, 0, len);//和用String來取是類似的★★★★★ } fw.close(); fr.close(); } //最後用try-catch處理一下異常,上面的步驟更清晰一些 ```` ### 5、使用FileReader和FileWriter不能處理圖片的複製的測試 - 當把hello.txt文字檔案改為圖片檔案時,發現程式碼是可以正常執行,但是複製結果並不對,新圖片打不開。 - 這是因為,圖片是用位元組來儲存的。用字元流來處理顯然不行。 ## 五、FileInputStream和FileOutputStream ### 1、用FileInputStream和FileOutputStream處理文字檔案會怎樣? - **結論** - **輸出到控制檯時**:英文不亂碼,中文可能會亂碼 - 單純複製,而不在記憶體層面檢視:不會亂碼,是可以的。 - **解釋** - **對於英文**,utf-8和gbk都是用一個位元組(4bit位)來存一個字母,因此每個字母都是完完整整的存入byte陣列,從而能完整的複製過去。 - **對於中文**,utf-8中用的是三個位元組來存一個漢字,那麼位元組陣列中的資料在輸出時,不確定在哪裡截斷,就會出現一部分字的亂碼。 ### 2、確定使用字元流還是位元組流 - 對於文字檔案(.txt, .java, .cpp),使用字元流 - 對於非文字檔案(.jpg, .mp3, .mp4, .avi, .doc, .ppt...),使用位元組流 ### 3、用FileInputStream和FileOutputStream複製圖片 - 同“使用FileReader和FileWriter複製文字檔案”,只要 - 使用FileInputStream和FileOutputStream - 把陣列改為byte陣列 ## 六、緩衝流 ### 1、緩衝流有哪些 BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter ### 2、作用 - 提高讀寫速度 ### 3、原因 - 在使用這些流類時,會**建立一個內部緩衝區陣列,**預設使用8192個位元組(8Kb)的緩衝區。 - 當讀取資料時,資料按塊**讀入緩衝區**,其後的讀操作則**直接訪問緩衝區**。 - 當使用BufferedInputStream讀取位元組檔案時,BufferedInputStream會一次性從檔案中讀取8192個(8Kb),存在緩衝區中,直到緩衝區裝滿了,才重新從檔案中讀取下一個8192個位元組陣列。 - 向流中寫入位元組時,不會直接寫到檔案,先寫到緩衝區中直到緩衝區寫滿, BufferedOutputStream才會把緩衝區中的資料一次性寫到檔案裡。 - 使用**方法 flush()**可以強制將緩衝區的內容全部寫入輸出流。 - 如果是帶緩衝區的流物件的close()方法,不但會關閉流,還會在關閉流之前刷 新緩衝區,關閉後不能再寫出。 - 填坑:自己寫程式碼的時候忘記關閉流操作,導致複製的圖片打不開的原因就是,沒有關閉流,緩衝區內還有一部分資料沒能複製過去。 ### 4、使用緩衝流複製圖片 ````java public void test() throws IOException { //1.建立File File srcFile = new File("img1.png"); File destFile = new File("img2.png"); //2.建立流 //2.1建立檔案流 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); //2.2建立位元組流 BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); //3.複製 byte[] bytes = new byte[10]; int len; while ((len = bis.read(bytes)) != -1){ bos.write(bytes,0,len); } //4.關閉流 bis.close(); bos.close(); } ```` - 關閉外層的流的同時,會自動關閉內層的流。所以只寫外層的關閉操作就可以。 ### 5、使用緩衝流複製文字檔案 ````java public void test1() throws IOException { //1.建立檔案和流 BufferedReader br = new BufferedReader(new FileReader(new File("hello1.txt"))); BufferedWriter bw = new BufferedWriter(new FileWriter(new File("hello4.txt"))); // //2.複製 // char[] chars = new char[10]; // int len; // while ((len = br.read(chars)) != -1) { // bw.write(chars, 0, len); // } // 複製:用String來實現★★★★★★★★★★★ String data;//但是是不帶換行的,可以用一以下兩種方法實現 while ((data = br.readLine()) != null) { // //方法一★★★★★★★★ // bw.write(data + "\n"); //方法二★★★★★★★★ bw.write(data); bw.newLine(); } //3.關閉 br.close(); bw.close(); } ```` ### 6、練習:統計文字每個字元出現次數 ## 七、轉換流 ### 1、什麼是轉換流 - 轉換流提供了在**位元組流和字元流之間的轉換** - 轉換流屬於**字元流** - Java API提供了兩個轉換流 - InputStreamReader:將InputStream轉換為Reader - 構造器一:`public InputStreamReader(InputStream in)`預設使用utf-8字符集 - 構造器二:`public InputSreamReader(InputStream in,String charsetName)`可以自己選擇字符集。 - OutputStreamWriter:將Writer轉換為OutputStream - 構造器和上面類似 - 位元組流中的資料都是字元時,轉成字元流操作更高效。 - 很多時候我們使用轉換流來處理檔案亂碼問題。實現編碼和解碼的功能。 ### 2、編碼與解碼 - 編碼:位元組、位元組陣列--->
字元陣列、字串 - 解碼:字元陣列、字串--->位元組、位元組陣列 ### 3、字符集 - **什麼是編碼表**:計算機只能識別二進位制資料,早期由來是電訊號。為了方便應用計算機,讓它可以識 別各個國家的文字。就將各個國家的文字用數字來表示,並一一對應,形成一張表。 這就是編碼表。 - **常見編碼表** | 按照地區輔助記憶 | 編碼表 | 描述 | | :--------------- | :----------------- | :----------------------------------------------------------- | | 美國 | ASCII | 用**一個位元組的7位**來表示所有英文和符號 | | 歐洲 | ISO8859-1 | 用**一個位元組的8位**表示所有歐洲語言的字母 | | 中國 | GB2312
GBK | **最多兩個位元組**編碼所有漢字
升級版,加入了更多的漢字 | | 國際通用 | Unicode
UTF-8 | Unicode編碼是對UTF-8/16的統稱
用**1-4個位元組**表示人類所有文字 | ### 4、轉換流的作用示意圖 ![](https://img2020.cnblogs.com/blog/2031463/202011/2031463-20201126005920627-2038164186.png) ### 5、練習題 - 綜合使用:將文字檔案從utf-8轉換為gbk編碼 - 程式碼實現 ````java @Test public void test2() throws Exception { //1.造檔案、造流 File file1 = new File("dbcp.txt"); File file2 = new File("dbcp_gbk.txt"); FileInputStream fis = new FileInputStream(file1); FileOutputStream fos = new FileOutputStream(file2); InputStreamReader isr = new InputStreamReader(fis,"utf-8"); OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk"); //2.讀寫過程 char[] cbuf = new char[20]; int len; while((len = isr.read(cbuf)) != -1){ osw.write(cbuf,0,len); } //3.關閉資源 isr.close(); osw.close(); } ```` ## 八、標準輸入輸出流(瞭解) ### 1、簡介 - 標準輸入流:System.in。預設輸入裝置是鍵盤。**型別是InputStream。** - 標準輸出流:System.out。預設輸出裝置是控制檯。**型別是PrintStream,是OutputStream的子類。** ### 2.練習 - 題目:從鍵盤輸入字串,要求將讀取到的整行字串轉成大寫輸出。然後繼續 進行輸入操作,直至當輸入“e”或者“exit”時,退出程式。 - 程式碼實現 ````java public class Exercise { public static void main(String[] args) {//idea不支援在單元測試中輸入內容,所以改用main()來測試 BufferedReader br = null; try { InputStreamReader isr = new InputStreamReader(System.in); br = new BufferedReader(isr); while (true) { System.out.println("請輸入字串: "); String data = br.readLine(); if ("e".equalsIgnoreCase(data)||"exit".equalsIgnoreCase(data)){ System.out.println("程式結束"); break; } String upperCase = data.toUpperCase(); System.out.println(upperCase); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) { br.close(); } } catch (IOException e) { e.printStackTrace(); } } } } ```` ## 九、列印流(瞭解) ### 1、列印流簡介 - 實現將**基本資料型別**的資料格式轉化為**字串**來**輸出** - 包含兩個:**PrintStream和PrintWriter** - 提供了一系列過載的print()和println()方法,用於多種資料型別的輸出 - System.out返回的是PrintStream的例項 ### 2、程式碼演示 - 把標準輸出流(控制檯輸出)改成檔案 ````java PrintStream ps = null; try { FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt")); // 建立列印輸出流,設定為自動重新整理模式(寫入換行符或位元組 '\n' 時都會重新整理輸出緩衝區) ps = new PrintStream(fos, true); if (ps != null) {// 把標準輸出流(控制檯輸出)改成檔案 System.setOut(ps); } for (int i = 0; i <= 255; i++) { // 輸出ASCII字元 System.out.print((char) i); if (i % 50 == 0) { // 每50個數據一行 System.out.println(); // 換行 } } } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (ps != null) { ps.close(); } } ```` ## 十、資料流(瞭解) ### 1、簡介 - **引入**:為了方便地操作Java語言的基本資料型別和String的資料,可以使用資料流 - 資料流有兩個類:(用於**讀取和寫出**基本資料型別、String類的資料,方便持久化) - DataInputStream 和 DataOutputStream - **DataInputStream中的方法** boolean readBoolean() char readChar() double readDouble() long readLong() String readUTF() byte readByte() float readFloat() short readShort() int readInt() void readFully(byte[] b) - **DataOutputStream中的方法** 將上述的方法的read改為相應的write即可 ### 2、練習 ````java 練習:將記憶體中的字串、基本資料型別的變數寫出到檔案中。 注意:處理異常的話,仍然應該使用try-catch-finally. */ @Test public void test3() throws IOException { //1. DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt")); //2. dos.writeUTF("劉建辰"); dos.flush();//重新整理操作,將記憶體中的資料寫入檔案 dos.writeInt(23); dos.flush(); dos.writeBoolean(true); dos.flush(); //3. dos.close(); } /* 將檔案中儲存的基本資料型別變數和字串讀取到記憶體中,儲存在變數中。 注意點:讀取不同型別的資料的順序要與當初寫入檔案時,儲存的資料的順序一致! */ @Test public void test4() throws IOException { //1. DataInputStream dis = new DataInputStream(new FileInputStream("data.txt")); //2. String name = dis.readUTF(); int age = dis.readInt(); boolean isMale = dis.readBoolean(); System.out.println("name = " + name); System.out.println("age = " + age); System.out.println("isMale = " + isMale); //3. dis.close(); } ```` ## 十一、物件流 ### 1、簡介 - 包含:兩個類ObjectInputStream和ObjectOutputStream - 是:用於儲存和讀取基本資料型別資料或物件的處理流 - 強大之處:可以把Java中的物件寫入到資料來源中,也能把物件從資料來源中還原回來。 ### 2、物件的序列化★★★★★ - **什麼是物件的序列化機制(面試題)** - 一方面,物件的序列化機制允許記憶體中的**Java物件轉換為平臺無關的二進位制流**。從而允許吧二進位制流**持久化到磁碟**,或,通過網路**傳給另一個網路節點**; - 另一方面,其他程式獲取了二進位制流,就可以恢復成原來的Java物件。 - **序列化的好處**:可將任何實現了Serializable接 使其在儲存和傳輸時可被還原。 ### 3、程式碼實現String類的物件的序列化和反序列化 ````java public class ObjectInputOutputStream { /* 程式碼實現String類的物件的序列化和反序列化 */ @Test//序列化 public void testObjectOutputStream(){ ObjectOutputStream oos = null; try { //1.造流和檔案 oos = new ObjectOutputStream(new FileOutputStream(new File("objectString.dat"))); //2.寫出 oos.writeObject(new String("我愛你中國")); } catch (IOException e) { e.printStackTrace(); } finally { //3.關閉流 try { if (oos != null) { oos.close(); } } catch (IOException e) { e.printStackTrace(); } } } @Test public void testObjectInputStream(){ ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream(new File("objectString.dat"))); Object readObject = ois.readObject(); System.out.println(readObject); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (ois != null) { ois.close(); } } catch (IOException e) { e.printStackTrace(); } } } } ```` ### 4、自定義類的序列化 - **要求** - 實現Serializable介面(這是一個標識介面,內部沒有方法) - 提供一個全域性常量`public static final long serialVersionUID = xxxxxxxxL;` - 如果類沒有顯示定義這個靜態常量,它的值是Java執行時環境根據類的內部細節自 動生成的。若類的例項變數做了修改,serialVersionUID 可能發生變化。故建議, 顯式宣告。 - 還要保證類的所以屬性也是可序列化的。 - 基本資料型別是可序列化的 - **注意**:ObjectOutputStream和ObjectInputStream不能序列化**static和transient修飾**的成員變數 - 因為static修飾的變數是類所有的 - 不想序列化的就可以用transient ### 5、面試題 - 談談你對java.io.Serializable介面的理解,我們知道它用於序列化, 是空方法介面,還有其它認識嗎? - 實現了Serializable介面的物件,可將它們轉換成一系列位元組,並可在以後 完全恢復回原來的樣子。這一過程亦可通過網路進行。這意味著序列化機 制能自動補償作業系統間的差異。換句話說,可以先在Windows機器上創 建一個物件,對其序列化,然後通過網路發給一臺Unix機器,然後在那裡 準確無誤地重新“裝配”。不必關心資料在不同機器上如何表示,也不必 關心位元組的順序或者其他任何細節。 - 由於大部分作為引數的類如String、Integer等都實現了 java.io.Serializable的介面,也可以利用多型的性質,作為引數使介面更 靈活。 ## 十二、RandomAccessFile ### 1、簡介 - RandomAccessFile,隨機存取檔案流,**直接繼承於java.lang.Object類**。 - **隨機:**RandomAccessFile 物件包含一個記錄指標,用以標示當前讀寫處的位置。 RandomAccessFile 類物件可以自由移動記錄指標 - long getFilePointer():獲取檔案記錄指標的當前位置 - **void seek(long pos):將檔案記錄指標定位到 pos 位置(這是他的靈魂所在)** - 應用場景:可以多執行緒斷點下載同一檔案再拼接起來;下載不完,下次接著下載。 - **存取**:實現了DataInput、DataOutput兩個介面**,所以這個類**既可以讀也可以寫**。 - 可以用**構造器裡的引數**決定是輸出流還是輸入流。 - public RandomAccessFile(File file, String **mode)** - public RandomAccessFile(String name, String **mode)** - mode引數指定了訪問模式 - r: 以只讀方式開啟 (常用) - rw:開啟以便讀取和寫入 (常用) - rwd:開啟以便讀取和寫入;同步檔案內容的更新 - rws:開啟以便讀取和寫入;同步檔案內容和元資料的更新 ### 2、用RandomAccessFile類實現文字檔案的複製 ````java @Test public void test1() throws IOException { //用引數mode標識,讓類代表輸入 RandomAccessFile r = new RandomAccessFile(new File("hello1.txt"), "r"); //用引數mode標識,讓類代表輸出 RandomAccessFile rw = new RandomAccessFile(new File("hello5.txt"), "rw"); byte[] bytes = new byte[1024]; int len; while ((len=r.read(bytes)) != -1){ rw.write(bytes,0,len); } r.close(); rw.close(); } ```` ### 3、用 RandomAccessFile作為輸出流時的特點 - 如果寫出到的檔案不存在,就建立 - 如果寫出到的檔案存在,會對原文**從頭開始進行覆蓋**,能覆蓋多少算多少。 ### 4、如何使用 RandomAccessFile對文字檔案實現插入效果 ````java /* 使用RandomAccessFile實現資料的插入效果 */ @Test public void test3() throws IOException { RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw"); raf1.seek(3);//將指標調到角標為3的位置 //儲存指標3後面的所有資料到StringBuilder中 StringBuilder builder = new StringBuilder((int) new File("hello.txt").length()); byte[] buffer = new byte[20]; int len; while((len = raf1.read(buffer)) != -1){ builder.append(new String(buffer,0,len)) ; } //調回指標,寫入“xyz” raf1.seek(3); raf1.write("xyz".getBytes()); //將StringBuilder中的資料寫入到檔案中 raf1.write(builder.toString().getBytes()); raf1.close(); } ```` ## 十三、第三方jar包的使用 ### 1、為什麼使用 - 第三方jar包提供了很多方便高效的API,方便我們開發中使用,實際開發中也是用這些jar包來提高工作效率,而不只是根據JDK提供的API,因為有些不夠簡練。 ### 2、IDEA中匯入第三方jar包 - 當前module下建立名為lib或libs的directory - 複製第三方jar包到lib目錄 - 右鍵jar包,選擇 add as library - 搞定 ### 3、用第三方jar包實現檔案複製 ````java public class JarTest { public static void main(String[] args) throws IOException { File srcFile = new File("s6_IO/hello1.txt"); File destFile = new File("s6_IO/hello6.txt"); FileUtils.copyFile(srcFile,destFile); }