溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何快速了解Java中的IO流

發(fā)布時間:2021-10-26 10:12:48 來源:億速云 閱讀:286 作者:iii 欄目:編程語言

這篇文章主要介紹“如何快速了解Java中的IO流”,在日常操作中,相信很多人在如何快速了解Java中的IO流問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何快速了解Java中的IO流”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一. File類
1.簡單介紹

  • File類的一個對象既能代表一個特定的文件的名稱,又能代表一個目錄下的一組文件的名稱。

  • File 能新建、刪除、重命名文件和目錄,但 File 不能訪問文件內(nèi)容本身。如果需要訪問文件內(nèi)容本身,則需要使用輸入/輸出流。

  • 想要在Java程序中表示一個真實存在的文件或目錄,那么必須有一個File對 象,但是Java程序中的一個File對象,可能沒有一個真實存在的文件或目錄。

  • 后續(xù)File類的對象常會作為參數(shù)傳遞到流的構找器中,指明讀取或?qū)懭氲?quot;終點"。

2.基本用法
在文件系統(tǒng)中,每個文件都存放在一個目錄下。絕對文件名( absolute file name) 是由文件名和它的完整路徑以及驅(qū)動器字母組成。相對文件名是相對于當前工作目錄的。例如,c:\book\Welcome.java 是文件Welcome.java 在 Windows 操作系統(tǒng)上的絕對文件名。Welcome.java 是一個相對文件名。

windows和DOS系統(tǒng)默認使用“\”來表示 UNIX和URL使用“/”來表示 Java程序支持跨平臺運行,因此路徑分隔符要慎用。為了解決這個隱患,F(xiàn)ile類提供了一個常量: public static final String separator。根據(jù)操作系統(tǒng),動態(tài)的提供分隔符。 File file = new File("D:"+File.separator +"JavaSE"+File.separator +"JavaProject");

2.1 構造方法

  • public File(String pathname) 以pathname為路徑創(chuàng)建File對象,可以是絕對路徑或者相對路徑

  • public File(String parent,String child)以parent為父路徑,child為子路徑創(chuàng)建File對象。

  • public File(File parent,String child)根據(jù)一個父File對象和子文件路徑創(chuàng)建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);

輸出結(jié)果:

如何快速了解Java中的IO流

2.2 常用方法
2.2.1 File類的獲取功能

  • public String getAbsolutePath():獲取絕對路徑

  • public String getPath() :獲取路徑

  • public String getName() :獲取名稱

  • public String getParent():獲取上層文件目錄路徑。若無,返回null,若文件對象中是相對路徑,則返回null;

  • public long length() :獲取文件長度(即:字節(jié)數(shù))。不能獲取目錄的長度。

  • public long lastModified() :獲取最后一次的修改時間,毫秒值,若該文件不在硬盤中真實存在,返回0。

  • public String[] list() :獲取指定目錄下的所有文件或者文件目錄的名稱數(shù)組

  • public File[] listFiles() :獲取指定目錄下的所有文件或者文件目錄的File數(shù)組

 @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());     } 復制代碼

輸出結(jié)果:

如何快速了解Java中的IO流

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());     } 復制代碼

輸出結(jié)果:

如何快速了解Java中的IO流

如何快速了解Java中的IO流

