1.File的操作
/** * java.io.File * File 的每一個實例用來表示硬盤上的一個文件或目錄 * 我們通過File可以: * 1:訪問一個文件或目錄的屬性信息。 * 文件名,大小,修改日期,訪問權限等 * 2:可以創建文件,刪除文件,創建目錄,刪除目錄 * 3.可以訪問目錄中的所有子項 * 但是不能: * 不能訪問文件數據 * @author lenovo * */ public class FileDemo { public static void main(String[] args) throws IOException { /** * 盡量使用相對路徑 * 在eclipse中,"." 當前目錄,指的是項目的根目錄。 * */ File file = new File("."+File.separator+"FileDir"+File.separator+"test.txt"); //獲取文件屬性 String name = file.getName(); System.out.println("name:"+name); /** * 獲取大小 * 返回值為一個long值,表示占用的字節量 */ long length = file.length(); System.out.println("l:"+length); //最后修改時間 long time = file.lastModified(); Date date = new Date(time); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("last date :"+sdf.format(date)); //判斷是否可運行,可讀,可寫 權限 返回boolean值 System.out.println(file.canExecute()); System.out.println(file.canRead()); System.out.println(file.canWrite()); //判斷當前File對象表示的是否為一個文件 boolean isFile = file.isFile(); System.out.println("isFile:"+isFile); //是否是文件夾 boolean isDir = file.isDirectory(); System.out.println("isDir:"+isDir); //是否隱藏 System.out.println(file.isHidden()); //創建文件 File file2 = new File("."+File.separator+"FileDir"+File.separator+"creat.txt"); if(!file2.exists()){ file2.createNewFile(); System.out.println("文件creat.txt創建成功"); } //刪除文件 File file3 = new File("."+File.separator+"FileDir"+File.separator+"del.txt"); if(file3.exists()){ file3.delete(); System.out.println("刪除del文件成功!"); } //創建目錄 File dir = new File("."+File.separator+"FileDir"+File.separator+"aa"); if(!dir.exists()){ dir.mkdir(); System.out.println("創建aa目錄成功!"); } //創建多級目錄 File dir2 = new File("."+File.separator+"FileDir"+File.separator +"aa"+File.separator+"c"+File.separator+"d"); if(!dir2.exists()){ dir2.mkdirs(); System.out.println("make dirs"); } //刪除目錄 刪除目錄,只能刪除空目錄 File dir3 = new File("."+File.separator+"FileDir"+File.separator +"aa"+File.separator+"c"+File.separator+"d"); if(dir3.exists()){ dir3.delete(); System.out.println("刪除d目錄"); } //獲取一個目錄下的所有子項 File dir4 = new File("."+File.separator+"FileDir"); File [] files = dir4.listFiles(); for(File f : files){ System.out.println((f.isFile() ? "文件:" :"目錄:")+f.getName()); } //獲取過濾之后的文件 File dir5 = new File("."+File.separator+"FileDir"); File [] fs = dir4.listFiles(new FileFilter() { public boolean accept(File file) { System.out.println("正在過濾:"+file.getName()); return file.getName().startsWith("t"); } }); for(File f : fs){ System.out.println("t開頭的文件有:"+f.getName()); } //遞歸刪除目錄所有文件 File dir6 = new File("."+File.separator+"FileDir"+File.separator+"b"); deleteFile(dir6); } //遞歸刪除文件 public static void deleteFile(File file){ if(file.isDirectory()){ File[] files = file.listFiles(); for(File f : files){ deleteFile(f); } } file.delete(); } }
2.RandomAccessFile操作
/** * java.io.RandomAccessFile * RandomAccessFile 專門用來讀寫文件數據 * @author lenovo * */ public class RandomAccessFileDemo { @Test public void demo07() throws IOException{ RandomAccessFile src = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"2.doc", "rw"); RandomAccessFile desc = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"3.doc", "rw"); byte[] b = new byte[1024*10]; int len = -1; long start =System.currentTimeMillis(); while((len = src.read(b)) != -1){ /** * void write(byte[] data,int offset,int len) * 將當前數組中從offset指定位置開始,連續len個字節寫出 */ desc.write(b, 0, len); } long end = System.currentTimeMillis(); System.out.println("耗時:"+(end-start)); src.close(); desc.close(); } @Test public void demo06() throws IOException{ RandomAccessFile raf = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"c.txt", "rw"); RandomAccessFile raf2 = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"copy_of_c.txt", "rw"); int d = -1; while((d = raf.read()) != -1){ raf2.write(d); } System.out.println("復制完成"); raf.close(); raf2.close(); } @Test public void demo05() throws IOException{ RandomAccessFile raf = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"raf.txt", "rw"); /** * RandomAccessFile 的讀寫操作都是基於指針操作的 * 總是在指針當前位置進行讀寫操作,無論是讀還是寫,操作完畢后,指針都會向后自動移動。 * 新建的RandomAccessFile指針默認在文件的第一個字節上。 * 我們可以通過操作指針位置來讀寫具體位置上的字節內容。 * 指針----字節。 */ long pos = raf.getFilePointer(); System.out.println("指針位置:"+pos); int max = Integer.MAX_VALUE; /** 寫入一個字節 低八位 * max: vvvvvvvv write()低八位。 * 01111111 11111111 11111111 11111111 * max>>>24 左邊補0,右邊溢出不管 */ raf.write(max>>>24); pos = raf.getFilePointer(); System.out.println("指針位置:"+pos); raf.write(max>>>16); raf.write(max>>>8); pos=raf.getFilePointer(); System.out.println("指針位置:"+pos); raf.write(max); //上面寫入了int的最大值 raf.writeInt(max); pos = raf.getFilePointer(); System.out.println("指針位置:"+pos); raf.writeDouble(1.234); pos = raf.getFilePointer(); System.out.println("指針位置:"+pos); raf.writeLong(123L); pos = raf.getFilePointer(); System.out.println("指針位置:"+pos); /** * RandomAccessFile 提供了可以操作指針位置的方法 * void seek(long pos) * 將指針移動到指定位置 */ raf.seek(0); /** * 讀取基本類型數據 * 連續讀取4個字節,並將對應int值返回,若讀取到文件末尾了, * 則拋出EOFException(End of File) */ int i = raf.readInt(); System.out.println(i); i = raf.readInt(); System.out.println(i); double d = raf.readDouble(); System.out.println(d); long l = raf.readLong(); System.out.println(l); /** * void skipByte(int n) * 忽略給定字節量 * 與seek不同點主要有兩個: * skipByte只能向后忽略 * skipByte給定的是相對值 * * skipByte在流的使用中很常用 * RandomAcessFile比較常用seek。 */ raf.seek(0); raf.skipBytes(8); d = raf.readDouble(); System.out.println(d); raf.close(); } @Test public void demo04() throws IOException{ RandomAccessFile raf = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"raf.txt", "rw"); byte [] bytes = new byte[100]; int len = raf.read(bytes); System.out.println(len); /** * 該構造方法允許我們將給定的字節數組中指定范圍內的字節轉換為對應的字符串 */ String str = new String(bytes, 0, len, "UTF-8"); System.out.println(str); raf.close(); } @Test public void demo03() throws IOException{ RandomAccessFile raf = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"raf.txt", "rw"); /** * * 批量寫出字節 * void write(byte [] data) * 一次性將給定的字節數組中的所有字節寫出 */ String str = "摩擦摩擦,是魔鬼的步伐"; /** * byte [] getByte()----上面輸出22個byte * String 提供的該方法可以將當前字符串按照系統默認的字符集轉換為對應的一組字節 * GBK -----2個字節一個中文, UTF-8 3個字節一個中文 * * byte [] getByte(String charset) * 按照給定的字符集將字符串轉換為一組字節 * 字符集: * GBK--:國標編碼,中文2個字節 * UFT-8--:編程編碼集,1-4個字節 ,中文3字節 ,是unicode的一個子集,萬國碼 * ISO8859-1--:歐洲編碼,不支持中文 */ byte [] bytes = str.getBytes("UTF-8"); System.out.println(Arrays.toString(bytes)); raf.write(bytes); System.out.println("寫入完畢"); raf.close(); } @Test public void demo02()throws IOException{ /** * int read() * 讀取一個字節,並以int形式返回 * 若讀取到文件末尾則返回值為-1 */ RandomAccessFile raf2 = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"raf.txt", "r"); int i = raf2.read(); System.out.println(i); raf2.close(); } @Test public void demo01() throws IOException{ /** * RandomAccessFile 創建支持很多模式 * 常用的有: * “r”: 只讀 * “rw” 讀寫 */ RandomAccessFile raf = new RandomAccessFile( "."+File.separator+"FileDir"+File.separator+"raf.txt", "rw"); /** * void write(int d) * 向文件中寫入一個字節,寫的是該int值 * 對應的2進制內容中的“低八位” 0000 0000 255以內 * * 8位2進制是一個字節 * int值4字節,32位2進制 00000000 00000000 000000000 000000000 */ raf.write(12); /** * RandomAccessFile 使用完畢后一定記得關閉來釋放資源。 * jvm gc不管用 * 在底層的程序進行磁盤讀寫,此程序無法被gc回收。 */ raf.close(); } }
3.字符流與字節流的操作
/** * 該類用於測試對象流讀寫對象 * 讀寫對象一般用於: * 保存現有對象到硬盤上 * 在網絡將傳輸對象。 * *接口一般有兩個作用: * 1:約束子類行為(通常含有若干抽象方法,需要子類重寫) * 2:標簽接口,就是給子類打個標簽,不需要為此改變什么,Serializable。 * *當一個類需要序列化時,除了該類自身要實現序列化接口外,其內部定義的自定義類型的屬性也要實現序列化接口才可以。 *但是由Java提供的類不需要,他們通常都實現了序列化接口。 * @author lenovo * */ public class Person implements Serializable { /** * 一個類實現了序列化接口后,通常要自行維護一個常量:serialVersionUID 版本號 * 版本號對於對象反序列化 的策略產生不同影響 * 當我們使用ObjectInputStream對一個對象繼續反序列化的時候, * 該流會檢查待反序列化的對象與該類聲明的版本號是否一致: * 一致:可以反序列化 * 不一致:不可以反序列化 * * 版本號一致時,若待序列化的對象與當前類現有的定義發生沖突(屬性結構有變化了),則啟用兼容模式: * 待反序列化對象原有的屬性,現在類沒有了,則忽略該屬性的值。 * * 帶反序列化對象沒有的屬性,現在類有的,則使用該屬性默認值,其他原樣還原。 */ private static final long serialVersionUID = 1L; private String name; private int age; private String gender; /** * transient 關鍵字修飾的屬性,序列化時被忽略,達到對象“瘦身"的目的。 */ private transient List<String> otherInfo; public Person(){ } public Person(String name, int age, String gender, List<String> otherInfo) { super(); this.name = name; this.age = age; this.gender = gender; this.otherInfo = otherInfo; } 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; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public List<String> getOtherInfo() { return otherInfo; } public void setOtherInfo(List<String> otherInfo) { this.otherInfo = otherInfo; } public String toString(){ return name+","+age+","+gender+","+otherInfo; } }
public class InputAndOutputDemo { @Test public void demo11()throws IOException{ /** * PrintWriter提供了用於處理其他流的構造方法,既可以處理字符流,也可以處理字節流。 */ FileOutputStream fis = new FileOutputStream("."+File.separator+"FileDir"+File.separator+"buffRW.txt"); /** * 可以直接將字節流包裝為緩沖字符輸出流 * 但是不足的地方在於,不能按照指定字符集將字符寫出,而必須用系統默認字符集。 */ //PrintWriter pw = new PrintWriter(fis); OutputStreamWriter osw = new OutputStreamWriter(fis, "UTF-8"); /** * 當我們使用第一個參數為流的構造方法創建PrintWriter時,它還支持一個重載的構造方法, * 允許我們傳入第二個參數,該參數為boolean類型。若該值為true,則創建的PrintWriter具有 * 自動行刷新: * 每當調用println()方法寫出一行內容后都會自動調用flush將其寫出 * 這樣做會降低寫出效率,但是可以保證寫出的及時性。 */ //PrintWriter pw = new PrintWriter(osw, true); PrintWriter pw = new PrintWriter(osw); pw.println("你在南方的寒夜里大雪紛飛"); pw.println("我在北方的艷陽里四季如春"); pw.close(); } @Test public void demo10()throws IOException{ /** * java.io.PrintWriter * 緩沖字符輸出流,特點是可以以行為單位寫出字符串,並且該流還具備自動行刷新功能。 * * 傳統的緩沖字符輸出流是BufferedWriter。 * 由於PrintWriter在創建的時候內部使用了該流,並且PrintWriter還具有自動行刷新,所以比較常用。 * * PrintWriter提供了若干構造方法,可以方便快速創建 * @author lenovo * */ /** * PrintWriter 可以直接創建基於文件的寫操作: * PrintWriter(File file) * PrintWriter(String path) */ PrintWriter pw = new PrintWriter("."+File.separator+"FileDir"+File.separator+"buffRW.txt","UTF-8"); pw.println("哈哈"); pw.write("hehe"); pw.println("不行不行"); pw.close(); } @Test public void demo09() throws IOException{ /** * java.io.BufferedReader-------。字符流。 * 緩沖字符輸入流 特點:以行為單位讀取字符串 * @author lenovo * */ FileInputStream fis = new FileInputStream("."+File.separator+"FileDir"+File.separator+"buffRW.txt"); InputStreamReader isr = new InputStreamReader(fis,"UTF-8"); BufferedReader br = new BufferedReader(isr); /** * String readLine() * BufferedReader 提供的該方法會讀取若干字符,直到讀取到換行符位置, * 然后將換行符之前讀取的這若干字符組成一個字符串返回 * 需要注意,返回的字符串中是不包含換行符的! * 若返回值為null,說明讀取到未見末尾了。 */ String line = null; while((line = br.readLine()) != null){ System.out.println(line); } br.close(); } @Test public void demo08()throws IOException{ /** * 轉碼: * 比如將UTF-8編碼的文本轉換為GBK編碼的文本文件 * 原理: * 使用UTF-8編碼將每一個字符讀取出來,再以GBK編碼將字符寫入另一個文件即可。 * @author lenovo * */ FileInputStream fis = new FileInputStream("."+File.separator+"FileDir"+File.separator+"osw.txt"); InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); FileOutputStream fos = new FileOutputStream("."+File.separator+"FileDir"+File.separator+"osw_GBK.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK"); char [] cr= new char[1024*5]; int len = -1; while((len = isr.read(cr)) != -1){ osw.write(cr, 0, len); } System.out.println("完成轉碼"); isr.close(); osw.close(); } @Test public void demo07()throws IOException{ /** * Reader 字符輸入流 特點:以字符為單位讀取數據 * InputStreamReader 是其常用實現類,作用是可以按照指定的字符集讀取字符。 * */ FileInputStream fis = new FileInputStream("."+File.separator+"FileDir"+File.separator+"osw.txt"); InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); int len = -1; while((len = isr.read()) != -1){ System.out.println((char)len); } isr.close(); } @Test public void demo06()throws IOException{ /** * 字符流: * 以字符為單位讀寫內容,所以字符流只能讀寫文本數據! * 字符流都是高級流,字符與字節之間的轉換交給字符流來干,底層實際還是要讀寫字節的。 * Writer 字符輸出流,特點:以字符為單位寫出數據, * OutputStreamWriter:字符流的一個常用實現類。特點是可以按照指定的字符集將給定的字符串 * 轉換為對應字節后寫出。 * */ FileOutputStream fos = new FileOutputStream("."+File.separator+"FileDir"+File.separator+"osw.txt"); /** * 常用構造方法: * OutputStreamWriter(OutputStream out) * 按照系統默認字符集將字符串轉換為字節后寫出 * * OutputStreamWriter(OutputStream out ,String charsetName) * 按照給定的字符集將字符串轉換為字節后寫出。 */ OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); osw.write("哈哈,你好。"); osw.write("什么意思?"); osw.close(); } @Test public void demo05() throws IOException{ /** * BIS 與BOS * 緩沖字節輸入流,緩沖字節輸出流 * 這是一對高級流,作用是可以提高讀寫效率 */ FileInputStream fis = new FileInputStream("."+File.separator+"FileDir"+File.separator+"heike.mp4"); FileOutputStream fos = new FileOutputStream("."+File.separator+"FileDir"+File.separator+"heike_2.mp4"); BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); int len = -1; while((len = bis.read()) != -1){ bos.write(len); } System.out.println("復制完成"); bis.close(); bos.close(); } @Test public void demo04()throws IOException{ FileInputStream fis = new FileInputStream("."+File.separator+"FileDir"+File.separator+"2.doc"); FileOutputStream fos = new FileOutputStream("."+File.separator+"FileDir"+File.separator+"3.doc"); byte [] data = new byte[1024*10]; int len = -1; while((len=fis.read(data)) != -1){ fos.write(data, 0, len); } System.out.println("復制完畢"); fis.close(); fos.close(); } @Test public void demo03()throws IOException{ FileOutputStream fos = new FileOutputStream("."+File.separator+"FileDir"+File.separator+"BOF.txt"); BufferedOutputStream bof = new BufferedOutputStream(fos); String str = "我愛你我的家"; bof.write(str.getBytes()); /** * void flush() * 緩沖流都提供了flush的實現。作用是強制將現有緩沖數組中的數據一次性寫出。 * 頻繁調用該方法會提高寫出次數從而降低寫出效率,但是當我們需要有寫出數據及時性的時候就要使用。 */ bof.flush(); bof.close(); } @Test public void demo02()throws IOException, ClassNotFoundException{ /** * java.io.ObjectOutputStream * 高級流,功能是將給定的一個對象轉換為一組字節 * 然后通過其處理的流將字節寫出。 */ FileOutputStream fos = new FileOutputStream("."+File.separator+"FileDir"+File.separator+"person.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); Person p = new Person(); p.setAge(23); p.setName("大神"); p.setGender("男"); List<String> list = new ArrayList<>(); list.add("不知道啥"); list.add("啥也不知道"); p.setOtherInfo(list); /** * void writeObject(Object obj) * 該方法會將給定的對象轉換為一組字節然后寫出 * * 序列化: * 將一個數據結構轉換為一組字節的過程。 * * 將內存中的數據寫入硬盤長久保存的過程稱之為:持久化。 * */ oos.writeObject(p); oos.close(); /** * java.io.ObjectInputStream * 高級流,可以進行對象的反序列化 * 將一組字節還原回對象,前提是這一組字節必須是由ObjectOutputStream將一個對象序列化后的字節。 */ FileInputStream fis = new FileInputStream("."+File.separator+"FileDir"+File.separator+"person.obj"); ObjectInputStream ois = new ObjectInputStream(fis); /** * Object readObject() * 改方法會讀取若干字節,然后將其反序列化回對象。 * 並以Object形式返回,需要自己強制類型轉換 */ Person pers = (Person) ois.readObject(); System.out.println(pers); ois.close(); } @Test public void demo01()throws IOException{ /** * java.io.FileOutputStream * 文件字節輸出流,用於將數據寫入到文件中的流 * 該流是一個低級流 * 低級流特點: * 數據的來源和去向是明確的,真實負責"搬運"數據的流 */ File file = new File("."+File.separator+"FileDir"+File.separator+"fos.txt"); /** * 向文件中寫出數據 * 一個參數的構造方法: * FileOutputStream(String path) * FileOutputStream(File file) * 創建出來的文件輸出流是覆蓋寫操作,若操作的文件中有數據,會先將數據清除, * 重寫本次寫出的數據。。。 * (File 對象) * * 若希望追加寫操作,則需要傳入第二個參數 * 是一個boolean值,為true即可。 * FileOutputStream(File file ,boolean append) * FileOutputStream(String path ,boolean append) * */ FileOutputStream fos = new FileOutputStream(file,true); String str = "這些年過的怎么樣?"; fos.write(str.getBytes("UTF-8")); fos.close(); FileInputStream fis = new FileInputStream(file); byte [] buf = new byte[1024*10]; int len = fis.read(buf); System.out.println(new String(buf,0,buf.length,"UTF-8")); fis.close(); } }