您好,登錄后才能下訂單哦!
這篇文章主要介紹“如何快速了解Java中的IO流”,在日常操作中,相信很多人在如何快速了解Java中的IO流問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何快速了解Java中的IO流”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
一. File類
1.簡單介紹
File類的一個對象既能代表一個特定的文件的名稱,又能代表一個目錄下的一組文件的名稱。
File 能新建、刪除、重命名文件和目錄,但 File 不能訪問文件內容本身。如果需要訪問文件內容本身,則需要使用輸入/輸出流。
想要在Java程序中表示一個真實存在的文件或目錄,那么必須有一個File對 象,但是Java程序中的一個File對象,可能沒有一個真實存在的文件或目錄。
后續File類的對象常會作為參數傳遞到流的構找器中,指明讀取或寫入的"終點"。
2.基本用法
在文件系統中,每個文件都存放在一個目錄下。絕對文件名( absolute file name) 是由文件名和它的完整路徑以及驅動器字母組成。相對文件名是相對于當前工作目錄的。例如,c:\book\Welcome.java 是文件Welcome.java 在 Windows 操作系統上的絕對文件名。Welcome.java 是一個相對文件名。
windows和DOS系統默認使用“\”來表示 UNIX和URL使用“/”來表示 Java程序支持跨平臺運行,因此路徑分隔符要慎用。為了解決這個隱患,File類提供了一個常量: public static final String separator。根據操作系統,動態的提供分隔符。 File file = new File("D:"+File.separator +"JavaSE"+File.separator +"JavaProject");
2.1 構造方法
public File(String pathname) 以pathname為路徑創建File對象,可以是絕對路徑或者相對路徑
public File(String parent,String child)以parent為父路徑,child為子路徑創建File對象。
public File(File parent,String child)根據一個父File對象和子文件路徑創建File對象
//構造器一 :public File(String pathname) File file1 = new File("hello.txt");//相對路徑 File file2 = new File("D:\\JavaSE\\JavaProject\\WorkSpace\\ioDemo\\hi.txt");//絕對路徑 System.out.println(file1); System.out.println(file2); //構造器二:public File(String parent,String child) File file3 = new File("D:\\JavaSE", "JavaProject"); System.out.println(file3); //構造器三:public File(File parent,String child) File file4 = new File(file3, "he.txt"); System.out.println(file4);
輸出結果:
2.2 常用方法
2.2.1 File類的獲取功能
public String getAbsolutePath():獲取絕對路徑
public String getPath() :獲取路徑
public String getName() :獲取名稱
public String getParent():獲取上層文件目錄路徑。若無,返回null,若文件對象中是相對路徑,則返回null;
public long length() :獲取文件長度(即:字節數)。不能獲取目錄的長度。
public long lastModified() :獲取最后一次的修改時間,毫秒值,若該文件不在硬盤中真實存在,返回0。
public String[] list() :獲取指定目錄下的所有文件或者文件目錄的名稱數組
public File[] listFiles() :獲取指定目錄下的所有文件或者文件目錄的File數組
@Test public void test4() { File file1 = new File("hello.txt");//不存在,只是一個對象 File file2 = new File("D:\\io\\hi.txt");//在硬盤存在 System.out.println(file1.getAbsolutePath()); System.out.println(file1.getPath()); System.out.println(file1.getName()); System.out.println(file1.getParent()); System.out.println(file1.length()); System.out.println(file1.lastModified()); System.out.println("*************************************"); System.out.println(file2.getAbsolutePath()); System.out.println(file2.getPath()); System.out.println(file2.getName()); System.out.println(file2.getParent()); System.out.println(file2.length()); System.out.println(file2.lastModified()); } 復制代碼
輸出結果:
2.2.2 File類的判斷功能
public boolean isDirectory():判斷是否是文件目錄
public boolean isFile() :判斷是否是文件
public boolean exists() :判斷是否存在
public boolean canRead() :判斷是否可讀
public boolean canWrite() :判斷是否可寫
public boolean isHidden() :判斷是否隱藏
@Test public void test5(){ File file1 = new File("hello.txt");//在硬盤中真實存在 File file2 = new File("hello1.txt");//不真實存中 System.out.println(file1.isDirectory()); System.out.println(file1.isFile()); System.out.println(file1.exists()); System.out.println(file1.canRead()); System.out.println(file1.canWrite()); System.out.println(file1.isHidden()); System.out.println("*****************************"); System.out.println(file2.isDirectory()); System.out.println(file2.isFile()); System.out.println(file2.exists()); System.out.println(file2.canRead()); System.out.println(file2.canWrite()); System.out.println(file2.isHidden()); System.out.println("*********************************"); File file3 = new File("d:\\io");//真實存在 File file4 = new File("d:\\io1");//不存在 System.out.println(file3.isDirectory()); System.out.println(file3.isFile()); System.out.println(file3.exists()); System.out.println(file3.canRead()); System.out.println(file3.canWrite()); System.out.println(file3.isHidden()); System.out.println("*****************************"); System.out.println(file4.isDirectory()); System.out.println(file4.isFile()); System.out.println(file4.exists()); System.out.println(file4.canRead()); System.out.println(file4.canWrite()); System.out.println(file4.isHidden()); } 復制代碼
輸出結果:
2.2.3 File類的其他功能
public boolean createNewFile() :創建文件。若文件存在,則不創建,返回false。指定文件的目錄要存在。 public boolean delete():刪除文件或者文件夾,刪除注意事項:Java中的刪除不走回收站。要想文件夾刪除成功,最后一個文件目錄下不能有子目錄或文件
@Test public void test6() throws IOException { File file1 = new File("hello.txt");//此時文件不存在 if (!file1.exists()){ //文件的創建 boolean newFile = file1.createNewFile(); System.out.println("文件創建成功"); }else{ boolean delete = file1.delete(); System.out.println("原文件刪除成功"); } } 復制代碼
public boolean mkdir() :創建文件目錄。如果此文件目錄存在,就不創建了。如果此文件目錄的上層目錄不存在,也不創建。
public boolean mkdirs() :創建文件目錄。如果上層文件目錄不存在,一并創建
@Test public void test7() { //文件目錄的創建 File file1 = new File("d:\\io\\io1\\io2");//此時只有io目錄存在 boolean mkdir = file1.mkdir(); if (mkdir) { System.out.println("創建成功1"); } File file2 = new File("d:\\io\\io1\\io2");//此時只有io目錄存在 boolean mkdirs = file2.mkdirs(); if (mkdirs) { System.out.println("創建成功2"); } } 復制代碼
輸出結果:
public boolean renameTo(File dest):把文件重命名為指定的文件路徑,比如:file1.renameTo(file2)為例: 要想保證返回true,需要file1在硬盤中是存在的,且file2不能在硬盤中存在。
@Test public void test9(){ File file1 = new File("hello.txt");//在硬盤中存在內容為"hello world!" File file2 = new File("D:\\io\\hi.txt");//hi.txt不存在 boolean renameTo = file1.renameTo(file2); System.out.println(renameTo); } 代碼
輸出結果:生成了原本不存在的hi.txt文件,內容為hello world! hello.txt位置發生移動。
idea中main()方法中File的默認相對路徑和Junit Test 方法中File的路徑不同
public class FileMainTest { public static void main(String[] args) { File file = new File("hello.txt"); System.out.println("main" + file.getAbsoluteFile());//輸出結果:mainD:\JavaSE\JavaProject\WorkSpace\hello.txt } @Test public void test1() { File file = new File("hello.txt"); System.out.println("test" + file.getAbsoluteFile());//輸出結果:testD:\JavaSE\JavaProject\WorkSpace\ioDemo\hello.txt } } 復制代碼
二. IO流
1. 簡單介紹
Java 提供了許多實現文件輸人 / 輸出的類。這些類可以分為文本 I/O 類(text I/O class)和二進制 I/O 類(binary I/O class)。
輸入對象(輸入流)讀取外部數據(磁盤、光盤等存儲設備的數據)到程序(內存)中,操作過程中,我們是以 程序(內存)的角度。
輸出對象(輸出流)將程序(內存)數據輸出到磁盤、光盤等存儲設備中。
1.1 流的分類
按操作數據單位不同分為:字節流(8 bit),字符流(16 bit)
按數據流的流向不同分為:輸入流,輸出流
按流的角色的不同分為:節點流,處理流
Java的IO流共涉及40多個類,實際上非常規則,都是從如下4個 抽象基類派生的。 由這四個類派生出來的子類名稱都是以其父類名作為子類名后綴。
2. 節點流(文件流)
定義文件路徑時,注意:可以用“/”或者“\”。
在寫入一個文件時,如果使用構造器FileOutputStream(file),則目錄下有同名文件將被覆蓋。
如果使用構造器FileOutputStream(file,true),則目錄下的同名文件不會被覆蓋,在文件內容末尾追加內容。
在讀取文件時,必須保證該文件已存在,否則報異常。
字節流操作字節,比如:.mp3,.avi,.rmvb,mp4,.jpg,.doc,.ppt
字符流操作字符,只能操作普通文本文件。最常見的文本文件:.txt,.java,.c,.cpp 等語言的源代碼。尤其注意.doc,excel,ppt這些不是文本文件。
2.1 FileReader/FileWriter(字符流)
2.1.1 FileReader常用方法
int read():讀取單個字符。作為整數讀取的字符,范圍在 0 到 65535 之間 (0x00-0xffff)(2個 字節的Unicode碼),如果已到達流的末尾,則返回 -1
int read(char[] cbuf):將字符讀入數組。如果已到達流的末尾,則返回 -1。否則返回本次讀取的字符數。
int read(char[] cbuf,int off,int len):將字符讀入數組的某一部分。存到數組cbuf中,從off處開始存儲,最多讀len個字符。如果已到達流的末尾,則返回 -1。否則返回本次讀取的字符數。
public void close() throws IOException:關閉此輸入流并釋放與該流關聯的所有系統資源。
2.1.2 基本用法
幾乎所有的I/O類中的方法都會拋出異常 ;java.io.IOException。因此,必須在方法中聲明會拋出:java.io.IOException 異常,或者將代碼放到 try-catch 塊中。
//將module下的hello.txt文件內容讀入程序中,并輸出到控制臺 @Test public void test1() throws IOException { FileReader fr = null; try { //1.File類的實例化 File file = new File("hello.txt"); //2.FileReader流的實例化 fr = new FileReader(file); //3.讀入的操作 使用read(char[] cbuf) char[] cbuf = new char[5]; int len; while ((len = fr.read(cbuf)) != -1) { //方法一 // for (int i = 0; i < len; i++) {//不能用cbuf.length // System.out.print(cbuf[i]); // } //方法二 String s = new String(cbuf, 0, len); System.out.print(s); } } catch (IOException e) { e.printStackTrace(); } finally { if (fr != null) { try { //4.資源的關閉 fr.close(); } catch (IOException e) { e.printStackTrace(); } } } } 復制代碼
輸出結果:
2.1.1 FileWriter常用方法
void write(int c):寫入單個字符。要寫入的字符包含在給定整數值的 16 個低位中,16 高位被忽略。 即寫入0 到 65535 之間的Unicode碼。
void write(char[] cbuf):寫入字符數組。
void write(char[] cbuf,int off,int len):寫入字符數組的某一部分。從off開始,寫入len個字符寫入字符串。
void write(String str,int off,int len):寫入字符串的某一部分。
void flush():刷新該流的緩沖,則立即將它們寫入預期目標。
public void close()throws IOException :關閉此輸出流并釋放與該流關聯的所有系統資源
2.1.2 基本用法
鴻蒙官方戰略合作共建——HarmonyOS技術社區
輸出操作,對應的File可以不存在的。并不會報異常
File對應的硬盤中的文件如果不存在,在輸出的過程中,會自動創建此文件。 File對應的硬盤中的文件如果存在: ① 如果流使用的構造器是:FileWriter(file,false) / FileWriter(file):對原有文件的覆蓋 ② 如果流使用的構造器是:FileWriter(file,true):不會對原有文件覆蓋,而是在原有文件基礎上追加內容
//從內存中寫出數據到硬盤的文件里 @Test public void test2() { FileWriter fw = null; try { //1.創建File類的對象,指明寫出的文件 File file = new File("hello1.txt"); //2.提供FileWrite的對象,用于數據的寫出 fw = new FileWriter(file); //3.寫出的操作 fw.write("I have a dream!\n"); fw.write("you need to have a dream!"); } catch (IOException e) { e.printStackTrace(); } finally { if (fw != null) { //4.關閉資源 try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } } 復制代碼
實現文本之間的復制
@Test public void test3() { FileReader fr = null; FileWriter fw = null; try { //1.創建File類的對象,指明讀入與寫出的文件 File srcFile = new File("hello.txt"); File destFile = new File("hello2.txt"); //2.創建輸入流與輸出流的對象 fr = new FileReader(srcFile); fw = new FileWriter(destFile); //3.數據的讀入與寫出的操作 char[] cbuf = new char[5]; int len; while ((len = fr.read(cbuf)) != -1) { fw.write(cbuf, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { //4.關閉流資源 try { if (fw != null) fw.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } } } 制代碼
2.2 FileInputStream/FileOutputStream(字節流)
2.2.1 FileInputStream常用方法
int read():從輸入流中讀取數據的下一個字節。返回 0 到 255 范圍內的 int 字節值。如果因為已經到達流末尾而沒有可用的字節,則返回值 -1。
int read(byte[] b):從此輸入流中將最多 b.length 個字節的數據讀入一個 byte 數組中。如果因為已經到達流末尾而沒有可用的字節,則返回值 -1。否則以整數形式返回實際讀取的字節數。
int read(byte[] b, int off,int len):將輸入流中最多 len 個數據字節讀入 byte 數組。嘗試讀取 len 個字節,但讀取的字節也可能小于該值。以整數形式返回實際讀取的字節數。如果因為流位于文件末尾而沒有可用的字節,則返回值 -1。
public void close() throws IOException:關閉此輸入流并釋放與該流關聯的所有系統資源。
2.2.2 FileOutputStream常用方法
void write(int b):將指定的字節寫入此輸出流。write 的常規協定是:向輸出流寫入一個字節。要寫入的字節是參數 b 的八個低位。b 的 24 個高位將被忽略。 即寫入0~255范圍的。
void write(byte[] b):將 b.length 個字節從指定的 byte 數組寫入此輸出流。write(b) 的常規協定是:應該與調用 write(b, 0, b.length) 的效果完全相同。
void write(byte[] b,int off,int len):將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此輸出流。
public void flush()throws IOException:刷新此輸出流并強制寫出所有緩沖的輸出字節,調用此方法指示應將這些字節立即寫入它們預期的目標。
public void close() throws IOException:關閉此輸出流并釋放與該流關聯的所有系統資源。
2.2.3 基本用法
@Test public void test1() { FileInputStream fis = null; FileOutputStream fos = null; try { //1.造文件對象 File srcFile = new File("photo1.jpg"); File destFile = new File("photo2.jpg"); //2.造流 fis = new FileInputStream(srcFile); fos = new FileOutputStream(destFile); //3.讀數據 byte[] buffer = new byte[5]; int len; while ((len = fis.read(buffer)) != -1) { fos.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { //4.關閉資源 try { if (fos != null) fos.close(); } catch (IOException e) { e.printStackTrace(); } try { if (fis != null) fis.close(); } catch (IOException e) { e.printStackTrace(); } } } 制代碼
復制成功
3.緩沖流
為了提高數據讀寫的速度,Java API提供了帶緩沖功能的流類,在使用這些流類時,會創建一個內部緩沖區數組,缺省使用8192個字節(8Kb)的緩沖區。
當讀取數據時,數據按塊讀入緩沖區,其后的讀操作則直接訪問緩沖區
當使用BufferedInputStream讀取字節文件時,BufferedInputStream會一次性從文件中讀取8192個(8Kb),存在緩沖區中,直到緩沖區裝滿了,才重新從文件中讀取下一個8192個字節數組。
向流中寫入字節時,不會直接寫到文件,先寫到緩沖區中直到緩沖區寫滿,BufferedOutputStream才會把緩沖區中的數據一次性寫到文件里。使用方法flush()可以強制將緩沖區的內容全部寫入輸出流
關閉流的順序和打開流的順序相反。只要關閉最外層流即可,關閉最外層流也會相應關閉內層節點流
flush()方法的使用:手動將buffer中內容寫入文件
如果是帶緩沖區的流對象的close()方法,不但會關閉流,還會在關閉流之前刷新緩沖區,關閉后不能再寫出
3.1 BufferedInputStream/BufferedOutputStream
@Test public void test1() { BufferedInputStream bis = null; BufferedOutputStream bos = null; try { //1.造文件對象 File srcFile = new File("D:\\QQmusic\\MV\\1988.mp4"); File descFile = new File("D:\\QQmusic\\MV\\copy1988.mp4"); //2.1造節點流 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(descFile); //2.2造緩沖流 bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); //3.數據讀入與寫出操作 byte[] buffer = new byte[1024]; int len; while ((len = bis.read(buffer)) != -1) { bos.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { //4.關閉資源 try { if (bos != null) bos.close(); } catch (IOException e) { e.printStackTrace(); } try { if (bis != null) bis.close(); } catch (IOException e) { e.printStackTrace(); } //說明:先關閉外層的流,再關閉內層的流 // 關閉外層流的同時,內層流也會自動的進行關閉。關于內層流的關閉,我們可以省略. // fos.close(); // fis.close(); } } 復制代碼
結果:成功復制
3.2 BufferedReader/BufferedWriter
@Test public void test2() throws IOException { BufferedReader br = null; BufferedWriter bw = null; try { //創建文件和相應的流 // BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt"))); br = new BufferedReader(new FileReader("hello.txt")); bw = new BufferedWriter(new FileWriter("hello3.txt")); //讀寫操作 //方式一 char[] cbuf = new char[1024]; int len; while ((len = br.read(cbuf)) != -1) { bw.write(cbuf, 0, len); } // //方式二 // String data; // while ((data = br.readLine())!= null){//一次讀取字符文本文件的一行字符 // bw.write(data);//data中不包含換行符, 一次寫入一行字符串 // bw.newLine(); // //bw.write(data + "\n"); // } } catch (IOException e) { e.printStackTrace(); } finally { try { if (bw != null) bw.close(); } catch (IOException e) { e.printStackTrace(); } try { if (br != null) br.close(); } catch (IOException e) { e.printStackTrace(); } } } 復制代碼
4.轉換流
4.1 InputStreamReader/OutputStreamWriter
轉換流提供了在字節流和字符流之間的轉換
Java API提供了兩個轉換流: InputStreamReader:將InputStream轉換為Reader OutputStreamWriter:將Writer轉換為OutputStream
字節流中的數據都是字符時,轉成字符流操作更高效。
很多時候我們使用轉換流來處理文件亂碼問題。實現編碼和解碼的功能。 編碼:字符串——>字節數組 解碼:字節數組——>字符串
/** * 綜合使用InputStreamReader和OutputStreamWriter */ @Test public void test1() { InputStreamReader isr = null;//默認IDE的字符集 OutputStreamWriter osw = null; try { //1.造文件對象 File file1 = new File("hello.txt"); File file2 = new File("hello_gbk.txt"); //2.造流 FileInputStream fis = new FileInputStream(file1); FileOutputStream fos = new FileOutputStream(file2); //InputStreamReader isr = new InputStreamReader(fis,"UTF-8"); isr = new InputStreamReader(fis); osw = new OutputStreamWriter(fos, "gbk"); //OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk"); //3.數據讀寫過程 char[] cbuf = new char[20]; int len; while ((len = isr.read(cbuf)) != -1) { osw.write(cbuf, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { //4.關閉資源 try { if (isr != null) isr.close(); } catch (IOException e) { e.printStackTrace(); } try { if (osw != null) osw.close(); } catch (IOException e) { e.printStackTrace(); } } } 復制代碼
5.對象流
5.2 對象的的序列化
ObjectlnputStream 類和 ObjectOutputStream 類除了可以實現基本數據類型與字符串的輸人和輸出之外,還可以實現對象的輸人和輸出。
序列化:用ObjectOutputStream類保存基本類型數據或對象的機制
反序列化:用ObjectInputStream類讀取基本類型數據或對象的機制
ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量
對象序列化機制允許把內存中的Java對象轉換成平臺無關的二進制流,從而允許把這種二進制流持久地保存在磁盤上,或通過網絡將這種二進制流傳輸到另一個網絡節點。//當其它程序獲取了這種二進制流,就可以恢復成原來的Java對象
序列化的好處在于可將任何實現了Serializable接口的對象轉化為字節數據,使其在保存和傳輸時可被還原
序列化是 RMI(Remote Method Invoke – 遠程方法調用)過程的參數和返回值都必須實現的機制,而 RMI 是 JavaEE 的基礎。因此序列化機制是JavaEE 平臺的基礎
如果需要讓某個對象支持序列化機制,則必須讓對象所屬的類及其屬性是可序列化的,為了讓某個類是可序列化的,該類必須實現如下兩個接口之一。否則,會拋出NotSerializableException異常 Serializable Externalizable
凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量: private static final long serialVersionUID; serialVersionUID用來表明類的不同版本間的兼容性。簡言之,其目的是以序列化對象進行版本控制,有關各版本反序列化時是否兼容。 如果類沒有顯示定義這個靜態常量,它的值是Java運行時環境根據類的內部細節自動生成的。若類的實例變量做了修改,serialVersionUID 可能發生變化。故建議,==顯式聲明==
簡單來說,Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常。(InvalidCastException)
談談你對java.io.Serializable接口的理解,我們知道它用于序列化,是空方法接口,還有其它認識嗎?
實現了Serializable接口的對象,可將它們轉換成一系列字節,并可在以后完全恢復回原來的樣子。這一過程亦可通過網絡進行。這意味著序列化機制能自動補償操作系統間的差異。換句話說,可以先在Windows機器上創建一個對象,對其序列化,然后通過網絡發給一臺Unix機器,然后在那里準確無誤地重新“裝配”。不必關心數據在不同機器上如何表示,也不必關心字節的順序或者其他任何細節。 由于大部分作為參數的類如String、Integer等都實現了java.io.Serializable的接口,也可以利用多態的性質,作為參數使接口更靈活。
5.1 ObjectInputStream/ObjectOutputStream
若某個類實現了 Serializable 接口,該類的對象就是可序列化的:
鴻蒙官方戰略合作共建——HarmonyOS技術社區
創建一個 ObjectOutputStream
調用 ObjectOutputStream 對象的writeObject(對象) 方法輸出可序列化對象
注意寫出一次,操作flush()一次
反序列化
鴻蒙官方戰略合作共建——HarmonyOS技術社區
創建一個 ObjectInputStream
調用 readObject() 方法讀取流中的對象
強調:如果某個類的屬性不是基本數據類型或 String 類型,而是另一個引用類型,那么這個引用類型必須是可序列化的,否則擁有該類型的Field 的類也不能序列化
package objectTest; import org.junit.Test; import java.io.*; /** * @author mazouri * @create 2020-04-21 20:08 */ public class ObjectInOutputStream { /** * 序列化過程:將內存中的java對象保存到磁盤中或通過網絡傳輸出去 * 使用ObjectOutputStream實現 */ @Test public void test1() { ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream("object.dat")); oos.writeObject(new Person("張三", 18)); //刷新操作 oos.flush(); oos.writeObject(new Person("李四", 23, 1001, new Account(5000))); oos.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (oos != null) oos.close(); } catch (IOException e) { e.printStackTrace(); } } } /* *反序列化:將磁盤文件中的對象還原為內存中的一個java對象 *使用ObjectInputStream來實現 */ @Test public void test2() { ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream("object.dat")); Person p = (Person) ois.readObject(); Person p1 = (Person) ois.readObject(); System.out.println(p + "\n" + p1); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } finally { try { if (ois != null) ois.close(); } catch (IOException e) { e.printStackTrace(); } } } } 復制代碼
輸出結果:
6.隨機存取文件流
到現在為止, 所使用的所有流都是只讀的(read.only ) 或只寫的(write.only)。這些流程為順序( sequential)流。使用順序流打開的文件稱為順序訪問文件。順序訪問文件的內容不能更新。然而,經常需要修改文件。Java 提供了 RandomAccessFile 類,允許在文件的任意位置上進行讀寫。使用RandomAccessFile 類打開的文件稱為隨機訪問文件。
RandomAccessFile 聲明在java.io包下,但直接繼承于java.lang.Object類。并且它實現了DataInput、DataOutput這兩個接口,也就意味著這個類既可以讀也可以寫
RandomAccessFile 內支持 “隨機訪問” 的方式,程序可以直接跳到文件的任意地方來讀、寫文件 支持只訪問文件的部分內容 可以向已存在的文件后追加內容
RandomAccessFile 對象包含一個記錄指針,用以標示當前讀寫處的位置。RandomAccessFile 類對象可以自由移動記錄指針: long getFilePointer():獲取文件記錄指針的當前位置 void seek(long pos):將文件記錄指針定位到 pos 位置
6.1 RandomAccessFile
構造器
public RandomAccessFile(File file, String mode)
public RandomAccessFile(String name, String mode) 創建 RandomAccessFile 類實例需要指定一個 mode 參數,該參數指 定 RandomAccessFile 的訪問模式: r: 以只讀方式打開 rw:打開以便讀取和寫入 rwd:打開以便讀取和寫入;同步文件內容的更新 rws:打開以便讀取和寫入;同步文件內容和元數據的更新
如果模式為只讀r。則不會創建文件,而是會去讀取一個已經存在的文件,如果讀取的文件不存在則會出現異常。 如果模式為rw讀寫。如果文件不存在則會去創建文件,如果存在則不會創建。
@Test public void test1() { RandomAccessFile raf1 = null; RandomAccessFile raf2 = null; try { //1. raf1 = new RandomAccessFile(new File("愛情與友情.jpg"),"r"); raf2 = new RandomAccessFile(new File("愛情與友情1.jpg"),"rw"); //2. byte[] buffer = new byte[1024]; int len; while((len = raf1.read(buffer)) != -1){ raf2.write(buffer,0,len); } } catch (IOException e) { e.printStackTrace(); } finally { //3. if(raf1 != null){ try { raf1.close(); } catch (IOException e) { e.printStackTrace(); } } if(raf2 != null){ try { raf2.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Test public void test2() throws IOException { RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw"); raf1.seek(3);//將指針調到角標為3的位置 raf1.write("xyz".getBytes());// raf1.close(); } /* 使用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(); } }
到此,關于“如何快速了解Java中的IO流”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。