2.2.3 File類的其他功能
public boolean createNewFile() :創(chuàng)建文件。若文件存在,則不創(chuàng)建,返回false。指定文件的目錄要存在。 public boolean delete():刪除文件或者文件夾,刪除注意事項:Java中的刪除不走回收站。要想文件夾刪除成功,最后一個文件目錄下不能有子目錄或文件

  @Test     public void test6() throws IOException {         File file1 = new File("hello.txt");//此時文件不存在         if (!file1.exists()){             //文件的創(chuàng)建             boolean newFile = file1.createNewFile();             System.out.println("文件創(chuàng)建成功");         }else{             boolean delete = file1.delete();             System.out.println("原文件刪除成功");         }     } 復制代碼

如何快速了解Java中的IO流

如何快速了解Java中的IO流

public boolean mkdir() :創(chuàng)建文件目錄。如果此文件目錄存在,就不創(chuàng)建了。如果此文件目錄的上層目錄不存在,也不創(chuàng)建。
public boolean mkdirs() :創(chuàng)建文件目錄。如果上層文件目錄不存在,一并創(chuàng)建

@Test public void test7() {     //文件目錄的創(chuàng)建     File file1 = new File("d:\\io\\io1\\io2");//此時只有io目錄存在     boolean mkdir = file1.mkdir();     if (mkdir) {         System.out.println("創(chuàng)建成功1");     }      File file2 = new File("d:\\io\\io1\\io2");//此時只有io目錄存在     boolean mkdirs = file2.mkdirs();     if (mkdirs) {         System.out.println("創(chuàng)建成功2");     } } 復制代碼

輸出結(jié)果:

如何快速了解Java中的IO流

public boolean renameTo(File dest):把文件重命名為指定的文件路徑,比如:file1.renameTo(file2)為例: 要想保證返回true,需要file1在硬盤中是存在的,且file2不能在硬盤中存在。

@Test   public void test9(){       File file1 = new File("hello.txt");//在硬盤中存在內(nèi)容為"hello world!"       File file2 = new File("D:\\io\\hi.txt");//hi.txt不存在       boolean renameTo = file1.renameTo(file2);       System.out.println(renameTo);   } 代碼

輸出結(jié)果:生成了原本不存在的hi.txt文件,內(nèi)容為hello world! hello.txt位置發(fā)生移動。

如何快速了解Java中的IO流

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());//輸出結(jié)果:mainD:\JavaSE\JavaProject\WorkSpace\hello.txt     }      @Test     public void test1() {         File file = new File("hello.txt");         System.out.println("test" + file.getAbsoluteFile());//輸出結(jié)果:testD:\JavaSE\JavaProject\WorkSpace\ioDemo\hello.txt     } } 復制代碼

二. IO流
1. 簡單介紹
Java 提供了許多實現(xiàn)文件輸人 / 輸出的類。這些類可以分為文本 I/O 類(text I/O class)和二進制 I/O 類(binary I/O class)。

輸入對象(輸入流)讀取外部數(shù)據(jù)(磁盤、光盤等存儲設備的數(shù)據(jù))到程序(內(nèi)存)中,操作過程中,我們是以 程序(內(nèi)存)的角度。
輸出對象(輸出流)將程序(內(nèi)存)數(shù)據(jù)輸出到磁盤、光盤等存儲設備中。

如何快速了解Java中的IO流

1.1 流的分類

  • 按操作數(shù)據(jù)單位不同分為:字節(jié)流(8 bit),字符流(16 bit)

  • 按數(shù)據(jù)流的流向不同分為:輸入流,輸出流

  • 按流的角色的不同分為:節(jié)點流,處理流

Java的IO流共涉及40多個類,實際上非常規(guī)則,都是從如下4個 抽象基類派生的。 由這四個類派生出來的子類名稱都是以其父類名作為子類名后綴。

如何快速了解Java中的IO流

2. 節(jié)點流(文件流)

  • 定義文件路徑時,注意:可以用“/”或者“\”。

  • 在寫入一個文件時,如果使用構造器FileOutputStream(file),則目錄下有同名文件將被覆蓋。

  • 如果使用構造器FileOutputStream(file,true),則目錄下的同名文件不會被覆蓋,在文件內(nèi)容末尾追加內(nèi)容。

  • 在讀取文件時,必須保證該文件已存在,否則報異常。

  • 字節(jié)流操作字節(jié),比如:.mp3,.avi,.rmvb,mp4,.jpg,.doc,.ppt

  • 字符流操作字符,只能操作普通文本文件。最常見的文本文件:.txt,.java,.c,.cpp 等語言的源代碼。尤其注意.doc,excel,ppt這些不是文本文件。

2.1 FileReader/FileWriter(字符流)
2.1.1 FileReader常用方法

  • int read():讀取單個字符。作為整數(shù)讀取的字符,范圍在 0 到 65535 之間 (0x00-0xffff)(2個 字節(jié)的Unicode碼),如果已到達流的末尾,則返回 -1

  • int read(char[] cbuf):將字符讀入數(shù)組。如果已到達流的末尾,則返回 -1。否則返回本次讀取的字符數(shù)。

  • int read(char[] cbuf,int off,int len):將字符讀入數(shù)組的某一部分。存到數(shù)組cbuf中,從off處開始存儲,最多讀len個字符。如果已到達流的末尾,則返回 -1。否則返回本次讀取的字符數(shù)。

  • public void close() throws IOException:關閉此輸入流并釋放與該流關聯(lián)的所有系統(tǒng)資源。

2.1.2 基本用法
幾乎所有的I/O類中的方法都會拋出異常 ;java.io.IOException。因此,必須在方法中聲明會拋出:java.io.IOException 異常,或者將代碼放到 try-catch 塊中。

//將module下的hello.txt文件內(nèi)容讀入程序中,并輸出到控制臺  @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();                 }             }         }     } 復制代碼

輸出結(jié)果:

如何快速了解Java中的IO流

2.1.1 FileWriter常用方法

  • void write(int c):寫入單個字符。要寫入的字符包含在給定整數(shù)值的 16 個低位中,16 高位被忽略。 即寫入0 到 65535 之間的Unicode碼。

  • void write(char[] cbuf):寫入字符數(shù)組。

  • void write(char[] cbuf,int off,int len):寫入字符數(shù)組的某一部分。從off開始,寫入len個字符寫入字符串。

  • void write(String str,int off,int len):寫入字符串的某一部分。

  • void flush():刷新該流的緩沖,則立即將它們寫入預期目標。

  • public void close()throws IOException :關閉此輸出流并釋放與該流關聯(lián)的所有系統(tǒng)資源

2.1.2 基本用法

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術社區(qū)

  2. 輸出操作,對應的File可以不存在的。并不會報異常

  3. File對應的硬盤中的文件如果不存在,在輸出的過程中,會自動創(chuàng)建此文件。 File對應的硬盤中的文件如果存在: ① 如果流使用的構造器是:FileWriter(file,false) / FileWriter(file):對原有文件的覆蓋 ② 如果流使用的構造器是:FileWriter(file,true):不會對原有文件覆蓋,而是在原有文件基礎上追加內(nèi)容

//從內(nèi)存中寫出數(shù)據(jù)到硬盤的文件里 @Test     public void test2() {         FileWriter fw = null;         try {             //1.創(chuàng)建File類的對象,指明寫出的文件             File file = new File("hello1.txt");              //2.提供FileWrite的對象,用于數(shù)據(jù)的寫出             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();                 }             }         }     } 復制代碼

如何快速了解Java中的IO流

實現(xiàn)文本之間的復制

@Test    public void test3() {        FileReader fr = null;        FileWriter fw = null;        try {            //1.創(chuàng)建File類的對象,指明讀入與寫出的文件            File srcFile = new File("hello.txt");            File destFile = new File("hello2.txt");             //2.創(chuàng)建輸入流與輸出流的對象            fr = new FileReader(srcFile);            fw = new FileWriter(destFile);             //3.數(shù)據(jù)的讀入與寫出的操作            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(字節(jié)流)
2.2.1 FileInputStream常用方法

  • int read():從輸入流中讀取數(shù)據(jù)的下一個字節(jié)。返回 0 到 255 范圍內(nèi)的 int 字節(jié)值。如果因為已經(jīng)到達流末尾而沒有可用的字節(jié),則返回值 -1。

  • int read(byte[] b):從此輸入流中將最多 b.length 個字節(jié)的數(shù)據(jù)讀入一個 byte 數(shù)組中。如果因為已經(jīng)到達流末尾而沒有可用的字節(jié),則返回值 -1。否則以整數(shù)形式返回實際讀取的字節(jié)數(shù)。

  • int read(byte[] b, int off,int len):將輸入流中最多 len 個數(shù)據(jù)字節(jié)讀入 byte 數(shù)組。嘗試讀取 len 個字節(jié),但讀取的字節(jié)也可能小于該值。以整數(shù)形式返回實際讀取的字節(jié)數(shù)。如果因為流位于文件末尾而沒有可用的字節(jié),則返回值 -1。

  • public void close() throws IOException:關閉此輸入流并釋放與該流關聯(lián)的所有系統(tǒng)資源。

2.2.2 FileOutputStream常用方法

  • void write(int b):將指定的字節(jié)寫入此輸出流。write 的常規(guī)協(xié)定是:向輸出流寫入一個字節(jié)。要寫入的字節(jié)是參數(shù) b 的八個低位。b 的 24 個高位將被忽略。 即寫入0~255范圍的。

  • void write(byte[] b):將 b.length 個字節(jié)從指定的 byte 數(shù)組寫入此輸出流。write(b) 的常規(guī)協(xié)定是:應該與調(diào)用 write(b, 0, b.length) 的效果完全相同。

  • void write(byte[] b,int off,int len):將指定 byte 數(shù)組中從偏移量 off 開始的 len 個字節(jié)寫入此輸出流。

  • public void flush()throws IOException:刷新此輸出流并強制寫出所有緩沖的輸出字節(jié),調(diào)用此方法指示應將這些字節(jié)立即寫入它們預期的目標。

  • public void close() throws IOException:關閉此輸出流并釋放與該流關聯(lián)的所有系統(tǒng)資源。

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.讀數(shù)據(jù)            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();            }        }    } 制代碼

復制成功

如何快速了解Java中的IO流

3.緩沖流

  • 為了提高數(shù)據(jù)讀寫的速度,Java API提供了帶緩沖功能的流類,在使用這些流類時,會創(chuàng)建一個內(nèi)部緩沖區(qū)數(shù)組,缺省使用8192個字節(jié)(8Kb)的緩沖區(qū)。

  • 當讀取數(shù)據(jù)時,數(shù)據(jù)按塊讀入緩沖區(qū),其后的讀操作則直接訪問緩沖區(qū)

  • 當使用BufferedInputStream讀取字節(jié)文件時,BufferedInputStream會一次性從文件中讀取8192個(8Kb),存在緩沖區(qū)中,直到緩沖區(qū)裝滿了,才重新從文件中讀取下一個8192個字節(jié)數(shù)組。

  • 向流中寫入字節(jié)時,不會直接寫到文件,先寫到緩沖區(qū)中直到緩沖區(qū)寫滿,BufferedOutputStream才會把緩沖區(qū)中的數(shù)據(jù)一次性寫到文件里。使用方法flush()可以強制將緩沖區(qū)的內(nèi)容全部寫入輸出流

  • 關閉流的順序和打開流的順序相反。只要關閉最外層流即可,關閉最外層流也會相應關閉內(nèi)層節(jié)點流

  • flush()方法的使用:手動將buffer中內(nèi)容寫入文件

  • 如果是帶緩沖區(qū)的流對象的close()方法,不但會關閉流,還會在關閉流之前刷新緩沖區(qū),關閉后不能再寫出

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造節(jié)點流             FileInputStream fis = new FileInputStream(srcFile);             FileOutputStream fos = new FileOutputStream(descFile);              //2.2造緩沖流             bis = new BufferedInputStream(fis);             bos = new BufferedOutputStream(fos);              //3.數(shù)據(jù)讀入與寫出操作             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();             }             //說明:先關閉外層的流,再關閉內(nèi)層的流             // 關閉外層流的同時,內(nèi)層流也會自動的進行關閉。關于內(nèi)層流的關閉,我們可以省略. //        fos.close(); //        fis.close();         }     } 復制代碼

結(jié)果:成功復制

如何快速了解Java中的IO流

3.2 BufferedReader/BufferedWriter

 @Test     public void test2() throws IOException {         BufferedReader br = null;         BufferedWriter bw = null;         try {             //創(chuàng)建文件和相應的流             //  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.轉(zhuǎn)換流
4.1 InputStreamReader/OutputStreamWriter

  • 轉(zhuǎn)換流提供了在字節(jié)流和字符流之間的轉(zhuǎn)換

  • Java API提供了兩個轉(zhuǎn)換流: InputStreamReader:將InputStream轉(zhuǎn)換為Reader OutputStreamWriter:將Writer轉(zhuǎn)換為OutputStream

  • 字節(jié)流中的數(shù)據(jù)都是字符時,轉(zhuǎn)成字符流操作更高效。

  • 很多時候我們使用轉(zhuǎn)換流來處理文件亂碼問題。實現(xiàn)編碼和解碼的功能。 編碼:字符串&mdash;&mdash;>字節(jié)數(shù)組 解碼:字節(jié)數(shù)組&mdash;&mdash;>字符串

 /**      * 綜合使用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.數(shù)據(jù)讀寫過程             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();             }         }     } 復制代碼

如何快速了解Java中的IO流

如何快速了解Java中的IO流

5.對象流
5.2 對象的的序列化

  • ObjectlnputStream 類和 ObjectOutputStream 類除了可以實現(xiàn)基本數(shù)據(jù)類型與字符串的輸人和輸出之外,還可以實現(xiàn)對象的輸人和輸出。

  • 序列化:用ObjectOutputStream類保存基本類型數(shù)據(jù)或?qū)ο蟮臋C制

  • 反序列化:用ObjectInputStream類讀取基本類型數(shù)據(jù)或?qū)ο蟮臋C制

  • ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量

  • 對象序列化機制允許把內(nèi)存中的Java對象轉(zhuǎn)換成平臺無關的二進制流,從而允許把這種二進制流持久地保存在磁盤上,或通過網(wǎng)絡將這種二進制流傳輸?shù)搅硪粋€網(wǎng)絡節(jié)點。//當其它程序獲取了這種二進制流,就可以恢復成原來的Java對象

  • 序列化的好處在于可將任何實現(xiàn)了Serializable接口的對象轉(zhuǎn)化為字節(jié)數(shù)據(jù),使其在保存和傳輸時可被還原

  • 序列化是 RMI(Remote Method Invoke &ndash; 遠程方法調(diào)用)過程的參數(shù)和返回值都必須實現(xiàn)的機制,而 RMI 是 JavaEE 的基礎。因此序列化機制是JavaEE 平臺的基礎

  • 如果需要讓某個對象支持序列化機制,則必須讓對象所屬的類及其屬性是可序列化的,為了讓某個類是可序列化的,該類必須實現(xiàn)如下兩個接口之一。否則,會拋出NotSerializableException異常 Serializable Externalizable

  • 凡是實現(xiàn)Serializable接口的類都有一個表示序列化版本標識符的靜態(tài)變量: private static final long serialVersionUID; serialVersionUID用來表明類的不同版本間的兼容性。簡言之,其目的是以序列化對象進行版本控制,有關各版本反序列化時是否兼容。 如果類沒有顯示定義這個靜態(tài)常量,它的值是Java運行時環(huán)境根據(jù)類的內(nèi)部細節(jié)自動生成的。若類的實例變量做了修改,serialVersionUID 可能發(fā)生變化。故建議,==顯式聲明==

  • 簡單來說,Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節(jié)流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現(xiàn)序列化版本不一致的異常。(InvalidCastException)

談談你對java.io.Serializable接口的理解,我們知道它用于序列化,是空方法接口,還有其它認識嗎?

實現(xiàn)了Serializable接口的對象,可將它們轉(zhuǎn)換成一系列字節(jié),并可在以后完全恢復回原來的樣子。這一過程亦可通過網(wǎng)絡進行。這意味著序列化機制能自動補償操作系統(tǒng)間的差異。換句話說,可以先在Windows機器上創(chuàng)建一個對象,對其序列化,然后通過網(wǎng)絡發(fā)給一臺Unix機器,然后在那里準確無誤地重新“裝配”。不必關心數(shù)據(jù)在不同機器上如何表示,也不必關心字節(jié)的順序或者其他任何細節(jié)。 由于大部分作為參數(shù)的類如String、Integer等都實現(xiàn)了java.io.Serializable的接口,也可以利用多態(tài)的性質(zhì),作為參數(shù)使接口更靈活。

5.1 ObjectInputStream/ObjectOutputStream
若某個類實現(xiàn)了 Serializable 接口,該類的對象就是可序列化的:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術社區(qū)

  2. 創(chuàng)建一個 ObjectOutputStream

  3. 調(diào)用 ObjectOutputStream 對象的writeObject(對象) 方法輸出可序列化對象

  4. 注意寫出一次,操作flush()一次

反序列化

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術社區(qū)

  2. 創(chuàng)建一個 ObjectInputStream

  3. 調(diào)用 readObject() 方法讀取流中的對象

強調(diào):如果某個類的屬性不是基本數(shù)據(jù)類型或 String 類型,而是另一個引用類型,那么這個引用類型必須是可序列化的,否則擁有該類型的Field 的類也不能序列化

package objectTest;  import org.junit.Test;  import java.io.*;  /**  * @author mazouri  * @create 2020-04-21 20:08  */ public class ObjectInOutputStream {     /**      * 序列化過程:將內(nèi)存中的java對象保存到磁盤中或通過網(wǎng)絡傳輸出去      * 使用ObjectOutputStream實現(xiàn)      */     @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();             }         }     }      /*      *反序列化:將磁盤文件中的對象還原為內(nèi)存中的一個java對象      *使用ObjectInputStream來實現(xiàn)      */     @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();             }         }     } } 復制代碼

