【Java】15 输入输出
文章目錄
- 一、File類
- 1.訪問文件和目錄
- 2.文件過濾器
- 二、理解Java的IO流
- 1.流的分類
- ①按數據流向分類
- ②按數據單元的長度劃分
- ③按流的角色來分類
- 2.流的概念模型
- 三、字節流和字符流
- 1.輸入流中的字節流和字符流
- 2.輸入流中的字節流和字符流
- 四、輸出/輸出流體系
- 1.處理流用法
- 2.輸入/輸出流體系
- 3.轉換流
- 4.推回輸入流
- 五、重定向標準輸入輸出
- 六、Java虛擬機讀寫其他進程的數據
- 七、RandomAccessFile
- 八、對象序列化
- 1.序列化的含義和意義
- 2.使用對象流實現序列化
- 序列化
- 反序列化
- 3.對象引用的序列化
- 4.自定義序列化
- 九、NIO
- 1.Buffer
- 2.Channel
一、File類
1.訪問文件和目錄
/** * @ClassName: FileTest* @description: 本節代碼主要討論FIle類的相關訪問文件和目錄* @author: FFIDEAL* @Date: 2020年4月10日 上午10:17:48*/ package M15;import java.io.File; import java.io.IOException;public class FileTest {public static void main(String[] args) throws IOException{//以當前===路徑===來創建一個File對象File file = new File(".");//獲取文件名System.out.println(file.getName()); //輸出:newFile.txt//獲取相對路徑的父路徑(可能會出錯,輸出null)System.out.println(file.getParent());//獲取絕對路徑 System.out.println(file.getAbsolutePath()); //輸出:E:\JavaCode\Code\newFile.txt//獲取上一級路徑System.out.println(file.getAbsoluteFile().getParent()); //輸出:E:\JavaCode\Code//在當前路徑下創建一個臨時文件File tmpFile = File.createTempFile("tempFile", ".txt");//輸出當前臨時文件的絕對路徑System.out.println(tmpFile.getParent()); //指定JVM退出時刪除該文件tmpFile.deleteOnExit();//以系統當前時間來命令新文件File newFile = new File(System.currentTimeMillis()+"");System.out.println("newFile對象是否存在:" + newFile.exists());newFile.createNewFile();//以newFile創建一個目錄,因為newFile已經存在//所以下面方法返回false,即無法創建該目錄newFile.mkdir();//使用list()方法列出當前路徑下的所有文件String[] fileList = file.list(); System.out.println("===當前路徑下的所有文件和路徑==="); for(String fileName : fileList){System.out.println(fileName);}//listRoots()靜態方法列出所有磁盤根路徑File[] roots = File.listRoots();System.out.println("===系統過有根目錄===");for(File root : roots) {System.out.println(root);}//listFiles是獲取該目錄下所有文件和目錄的絕對路徑 File[] fs = file.listFiles();for(File f:fs) {System.out.println(f);}} }2.文件過濾器
/** * @ClassName: FileNameFilterTest* @description: 文件過濾器* @author: FFIDEAL* @Date: 2020年4月14日 上午10:07:43*/ package M15;import java.io.File;public class FileNameFilterTest {public static void main(String[] args) {File file = new File(".");//文件以“.java”結尾或者文件對應一個路徑,則返回trueString[] nameList = file.list((dir , name) -> name.endsWith(".java") || new File(name).isDirectory());for(int i = 0; i < nameList.length; i++) {System.out.println(i);System.out.println(nameList[i]);}for(String name : nameList) {System.out.println(name);}} }二、理解Java的IO流
1.流的分類
①按數據流向分類
? 從程序所在內存角度劃分
? 輸出流:只能向其寫入數據,而不能從中讀取數據(內存 → 硬盤)------- 基類為:OutputStream類和Writer類
? 輸入流:只能從中讀取數據,而不能向其寫入數據(cache → 內存)--------基類為:InputStream類和Reader類
②按數據單元的長度劃分
? 字節流:數據單元為8位的字節 ------- 基類為:InputStream類和OutputStream類
? 字符流:數據單元為16位的字節------- 基類為:Writer類和Reader類
③按流的角色來分類
? 節點流:從特定的IO設備(如磁盤、網絡等)讀/寫的數據的流
? 處理流:用一個已存在的流進行連接或封裝,通過封裝后的流來實現讀/寫的數據的功能
? 處理流的好處:不能直接連接到實際的數據源,可以采用完全相同的輸入/輸出代碼來訪問不同的數據源,消除不同節點流帶來的差異(只要使用相同的處理流)————變壓器?
2.流的概念模型
? Reader/Writer:是對人來說,Reader讀者,獲取知識,輸入;Writer寫著,輸出知識,輸出
? InputStream/Reader:所有輸入流的基類,前者是字節輸入流,后者是字符輸入流
? OutputStream/Writer:所有輸出流的基類,前者是字節輸出流,后者是字符輸出流
三、字節流和字符流
1.輸入流中的字節流和字符流
read():讀取一個“水滴(字節或字符)”
read(byte[] b)/read(char[] ch):讀取多個"水滴"
read(char[] ch,int off,int len)/read(byte[] ch,int off,int len):同上,規定了長度
字節流
/** * @ClassName: FileInputStreamTest* @description: 本節代碼討論了使用FileInputStream (字節流而非字符流)輸入流讀取數據的一種實現方法* 注意:在本節代碼中,如果設置的“水管”不長,也就是說,不能一次性取完文件中所有的數據,要分多批次* 此時,若文件中時有中文的話,意味著可能會發生亂碼 ———— 原因是,中文占2個字符,而讀取時,只能制度去一個字符* @author: FFIDEAL* @Date: 2020年4月14日 下午2:06:07*/ package M15;import java.io.FileInputStream; import java.io.IOException;public class FileInputStreamTest {public static void main(String[] args) throws IOException{//創建一個字節輸入流FileInputStream fis = new FileInputStream("E:\\JavaCode\\Code\\src\\M15\\FileNameFilterTest.java");//創建一個字節流水管,用來取水byte[] bbuf = new byte[1024];//用于保存實際讀取的字節數int hasRead = 0;//當水管里還有水的時候while((hasRead = fis.read(bbuf)) > 0) {System.out.println(new String(bbuf , 0 , hasRead));}//關閉水管fis.close();} }字符流
/** * @ClassName: FileInputStreamTryCatchTest* @description: 本節代碼主要討論使用try-catch和FileReader(字符輸入流) 字符流 來實現輸入流的實現過程* 另外,也是使用了自動關閉資源的try語句來關閉文件輸入流* @author: FFIDEAL* @Date: 2020年4月14日 下午2:18:59*/ package M15;import java.io.FileReader; import java.io.IOException;public class FileInputStreamTryCatchTest {public static void main(String[] args) throws IOException{try(FileReader fis = new FileReader("E:\\JavaCode\\Code\\src\\M15\\FileNameFilterTest.java")){//創建一個字符流水管char[] chbuf = new char[32];//取水珠計數器int hasRead = 0;while((hasRead = fis.read(chbuf)) > 0) {System.out.println(new String(chbuf, 0 , hasRead));}}catch(IOException ex) {ex.printStackTrace();}} }2.輸入流中的字節流和字符流
write(int a):寫入一個字節/字符
write(byte[] b/char[] ch):寫入一組數據
write(byte[] b/char[] ch,int off,int len):寫入一組由off開始,長度為lend數據
字節流
/** * @ClassName: FileOutputStreamTest* @description: 本節代碼主要討論==字節輸出流==的實現類,配合字節輸入流,將一個文檔里面的數據轉移到另一個文檔中去* @author: FFIDEAL* @Date: 2020年4月14日 下午2:32:35*/ package M15;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;public class FileOutputStreamTest {public static void main(String[] args) throws IOException{try(//創建一個字節輸入流FileInputStream fis = new FileInputStream("E:\\JavaCode\\Code\\src\\M15\\FileNameFilterTest.java");//創建一個字節輸出流FileOutputStream fos =new FileOutputStream("E:\\JavaCode\\Code\\src\\M15\\FileNameFilterTest.txt")){//創建一根字節流水管byte[] bbuf = new byte[1024];//取水計數器int hasRead = 0;while((hasRead = fis.read(bbuf)) > 0) {//每讀一次,即寫入文件輸出流,讀了多少就寫多少fos.write(bbuf, 0, hasRead);}}catch(IOException ex) {ex.printStackTrace();}} }字符流
/** * @ClassName: FileWriterTest* @description: 本節討論了使用==字符輸出流==來實現將一首詩寫入到文件中,同時也將一個文件里的數據寫入到另一個文件里* @author: FFIDEAL* @Date: 2020年4月14日 下午2:41:50*/ public class FileWriterTest {public static void main(String[] args) throws IOException {try(//創建一個字符輸出流FileWriter fw = new FileWriter("E:\\JavaCode\\Code\\src\\M15\\pom.txt");){fw.write("床前明月光,\t\n");fw.write("疑是地上霜。\t\n");fw.write("舉頭望明月。\t\n");fw.write("低頭思故鄉。\t\n");}catch(IOException ex) {ex.printStackTrace();}//創建一個字符輸入流FileReader fr = new FileReader("E:\\JavaCode\\Code\\src\\M15\\pom.txt");//創建一個字符輸出流FileWriter fw = new FileWriter("E:\\JavaCode\\Code\\src\\M15\\pomWriter.txt");//創建一根水管char[] chbuf = new char[1024];//取水計數器int hasRead = 0;while((hasRead = fr.read(chbuf)) > 0) {fw.write(chbuf, 0, hasRead);}//關閉輸入流和輸出流fr.close();fw.close();} }四、輸出/輸出流體系
1.處理流用法
處理流的典型思路是:使用處理流來包裝節點流,程序通過處理流來執行輸入、輸出功能,讓節點流和底層IO設備以及文件交互
識別處理流很簡單:只要流的構造器參數不是一個物理節點,而是已經存在的流,那么這種流就是處理流
/** * @ClassName: PrintStreamTest* @description: 本節代碼討論的是PrintStream處理流,* @author: FFIDEAL* @Date: 2020年4月15日 下午1:46:30*/ public class PrintStreamTest {public static void main(String[] args) throws IOException{try(//創建一個字節流FileOutputStream fos = new FileOutputStream("E:\\JavaCode\\Code\\src\\M15\\print.txt");//創建一個PrintStream流,把FileOutputStream字節流包裝起來PrintStream ps = new PrintStream(fos)){//使用PrintStream執行輸出ps.println("PrintStream執行輸出");//直接使用PrintStream對象輸出對象ps.println(new PrintStreamTest());}catch(IOException e) {e.printStackTrace();}} }2.輸入/輸出流體系
字節流以字節數粗為節點,字符流以字符數組為節點;
字符流可以使用字符串作為物理節點,用于實現從字符串讀取內容,或將內容寫入字符串
/** * @ClassName: StringNodeTest* @description: 本節代碼主要討論輸入輸出的體系問題* @author: FFIDEAL* @Date: 2020年4月15日 下午2:09:39*/ public class StringNodeTest {public static void main(String[] args) throws IOException{String src ="一去二三里,煙村四五家。 \r\n" + "亭臺六七座,八九十枝花。";char[] chbuf = new char[1024];int hasRead = 0;try(StringReader sr = new StringReader(src)){//以循環的方式讀取字符串while((hasRead = sr.read(chbuf)) > 0) {System.out.println(new String(chbuf,0,hasRead));}}catch(IOException ioe) {ioe.printStackTrace();}try(//創建StringWriter時,是加上以一個StringBuffer作為輸出節點//一面指定的20就是StringBuffer的初始長度StringWriter sw = new StringWriter()){sw.write(src);System.out.println("===下面是sw字符串節點里面的內容===");System.out.println(sw.toString());}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }3.轉換流
/** * @ClassName: KeyinTest* @description: 本節代碼主要討論System.in對象轉換成Reader對象(利于包裝為BufferReader),* 將普通的Reader包裝為BufferReader(使用BufferReader對象的方法利于讀取)* @author: FFIDEAL* @Date: 2020年4月15日 下午4:29:34*/ package M15;public class KeyinTest {public static void main(String[] args) throws IOException{try(//將System.in對象轉換成Reader對象InputStreamReader isr = new InputStreamReader(System.in);//將普通的Reader包裝為BufferReaderBufferedReader br = new BufferedReader(isr)){String line =null;//采用循環的方式來讀取while((line = br.readLine()) != null) {//如果讀取到字符串“exit”,程序就退出if(line.equals("exit")) {System.exit(1);}System.out.println("輸出內容為:" + line);}}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }4.推回輸入流
就是輸出到—傳入的參數----輸出傳參以前的字符
五、重定向標準輸入輸出
將System.out的輸出重定向到指定文件輸出,而非在屏幕上輸出
/** * @ClassName: RedirectOut* @description: 本節代碼主要討論將系統的標準輸出重定向到該printStream輸出流* 運行上面程序時將看不到任何輸出 ———— 這意味著標準輸出不再輸出到屏幕,而是輸出到out.txt* 將System.in重定義到指定文件里的內容,正好與程序中的輸出一致* @author: FFIDEAL* @Date: 2020年4月15日 下午6:05:58*/ public class RedirectOut {public static void main(String[] args) throws IOException{try(//一次性創建PrintStream輸出流PrintStream ps = new PrintStream(new FileOutputStream("E:\\JavaCode\\Code\\src\\M15\\out.txt"))){//將標準輸出重定向到ps輸出流System.setOut(ps);//向標準輸出輸出一個字符串System.out.println("這是一個字符串");//向標準輸出輸出一個對象System.out.println(new RedirectOut());}catch(IOException ioe) {ioe.printStackTrace();}} }將System.in的重定向到指定文件,而不是鍵盤輸入
/** * @ClassName: RedirectIn* @description: 創建一個FileInputStream輸入流,并使用System的setIn()方法將系統標準輸入重定向到該文件輸入流* 運行本程序,程序不會等用戶輸入,而是直接輸出RedirectOut.java文件的內容,這表明程序不再使用鍵盤作為標準輸入* @author: FFIDEAL* @Date: 2020年4月15日 下午9:42:45*/ public class RedirectIn {public static void main(String[] args) throws IOException{try(//創建一個FileInputStream輸入流FileInputStream fis = new FileInputStream("E:\\JavaCode\\Code\\src\\M15\\RedirectOut.java")){//將標準輸入重定向到fis輸出流System.setIn(fis);//使用System.in創建Scanner對象,用于獲取標準輸入Scanner sc = new Scanner(System.in);//增加下面一行只把回車作為分隔符sc.useDelimiter("\n");//判斷是否還有下一個輸入項while(sc.hasNext()) {System.out.println("鍵盤輸入的內容是:" + sc.next());}}catch(IOException ioe) {ioe.printStackTrace();}} }六、Java虛擬機讀寫其他進程的數據
/** * @ClassName: ReadFromProcess* @description: 本節代碼主要討論使用Runtime對象的exec()方法可以運行平臺上的其他程序,* 該方法產生一個Process對象,* Process對象代表由該Java程序啟動的子進程* @author: FFIDEAL* @Date: 2020年4月16日 上午10:50:18*/ public class ReadFromProcess {public static void main(String[] args) throws IOException{//運行javac命令,返回運行該命令的子進程Process p = Runtime.getRuntime().exec("javac");try(//以p進程的錯誤流創建BufferReader對象,這個錯誤流對本程序是輸入流,對p進程是輸出流BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()))){String buff = null;while((buff = br.readLine()) != null) {System.out.println(buff);}} } } /** * @ClassName: WriteToProcess* @description: 本節代碼討論通過Process的getOutStream()方法獲得向進程輸入數據的流,* 如下程序實現了在java程序中啟動Java虛擬機運行另一個java程序,并向另一個程序輸入數據* @author: FFIDEAL* @Date: 2020年4月16日 下午12:50:20*/ public class WriteToProcess {public static void main(String[] args) throws IOException{//運行Java ReadStandard命令,返回該命令的子進程Process p = Runtime.getRuntime().exec("Java ReadStandard");try(//以p進程的輸出流創建PrintStream對象//對于程序來說這是輸出流,對于子進程來說,這是輸入流PrintStream ps = new PrintStream(p.getOutputStream());){//向ReadStandard程序寫入內容,這些內容被ReadStandard讀取ps.println("這是ReadStandard讀取的內容");ps.println(new WriteToProcess()); }} }//定義一個ReadStandard類,該類可以接收標準輸入 //并將標準輸入寫入ReadStandard.txt文件中d class ReadStandard{public static void main(String[] args) throws IOException{try(//使用System.in創建Scanner對象用于標準輸入Scanner sc = new Scanner(System.in);PrintStream ps = new PrintStream("E:\\JavaCode\\Code\\src\\M15\\ReadStandard.txt")){//增加下面一行只把回車作為分隔符sc.useDelimiter("\n");while(sc.hasNext()) {//輸出鍵盤輸入的內容System.out.println("鍵盤輸入的內容是:" + sc.next());}}catch(Exception e) {e.printStackTrace();}} }七、RandomAccessFile
RandomAccessFile(任意訪問文件):是功能最豐富的文件訪問類,它既==可以讀文件,也可以寫文件,同時還有**“任意訪問”==**文件。若只需要訪問文件的部分內容,而非把文件從頭到尾讀取,采用RandomAccessFile類將是一個很好的選擇。
但是她有一個缺陷,也就是說他只能讀寫文件但**不能讀寫其他IO節點**。
以下使用RandomAccessFile來訪問指定的中間部分數據
public class RandomAccessFiletest {public static void main(String[] args) throws IOException{try(//創建一個RandomAccessFile對象RandomAccessFile raf = new RandomAccessFile("E:\\JavaCode\\Code\\src\\M15\\pomWriter.txt", "r");){//獲取RandomAccessFile對象指針位置,初始位置為0System.out.println("RandomAccessFile的文件指針的初始地址" + raf.getFilePointer());//移動文件記錄指針位置raf.seek(6);byte[] bbuf = new byte[1024];//記錄實際讀取的字節數int hasRead = 0;while((hasRead = raf.read(bbuf)) > 0) {//取出竹筒中的水滴(“字節”),將字節數組轉換成字符串輸入System.out.println(new String(bbuf,0,hasRead));}}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }下面代碼是寫入文件
public class AppendContent {public static void main(String[] args) throws IOException{try(//以“讀寫”的方式打開一個RandomAccessFile對象RandomAccessFile raf = new RandomAccessFile("E:\\JavaCode\\Code\\src\\M15\\pomWriter.txt", "rw");){//將指針移動到最后raf.seek(raf.length());raf.write("\n這是使用RandomAccessFile對象追加的內容".getBytes());}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }下面程序實現了向指定文件、指定位置插入內容的功能
/** * @ClassName: InsertContent* @description: 本節代碼向指定位置插入數據,在此位置之后的數據放入緩存區,* 當全部寫完輸入后,緩存區里的數據接在插入數據之后* @author: FFIDEAL* @Date: 2020年4月16日 下午5:42:01*/ public class InsertContent {public static void insert(String fileName, long position , String insertContent) throws IOException{//創建一個臨時文件,用作緩存區File tmp = File.createTempFile("tmp", null);tmp.deleteOnExit();try(RandomAccessFile raf = new RandomAccessFile(fileName, "rw");//使用臨時文件來保存插入點數據FileOutputStream tmpOut = new FileOutputStream(tmp);FileInputStream tmpIn = new FileInputStream(tmp)){raf.seek(position);//下面代碼將插入點后的內容讀入臨時文件中保存byte[] bbuf = new byte[20];//用于保存實際讀取的字節int hasRead = 0;while((hasRead = raf.read(bbuf)) > 0) {//將讀取的數據寫入 臨時文件tmpOut.write(bbuf, 0, hasRead);}//下面代碼用于插入內容//把文件記錄指針重新定位到pos位置raf.seek(position);//追加需要插入的內容raf.write(insertContent.getBytes());//追加臨時文件中的內容while((hasRead = tmpIn.read(bbuf)) > 0) {raf.write(bbuf,0,hasRead);}}}public static void main(String[] args) throws IOException {insert("E:\\JavaCode\\Code\\src\\M15\\print.txt", 45, "=========================");} }八、對象序列化
1.序列化的含義和意義
序列化機制:將實現序列化的Java對象轉換成字節序列,這些字節序列可以保存在磁盤上,或通過網絡傳輸,以備以后重新恢復成原來的對象 —— 序列化機制使得對象可以脫離程序存在
對象的序列化:講一個Java對象希爾IO流中,與此對應的四,對象的反序列化則指從IO流中恢復該Java對象
實現對象的序列化的前提就是對象的類要序列化,類的序列化就是必須實現Serialiable或Externalizable接口
2.使用對象流實現序列化
使用Serializable來實現序列化非常簡單,主要讓目標實現Serializable標記接口即可,無需事先任何方法
? 1.創建ObjectOutputStream,這是一個輸出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));? 2.調用ObjectOutputStream對象的writeObject()方法輸出可序列化對象
oos.writeObject(per);序列化
實例代碼
//創建一個普通類,繼承Serializable接口。當然Externalizable接口也行 public class Person implements Serializable{private String name;private int age;public Person(String name, int age) {System.out.println("有參數構造器");this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}使用objectOutputStream(對象輸出流)講一個Person類的對象寫入文件中
public class WriteObject {public static void main(String[] args) throws IOException{try(//創建一個ObjectoutputStream輸出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\JavaCode\\Code\\src\\M15\\Seriliable.txt"));){Person per = new Person("張三", 18);//將這個對象寫入輸出流oos.writeObject(per);}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }反序列化
1.創建一個ObjectInputStream輸入流,這個輸入流是一個處理流,必須建立在其他節點流基之上
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("out.txt"));2.調用ObjectInputStream對象的readObject()方法讀取流中的對象,該方法返回一個Object類型的java對象
Person p = (Person)ois.readObject();以下代碼示范了剛剛生成的文件中讀取Person對象的步驟
public class ReadObjectTest {public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\JavaCode\\Code\\src\\M15\\Seriliable.txt"))){Person p = (Person)ois.readObject();System.out.println("p的姓名:" + p.getName() + ",年齡:" + p.getAge());}catch(Exception e) {e.printStackTrace();}} }注意:反序列化讀取的僅僅使Java對象的數據,而非Java類
若使用序列化機制向文件中寫入多個Java對象,使用反序列化機制恢復對象時必須按實際寫入的順序讀取
3.對象引用的序列化
若一個類的成員變量不是基本類型或者String型,而是另一種引用類型,那么這個引用類必須是可序列化的
此外,序列化機制會采用一種特殊的序列化算法
1.所有保存到磁盤中的對象都有一個序列化編號
2.在程序試圖序列化一個對象的時候,程序會優先檢查該對象是否被序列化過,若沒有,系統才會將該對象轉換成字節序列并輸出
3.程序將只是直接輸出一個序列化編號,而不是再次重新序列化該對象
public class Teacher implements Serializable{private String name;private Person student;public Teacher(String name,Person student) {this.name = name;this.student = student;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Person getStudent() {return student;}public void setStudent(Person student) {this.student = student;} } public class WriteTeacher {public static void main(String[] args) throws FileNotFoundException, IOException {try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\JavaCode\\Code\\src\\M15\\teacher.txt"))){Person per = new Person("小明", 13);Teacher t1 = new Teacher("王老師", per);Teacher t2 = new Teacher("張老師", per);//依次將4個對象寫入輸出流oos.writeObject(t1);oos.writeObject(t2);oos.writeObject(per);oos.writeObject(t2);}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }上面writeObject()方法仿佛寫入了四個對象,但實際上只寫入三個對象,而且序列的兩個Teacher對象的student引用實際是同一個Person對象。下面程序讀取序列化文件中的對象即可證明
public class ReadTeacher {public static void main(String[] args) throws FileNotFoundException,IOException, ClassNotFoundException{try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\JavaCode\\Code\\src\\M15\\teacher.txt"))){//依次讀取ObjectInputStream輸入流中的4個對象Teacher t1 = (Teacher)ois.readObject();Teacher t2 = (Teacher)ois.readObject();Person per = (Person)ois.readObject();Teacher t3 = (Teacher)ois.readObject();//輸出trueSystem.out.println("t1的student引用和p是否相同:" + (t1.getStudent()==per));//輸出trueSystem.out.println("t2的student引用和p是否相同:" + (t2.getStudent()==per));//輸出trueSystem.out.println("t2和t3是否相同:" + (t2==t3));}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }注意:序列化機制當程序序列化一個可變對象時,只有第一次使用writeObject()方法輸出時才會將該對象轉換成字節序列并輸出,再次調用只會輸出前面序列化的編號
4.自定義序列化
在一些特殊的場景下不希望系統將實例變量值進行序列化
通過在實例變量前用transient關鍵詞修飾,可以指定Java序列化無需理會該實例變量。
private transient int age;下面程序先序列化一個Person對象,然后再反序列化該Person對象,得到反序列化兌現的Person對象之后程序輸出該對象的age實例變量值
public class TransientTest {public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\JavaCode\\Code\\src\\M15\\transient.txt"));ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\JavaCode\\Code\\src\\M15\\transient.txt"))){Person per = new Person("哪吒", 7);oos.writeObject(per);Person p = (Person)ois.readObject();System.out.println(p.getAge());}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }九、NIO
新IO采用內存映射文件的方式來處理輸入/輸出,新IO將文件或文件的一段區域映射到內存中,這樣就可以像訪問內存一樣來訪問文件。Channel(通道)和Buffer(緩沖)是新IO的兩個核心對象。
Channel比InputStream、OutputStream最大的區別在于他提供了一個map方法,通過這個方法可以直接將“一塊數據”映射到內存中。Buffer可以被理解成一個容器,它的本質是一個數組,發送到Channel中的所有對象都必須首先放到Buffer中去。
打個比方:Buffer既可以像“竹筒”一樣一次次從Channel中取水,也允許使用Channel直接將文件袋某塊數據映射成Buffer
1.Buffer
Buffer有三個重要的概念:容量(capacity)、界限(limit)和位置(position)
2.Channel
Channel有以下兩個特點
Channel有三個主要的方法:map() read() write()
public class FileChannelTest {public static void main(String[] args) throws FileNotFoundException, IOException {File f = new File("E:\\JavaCode\\Code\\src\\M15\\print.txt");try(//創建FileInputStream,以文件輸入流創建FileChannelFileChannel inChannel = new FileInputStream(f).getChannel();//文件輸出流創建FileChannel,用以控制輸出FileChannel outChannel = new FileOutputStream("E:\\JavaCode\\Code\\src\\M15\\ChannelOut.txt").getChannel();){//將FileChannel里的全部數據映射成ByteBuffer,將FileChannel里面的輸出全部改為ByteChannelMappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());//使用GBK的字符集來創建解碼器Charset charset = Charset.forName("GBK");//直接將buffer里的數據全部輸出,將整個ByteBuffer的全部數據寫入一個輸出FileChanneloutChannel.write(buffer);//在調用buffer的clear()方法,復原limit和position的位置buffer.clear();//創建解碼器(CharsetDecoder)對象CharsetDecoder cd = charset.newDecoder();//使用解碼器將ByteBuffer轉換成charBufferCharBuffer cb = cd.decode(buffer);//CharBuffer的toString方法可以獲取對應的字符串System.out.println(cb);}catch (Exception e) {// TODO: handle exceptione.printStackTrace();}} }總結
以上是生活随笔為你收集整理的【Java】15 输入输出的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【前端模块】css基础
- 下一篇: 【PTA】JAVA提交的一些注意点