Io流
按照分類 有兩種分類
流向方向: 有輸入流和輸出流
按照操作型別有:位元組流和字元流
按照流向方向
位元組流的一些操作 //讀檔案 FileInputStream fis = new FileInputStream("java.txt"); int temp = fis.read()//一次讀取一個位元組 System.out.println(temp); //列印的字母的碼值 讀取完返回-1 System.out.println((char)temp);//列印字母 byte[] arr = new byte[6]; //定義byte陣列告訴系統一次讀取幾個位元組,減少記憶體和硬碟之間的通訊,可以提高效率 int temp = bis.read(arr); //有參的read方法返回的int值是讀取了幾個位元組 System.out.println(new String(arr, 0, temp)); // //寫檔案 FileOutputStream fos = new FileOutputStream("file" + File.separator + "1024.txt",true); //如果該檔案不存在,則會自動建立 //傳入true會在檔案內容的後面寫入文字,而不會覆蓋之前的內容 //開發中檔案分隔符最好不要直接寫 而是寫 File.separator String msg = "Hello World"; fos.write(" ".getBytes());//換行,並向檔案寫入 String.getBytes() 因為要以位元組的形式傳入 fos.write(msg.getBytes()); String msg = "好好學習"; //一個漢字佔2個位元組,向裡面一次傳入3個位元組會導致亂碼 fos.write(msg.getBytes(), 0, 3); byte[] arr = new byte[6];//一次性寫這麼多位元組 int temp = fis.read(arr); fos.write(arr, 0, temp); fos.flush();//重新整理 //新的jdk7寫法是在try括號()裡面寫檔案的連結, 這樣最後就不用關閉了,會自動關閉 //緩衝輸入流底層預設建立一個大小是8192長度的byte陣列 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("java.txt")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("file" + File.separator + "good.txt")); int temp = bis.read();//temp依然為ascii瑪 每次一個
一些練習
利用BufferedInputStream 和 BufferedOutputStream 實現將一個檔案copy到另一個檔案
package com.wpbxx.stream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class BufferFileCopy { public static void main(String[] args) { BufferedInputStream bis = null; BufferedOutputStream bos = null; try { bis = new BufferedInputStream(new FileInputStream("java.txt")); bos = new BufferedOutputStream(new FileOutputStream("file" + File.separator + "good.txt")); int temp; while((temp = bis.read()) != -1){ bos.write(temp); } bos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally{ try { bis.close(); bos.close(); } catch (IOException e) { e.printStackTrace(); } } } }
檔案的加密 將一個位元組異或一個數字實現 在傳輸時進行檔案的加密
package com.wpbxx.stream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class CodeFile { public static void main(String[] args) { //jdk7新寫法 try ( BufferedInputStream bis = new BufferedInputStream(new FileInputStream("圖片.png")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("code.png")); ) { int temp; while((temp = bis.read()) != -1){ bos.write(temp ^ 88); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
檔案解密
package com.wpbxx.stream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class DecodeFile { public static void main(String[] args) { try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("code.png")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("decode.png"));) { int temp; while ((temp = bis.read()) != -1) { bos.write(temp ^ 88); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
字元流的一些操作 可以解決亂碼的問題
//讀 //注意:字元流不能讀取非文字檔案 FileReader fr = new FileReader("java.txt"); int temp; while ((temp = fr.read()) != -1) { System.out.println((char) temp); //一次一個字元 } //使用緩衝字元流 BufferedReader br = new BufferedReader(new FileReader("word.txt")); String msg; while((msg = br.readLine()) != null){ //一次可以讀取一行 System.out.println(msg); } //寫 FileWriter fw = new FileWriter("word.txt"); fw.write("我喜歡學習java"); fw.write(97); BufferedWriter bw = new BufferedWriter(new FileWriter("newbuffered.txt")); bw.write("你好"); bw.newLine();//回車換行 bw.write("java");
同樣是copy檔案
package com.wpbxx.chario; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; /** * 使用緩衝流拷貝檔案 * 注意:字元流不能讀取非文字檔案 */ public class BufferFileCopy { public static void main(String[] args) { try (BufferedReader br = new BufferedReader(new FileReader("java.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("file" + File.separator + "hellojava.txt")); ) { String msg; while((msg = br.readLine()) != null){ bw.write(msg); bw.newLine(); } bw.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } } }
通過java中的File類實現對檔案的一些操作
File file1 = new File("D:\hello.txt"); //如果檔案存在,就不建立了,返回false,如果不存在就會建立,返回true System.out.println(file1.createNewFile()); File file2 = new File("D:\new"); //如果資料夾存在,就不建立了,返回false,如果不存在就會建立,返回true System.out.println(file2.mkdir()); File file3 = new File("D:\wpbxx\1024"); //可以建立多級目錄,如果資料夾存在,就不建立了,返回false,如果不存在就會建立,返回true System.out.println(file3.mkdirs()); File file4 = new File("D:\wpbxx\1024.txt"); //只能建立資料夾 System.out.println(file4.mkdirs()); File file5 = new File("1026.txt"); //如果不寫碟符,會預設在專案的根目錄裡面建立 System.out.println(file5.createNewFile()); System.out.println(file5.exists()); //舊名字 File oldFile1 = new File("D:\world.txt"); //新名字 File newFile1 = new File("D:\wpbxx\java.txt"); //如果兩個檔案路徑不一致,則會將舊檔案剪下到新的檔案路徑中再重新命名 oldFile1.renameTo(newFile1); //不會將檔案放到回收站中,而是直接刪除 File del = new File("D:\wpbxx\java.txt"); File del1 = new File("D:\wpbxx"); //如果資料夾下有其他檔案,則不會刪除 System.out.println(del1.delete()); File file2 = new File("D:\new.txt"); //判斷是否是資料夾 System.out.println(file2.isDirectory()); //判斷是否是檔案 System.out.println(file2.isFile()); //判斷檔案是否存在 System.out.println(file2.exists()); File file3 = new File("D:\hidden"); //判斷檔案是否隱藏 System.out.println(file3.isHidden()); File file1 = new File("1024.txt"); //檢視絕對路徑 System.out.println(file1.getAbsolutePath()); //檔案的大小,單位是位元組 System.out.println(file1.length()); //最後修改時間 Date date = new Date(file1.lastModified()); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); System.out.println(sdf.format(date)); File file2 = new File("F:\wpbxx\程式碼\code\chapter-08"); //獲取目錄下的同級檔案或資料夾的名稱 String[] nameArray = file2.list(); for(String name : nameArray){ System.out.println(name); }
幾個小練習
package com.wpbxx.exercise; import java.io.File; import java.util.Scanner; /** * 問題:從鍵盤接收一個路徑,將這個路徑下的所有檔案和資料夾的名字按照層級列印。 * 例如: * wpbxx * java * XXX.java * XXX.jpg * php * XXX.php * readme.txt * * 分析:獲取路徑File物件中的File陣列 * 遍歷陣列,取得File物件 * 列印檔案或資料夾的名字 * 如果是一個資料夾的話,使用遞迴重複上面的操作 */ public class FileNames { //用來記錄縮排的次數 private static int count = 0; public static void main(String[] args) { File file = getFile(); getFileNames(file); } //每次呼叫該方法時,說明進入到一個新的資料夾的內部,需要增加一個縮排 private static void getFileNames(File file) { //獲取路徑File物件中的File陣列 File[] fileArray = file.listFiles(); //遍歷陣列,取得File物件 for(int i=0; i<fileArray.length; i++){ //通過遍歷count來控制列印幾個縮排 for(int j=0; j<count; j++){ System.out.print(" "); } //列印檔案或資料夾的名字 System.out.println(fileArray[i]); //如果是一個資料夾的話,使用遞迴重複上面的操作 if(fileArray[i].isDirectory()){ count++; getFileNames(fileArray[i]);//陣列遍歷完最後一個File物件時,說明當前資料夾已經遍歷結束,需要做自減運算 count--; } } } //獲取使用者輸入路徑的File物件 private static File getFile() { System.out.println("請輸入一個資料夾路徑:"); Scanner sc = new Scanner(System.in); //獲取使用者輸入的路徑,使用者輸入的路徑有可能是錯誤的,需要進行判斷 while(true){ String input = sc.nextLine(); File file = new File(input); if(!file.exists()){ System.out.println("您輸入的檔案路徑有誤,請重新輸入檔案路徑:"); }else if(file.isFile()){ //如果使用者輸入的路徑是一個檔案 System.out.println("您輸入的路徑是一個檔案,請輸入一個資料夾的路徑"); }else{ return file; } } } }
package com.wpbxx.exercise; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * 問題:收費版軟體有試用次數,利用IO流的知識,模擬一個可以試用3次的功能,開啟3次之後提示使用者購買正版軟體 * * 分析:將試用的次數做加密處理後寫到txt檔案中 * 使用IO流相關的知識將txt檔案中的內容讀取到記憶體中 * 如果讀取的內容小於0時提示使用者購買正版軟體 * 如果大於0小於等於3時,將試用次數做自減運算之後寫出到txt檔案中 */ public class Trial { public static void main(String[] args) { //code(); BufferedInputStream bis = null; BufferedOutputStream bos = null; try { bis = new BufferedInputStream(new FileInputStream("src" + File.separator + "com" + File.separator + "monkey1024" + File.separator + "exercise" + File.separator + "config.txt")); int temp = bis.read(); //解密處理 int count = temp ^ 66; if(count > 0 && count <= 3){ count--; System.out.println("您的試用次數還剩餘" + count + "次"); bos = new BufferedOutputStream(new FileOutputStream("src" + File.separator + "com" + File.separator + "monkey1024" + File.separator + "exercise" + File.separator + "config.txt")); //做加密處理 bos.write(count ^ 66); bos.flush(); }else{ System.out.println("您的試用次數已超出限制,請購買正版軟體!"); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally{ try { //避免出現空指標 if(bis != null){ bis.close(); } if(bos != null){ bos.close(); } } catch (IOException e) { e.printStackTrace(); } } } //試用次數加密處理 private static void code() { BufferedOutputStream bos = null; try { bos = new BufferedOutputStream(new FileOutputStream("src" + File.separator + "com" + File.separator + "monkey1024" + File.separator + "exercise" + File.separator + "config.txt")); //加密處理 bos.write(3 ^ 66); bos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally{ try { //避免出現空指標異常 if(bos != null){ bos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
package com.wpbxx.exercise; import java.io.File; /** * 問題:統計專案根目錄下以.txt結尾的檔案數量,並將檔名列印出來 * 分析:獲取專案根目錄下的檔名 * 對檔名進行判斷是否是以.txt結尾 */ public class FindTxt { public static void main(String[] args) { File file = new File("F:\wpbxx\01-JavaSE\程式碼\code\chapter-08"); File[] fileArray = file.listFiles(); //返回一個File列表就是該目錄下的File列表 //統計出現次數 int count = 0; for(File name : fileArray){ String s = name.toString(); //判斷是否是以.txt檔案結尾 if(s.endsWith(".txt")){ if(name.isFile()){ count++; System.out.println(name); } } } System.out.println("以.txt檔案結尾的數量是" + count + "個"); } }
package com.monkey1024.file; import java.io.File; import java.io.FilenameFilter; /** * 問題:統計專案根目錄下以.txt結尾的檔案數量,並將檔名列印出來 * 使用檔案過濾器實現上述需求 */ public class FilenameFilterTest01 { public static void main(String[] args) { File file = new File("F:\monkey1024\01-JavaSE\程式碼\code\chapter-08"); String[] nameArray = file.list(new FilenameFilter() { @Override public boolean accept(File dir, String name){ //獲取根目錄下每個檔案的File物件 File file1 = new File(dir, name); //編寫篩選條件 return file1.isFile() && file1.getName().endsWith(".txt"); } }); System.out.println("以.txt結尾的檔案個數是" + nameArray.length + "個"); for(String name : nameArray){ System.out.println(name); } } }
package com.wpbxx.file; import java.io.File; import java.io.FilenameFilter; /** * 問題:統計專案根目錄下以.txt結尾的檔案數量,並將檔名列印出來 * 使用檔案過濾器實現上述需求 */ public class FilenameFilterTest01 { public static void main(String[] args) { File file = new File("F:\wpbxx\01-JavaSE\程式碼\code\chapter-08"); String[] nameArray = file.list(new FilenameFilter() {//重寫accept方法 @Override public boolean accept(File dir, String name){//將過濾的規則寫進來 //獲取根目錄下每個檔案的File物件 File file1 = new File(dir, name); //編寫篩選條件 return file1.isFile() && file1.getName().endsWith(".txt"); } }); System.out.println("以.txt結尾的檔案個數是" + nameArray.length + "個"); for(String name : nameArray){ System.out.println(name); } } }
對物件的讀取
為啥要對物件讀取?
平時我們在Java記憶體中的物件,是無 法進行IO操作或者網路通訊的,因為在進行IO操作或者網路通訊的時候,人家根本不知道記憶體中的物件是個什麼東西,因此必須將物件以某種方式表示出來,即 儲存物件中的狀態。一個Java物件的表示有各種各樣的方式,Java本身也提供給了使用者一種表示物件的方式,那就是序列化。換句話說,序列化只是表示對 象的一種方式而已。OK,有了序列化,那麼必然有反序列化,我們先看一下序列化、反序列化是什麼意思。
序列化:將一個物件轉換成一串二進位制表示的位元組陣列,通過儲存或轉移這些位元組資料來達到持久化的目的。
反序列化:將位元組陣列重新構造成物件。
序列化只需要實現java.io.Serializable介面就可以了。序列化的時候有一個serialVersionUID引數,Java序列化機制是通過在執行時判斷類的serialVersionUID來驗證版本一致性的。 在進行反序列化,Java虛擬機器會把傳過來的位元組流中的serialVersionUID和本地相應實體類的serialVersionUID進行比較, 如果相同就認為是一致的實體類,可以進行反序列化,否則Java虛擬機器會拒絕對這個實體類進行反序列化並丟擲異常。serialVersionUID有兩 種生成方式:
摘自:https://www.cnblogs.com/szlbm/p/5504166.html 這個也比較詳細
如果一個類的物件支援序列化和反序列化,需要實現Serializable,Serializable中沒有任何方法,只是相當於一個標記
有一個類
package com.monkey1024.serializable; import java.io.Serializable; /** * 如果一個類的物件支援序列化和反序列化,需要實現Serializable * Serializable中沒有任何方法 */ public class Student implements Serializable{ /** * 自動生成序列化版本號 */ private static final long serialVersionUID = -716323668524282676L; private String name; //新增屬性後,使用反序列化時會報出InvalidClassException //transient修飾的變數不會被序列化 transient private int age; private boolean sex; public boolean isSex() { return sex; } public void setSex(boolean sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
然後我們對這個類進行序列化和反序列化
Student zhangsan = new Student(); zhangsan.setName("張三"); zhangsan.setAge(20); //寫 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("zhangsan")); oos.writeObject(zhangsan); oos.flush(); //讀 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("zhangsan")); Student s = (Student)ois.readObject(); System.out.println(s.getName()); System.out.println(s.getAge());