輸出結(jié)果:

如何快速了解Java中的IO流

6.隨機存取文件流

  • 到現(xiàn)在為止, 所使用的所有流都是只讀的(read.only ) 或只寫的(write.only)。這些流程為順序( sequential)流。使用順序流打開的文件稱為順序訪問文件。順序訪問文件的內(nèi)容不能更新。然而,經(jīng)常需要修改文件。Java 提供了 RandomAccessFile 類,允許在文件的任意位置上進行讀寫。使用RandomAccessFile 類打開的文件稱為隨機訪問文件。

  • RandomAccessFile 聲明在java.io包下,但直接繼承于java.lang.Object類。并且它實現(xiàn)了DataInput、DataOutput這兩個接口,也就意味著這個類既可以讀也可以寫

  • RandomAccessFile 內(nèi)支持 “隨機訪問” 的方式,程序可以直接跳到文件的任意地方來讀、寫文件 支持只訪問文件的部分內(nèi)容 可以向已存在的文件后追加內(nèi)容

  • RandomAccessFile 對象包含一個記錄指針,用以標示當前讀寫處的位置。RandomAccessFile 類對象可以自由移動記錄指針: long getFilePointer():獲取文件記錄指針的當前位置 void seek(long pos):將文件記錄指針定位到 pos 位置

6.1 RandomAccessFile
構造器

  • public RandomAccessFile(File file, String mode)

  • public RandomAccessFile(String name, String mode) 創(chuàng)建 RandomAccessFile 類實例需要指定一個 mode 參數(shù),該參數(shù)指 定 RandomAccessFile 的訪問模式: r: 以只讀方式打開 rw:打開以便讀取和寫入 rwd:打開以便讀取和寫入;同步文件內(nèi)容的更新 rws:打開以便讀取和寫入;同步文件內(nèi)容和元數(shù)據(jù)的更新

  • 如果模式為只讀r。則不會創(chuàng)建文件,而是會去讀取一個已經(jīng)存在的文件,如果讀取的文件不存在則會出現(xiàn)異常。 如果模式為rw讀寫。如果文件不存在則會去創(chuàng)建文件,如果存在則不會創(chuàng)建。

  @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);//將指針調(diào)到角標為3的位置         raf1.write("xyz".getBytes());//          raf1.close();      }     /*     使用RandomAccessFile實現(xiàn)數(shù)據(jù)的插入效果      */     @Test     public void test3() throws IOException {          RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");          raf1.seek(3);//將指針調(diào)到角標為3的位置         //保存指針3后面的所有數(shù)據(jù)到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)) ;         }         //調(diào)回指針,寫入“xyz”         raf1.seek(3);         raf1.write("xyz".getBytes());          //將StringBuilder中的數(shù)據(jù)寫入到文件中         raf1.write(builder.toString().getBytes());          raf1.close();     } }

到此,關于“如何快速了解Java中的IO流”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI