1. 程式人生 > >《Java程式設計思想》學習筆記14——I/O高階

《Java程式設計思想》學習筆記14——I/O高階

1.記憶體對映檔案:

記憶體對映檔案允許把比記憶體大的檔案讀入記憶體中建立和修改,使用記憶體對映檔案,可以像使用記憶體中陣列一樣在記憶體中訪問整個檔案,例子如下:

  1. import java.nio.*;  
  2. import java.nio.channels.*;  
  3. import java.io.*;  
  4. pulbic class MemoryMappedFile{  
  5.     //十六進位制,128MB大小
  6.     staticint length = 0x8FFFFFF;  
  7.     publicstaticvoid main(String[] args)throws Exception{  
  8.         //通過檔案通道將檔案對映為記憶體中的自己緩衝區
  9.     MappedByteBuffer out = new RandomAccessFile(“test.dat”, “rw”).getChannel()  
  10. .map(FileChannel.MapMode.READ_WRITE, 0, length);  
  11.         for(int i = 0; i < length; i++){  
  12.     out.put((byte)’x’);  
  13. }   
  14. System.out.println(“Finished writing”);  
  15. for(int I = length/2
    ; i < length/2 + 6; i++){  
  16.     System.out.println((char)out.get(i));  
  17. }  
  18. }  
  19. }  

MappedByteBuffer是直接位元組緩衝區,其內容是檔案的記憶體對映區域,對映的位元組緩衝區和它所表示的檔案對映關係在該緩衝區本身成為垃圾回收之前一直保持有效。

FileChannel的MappedByteBuffermap(FileChannel.MapMode mode, long position, long size) thorws IOException方法可以將此通道的檔案區域直接對映到記憶體中。

可以通過以下三種模式將檔案區域對映到記憶體中:

(1).只讀:檢視修改得到的緩衝區將導致丟擲ReadOnlyBufferException。

(2).讀/寫:對得到的緩衝區的更改將最終傳播到檔案,該更改對對映到同一檔案的其他程式不一定是可見的。

(3).專用:對的到的緩衝區更改將不會被傳播到檔案,並且該更改對對映到同一檔案的其他程式也是不可見的,相反,會建立緩衝區已修改部分的專用副本。

建立對映時指定檔案區域對映的起始位置和大小,因此,只有指定的部分才會被影響到記憶體的位元組緩衝區中,而不再指定範圍內的檔案區域不會被對映到記憶體中,因此,對於大型檔案來說,可以大大提高程式效能。

注意:對映關係一經建立,就不再依賴於建立它時所用的檔案通道,特別是關閉該通道對對映關係的有效性沒有任何影響。另外,從效能觀點來講,通常相對較大的檔案對映到記憶體中才是值得的。

2.檔案鎖定:

在同一個JVM中,共享資源的檔案可以通過執行緒同步來確保訪問的安全性,但是在不同的JVM或者Java執行緒和作業系統本地執行緒共同競爭一個共享的檔案資源時,就必須通過對檔案的鎖定機制來確保,例子如下:

  1. import java.nio.channels.*;  
  2. import java.util.concurrent.*;  
  3. import java.io.*;  
  4. publicclass FileLocking{  
  5.     publicstaticvoid main(String[] args)throws Exception{  
  6.     FileOutputStream fos = new FileOutputStream(“file.txt”);  
  7.     //試圖對檔案通道的檔案鎖定
  8.     FileLock fl = fos.getChannel().tryLock();  
  9.     //檔案鎖定成功
  10.     if(fl != null){  
  11.     System.out.println(“Locked File”);  
  12.     TimeUnit.MILLISECONDS.sleep(100);  
  13.     //釋放檔案鎖
  14.     fl.release();  
  15.     System.out.println(“Released Lock”);  
  16. }  
  17. foc.close();  
  18. }  
  19. }  

輸出結果:

Locked File

Released Lock

檔案通道的tryLock()方法試圖獲取對此通道的檔案給定區域的鎖定,是個非阻塞方法,無論是否已成功獲得請求區域的鎖定,呼叫總是立即返回。如果由於另一個程式保持這一個重疊鎖而無法鎖定,則此方法返回null.

檔案鎖定方法:

(1).FileLock tryLock():

試圖獲取對此通道檔案的獨佔鎖定。

(2).FileLock tryLock(long position, long size, Boolean shared):

檢視獲取對此通道檔案給定區域的鎖定。

(3).FileLock lock():

獲取此通道的檔案的獨佔鎖定。

(4).FileLock lock(long position, long size, Boolean shared):

獲取此通道的檔案的給定區域鎖定。

檔案鎖定方法是共享鎖還是排斥鎖取決於底層作業系統,可以使用FileLock.isShared()方法判斷使用的是何種型別的檔案鎖。

3.壓縮/解壓縮:

Java I/O類庫中提供了一些關於壓縮和加壓的類,由於壓縮和解壓縮演算法是針對位元組資料進行操作的,因此javaI/O中關於壓縮和加壓素的類是繼承自InputStream和OutputStream位元組流體系。

Java壓縮和解壓的相關類在java.util.zip包下,具體的類如下:

需要維護所讀取資料校驗和的輸入流,校驗和可用於驗證輸入資料的完整性。

(2).CheckedOutputStream:

需要維護所寫入資料校驗和的輸出流。

(3).Deflater:

使用流行的”ZLIB”壓縮程式庫為通用壓縮提供支援。

(4).Inflater:

使用流行的”ZLIB”壓縮程式庫為通用解壓縮提供支援。

(5).DeflaterInputStream:

為壓縮“deflate“格式壓縮資料實現輸入流過濾器。

(6).DeflaterOutputStream:

為壓縮 “deflate“格式壓縮資料實現輸出流過濾器,它還用作其他型別的壓縮過濾器(如GZIPOutputStream)的基礎。

(7).InflaterInputStream:

為解壓縮”deflate”壓縮格式的資料實現輸入流過濾器,它還用作其他解壓縮過濾器(如GZIPInputStream)的基礎。

(8).InfaterOutputStream:

為解壓縮“deflate”壓縮格式儲存資料實現輸出流過濾器。

(9).ZipOutputStream:

為以”zip”檔案格式寫入檔案實現輸出流過濾器,包括對已壓縮和未壓縮條目的支援。

(10).ZipInputStream:

為讀取以”zip”檔案格式的檔案實現輸入流過濾器,包括對已壓縮和未壓縮條目的支援。

(11).GZIPOutputStram:

為使用“GZIP“檔案格式寫入壓縮資料實現輸出流過濾器。

(12).GZIPInputStram:

為讀取“GZIP“檔案格式的壓縮資料實現輸入流過濾器。

Java I/O壓縮和解壓縮操作小例子如下:

  1. import java.util.zip.*;  
  2. import java.io.*;  
  3. publicclass GZIPCompress{  
  4.     publicstaticvoid main(String[] args)throws IOException{  
  5.     BufferedReader in = new BufferedReader(new FileReader(“test.dat”));  
  6.     BufferedOutputStream out = new BufferedOutputStream(new GZIPOutputStream(  
  7. new FileOutputStream(“test.gz”)));  
  8.         int c;  
  9.         //寫GZIP格式壓縮檔案
  10.         while((c = in.read()) != -1){  
  11.     out.write(c);  
  12. }  
  13. in.close();  
  14. out.close();  
  15. BufferedReader in2 = new BufferedReader(new InputStreamReader(  
  16. new GZIPInputStream(new FileInputStream(“test.gz”))));  
  17.         String s;  
  18.         //讀取GZIP格式壓縮檔案
  19.         while((s = in2.readLine()) != null){  
  20.     System.out.println(s);  
  21. }  
  22. in2.close();  
  23. }  
  24. }  

使用java中壓縮相關類時,只需對輸入流使用GZIPInputStream或ZipInputStream包裝,對輸出流使用GZIPOutputStream或ZipOutputStream包裝即可,其他的操作和普通的java I.O操作相同。

4.使用zip多檔案壓縮:

zip格式的壓縮檔案是最常用的壓縮方式,使用zip多檔案壓縮時,可以將多個檔案壓縮在一個壓縮包中,同時還可以從一個包含多個檔案的壓縮包中讀取所有的壓縮檔案。使用zip進行多檔案壓縮時,一般要使用CheckSum類計算校驗和,校驗和的計算有兩種演算法:

(1).Adler32:速度比較快。

(2).CRC32:速度比較慢,但是更精確。

使用zip多檔案壓縮的例子如下:

  1. import java.util.zip.*;  
  2. import java.io.*;  
  3. import java.util.*;  
  4. publicclass ZipCompress{  
  5.     publicstaticvoid main(String[] args)throws Exception{  
  6.         FileOutputStream f = new FileOutputStream(“test.zip”);  
  7.         //使用Adler32演算法為檔案輸入流產生輸出校驗和檔案
  8.         CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());  
  9.         ZipOutputStream zos = new ZipOutputStream(csum);  
  10.         BufferedOutputStream out = new BufferedOutputStream(zos);  
  11.         //設定zip檔案註釋
  12.         zos.setComment(“A test of java zipping”);  
  13.         //向zip壓縮檔案寫入多個檔案
  14.         for(String arg : args){  
  15.     System.out.println(“Writing file:” + arg);  
  16. BufferedReader in = new BufferedReader(new FileReader(arg));  
  17.             //寫入一個zip檔案條目,並將流定位到條目資料的開始處
  18.             zos.putNextEntry(new ZipEntry(arg));  
  19.             int c;  
  20.             //寫入zip檔案內容
  21.             while((c = in.read()) != -1){  
  22.                 out.write(c);  
  23. }  
  24. in.close();  
  25. out.flush();  
  26. }  
  27.         out.close();  
  28. //檔案關閉後獲取校驗和
  29. System.out.println(“Checksum:” + csum.getChecksum().getValue());  
  30. FileInputStream fi = new FileInputStream(“test.zip”);  
  31. //使用Adler32演算法為輸入檔案流產生輸入校驗和檔案流
  32. CheckedInputStream csumi = new CheckedInputStream(fi, new Adler32());  
  33. ZipInputStream in2 = new ZipInputStream(csumi);  
  34. BufferedInputStream bis = new BufferedInputStream(in2);  
  35. ZipEntry ze;  
  36. //讀取zip檔案條目
  37. While((ze = in2.getNextEntry()) != null){  
  38.     System.out.println(“Reading file:” + ze);  
  39. int x;  
  40.     //讀取zip檔案條目內容
  41.     while((x = bis.read()) != -1){  
  42.     System.out.println(x);  
  43. }  
  44. }  
  45. if(args.length == 1){  
  46.     System.out.println(“Checksum:” + csumi.getChecksum().getValue());  
  47. }  
  48. bis.close();  
  49. //另一種讀取zip檔案的方法
  50. ZipFile zf = new ZipFile(“test.zip”);  
  51. //獲取zip檔案的條目
  52. Enumeration e = zf.entries();  
  53. 相關推薦

    Java程式設計思想學習筆記14——I/O高階

    1.記憶體對映檔案: 記憶體對映檔案允許把比記憶體大的檔案讀入記憶體中建立和修改,使用記憶體對映檔案,可以像使用記憶體中陣列一樣在記憶體中訪問整個檔案,例子如下: import java.nio.*;   import java.nio.channels.*;  

    Java程式設計思想學習筆記-第11章

    .title { text-align: center; margin-bottom: .2em } .subtitle { text-align: center; font-size: medium; font-weight: bold; margin-top: 0 } .todo { font-famil

    JAVA程式設計思想學習筆記(一)

    物件導論 1.1 抽象過程 Smalltalk的五個基本特性: 萬物皆為物件。 程式是物件的集合,它通過傳送訊息來告知彼此所要做的。 每個物件都有自己的由其他物件所構成的儲存。 每個物件都有其型別。 某一特定型別的所有物件都可以接受同樣的訊息。

    java程式設計思想學習筆記——第1章 物件導論

    1.1 抽象過程 面向物件思想的實質:程式可以通過新增新型別的物件使自身適用於某個特定問題。 面向物件思想的五個基本特徵: 1)萬物皆物件 2)程式是物件的集合 3)每個物件都有自己的由其他物件所構成的儲存 4)每個物件都有其型別 5)某一特定型別的所有物件都可以接收同樣的訊息 物件具有行為、

    Java程式設計思想筆記14.型別資訊

    執行時型別資訊使得你可以在執行時發現和使用型別資訊,主要有兩種方式: “傳統的”RTTI,它假定我們在編譯時已經知道了所有的型別; “反射”機制,它允許我們在執行時發現和使用類的資訊。 14.1 為什麼需要RTTI RTTI維護型別型別的資訊,為多型機制的實現提供基礎。 14.2 Cla

    java程式設計思想學習筆記——第2章 一切都是物件

    儘管java是基於C的,但是相比之下,java是一種更“純粹”的面向物件程式設計語言。 2.1 用引用操縱物件 一切都視為物件,因此可採用單一固定的語法。儘管這一切都看作物件,但操縱的識別符號實際上是物件的一個“引用(reference)”。 java語言的一個特性:字串可以用帶引號的文字初始化。通常,

    java程式設計思想學習筆記:初始&過載&this&static

    構造器初始化 構造器 ,採用與類相同的名稱,建立物件時,自動呼叫構造器來初始化物件 預設構造器(無參構造器):不接受任何引數的構造器 構造器也可帶引數,指定如何建立物件 當類中沒有構造器,編譯器會自動建立一個預設構造器; 當類中已經定義了一個構造

    JAVA程式設計思想學習筆記(三)操作符

    操作符 別名問題 先來看段程式碼,猜猜最後輸出的是什麼: class Test{ int t; } public class A { public static void main(String[] args) { // TODO Auto-gener

    JAVA程式設計思想學習筆記(八)介面

    介面 抽象類和抽象方法 抽象方法:這種方法不完整,僅有宣告而沒有方法體。所採用的語法如下: abstract void f(); 抽象類:包含抽象方法的類叫做抽象類,如果一個類包含一個或多個抽象方法,該類必須被限定為抽象的。 介面 關鍵字:interface 介面定

    JAVA程式設計思想學習筆記(七)多型

    多型 繫結 繫結: 將一個方法呼叫同一個方法主體關聯起來被稱作繫結。 前期繫結: 若在程式執行前進行繫結,叫做前期繫結,它是面嚮物件語言不需要選擇就預設的繫結方式。 後期繫結: 它的含義就是在執行時根據物件的型別進行繫結,也叫做動態繫結或執行時繫結。java中除了static和fin

    JAVA程式設計思想學習筆記(六)複用類

    複用類 組合語法 組合語法就是在類中用其他類的物件作為本類的成員變數。 編譯器不會為每一個引用都建立預設物件,想要初始化引用,可以在下列位置進行: 在定義物件的地方 在類的構造器中 在使用物件之前,惰性初始化 使用例項初始化 繼承語法 關鍵

    JAVA程式設計思想學習筆記(五)訪問許可權控制

    訪問許可權控制 包:庫單元 打包關鍵字:package 匯入關鍵字:import package必須是除註釋以外的第一句程式程式碼。 java直譯器的執行過程: 找出環境變數CLASSPATH。 CLASSPATH包含一個或多個目錄,用作查詢.class檔案

    JAVA程式設計思想學習筆記(四)初始化與清理

    初始化與清理 用構造器確保初始化 JAVA採用和C++相同的方案,即構造器採用與類相同的名稱,在建立物件時,將會為物件分配儲存空間,並呼叫同名的構造器,達到確保初始化的目的。 構造器是一種特殊的方法,它是沒有返回值的,與返回值為空(void)不同。 另外,如果自己沒有實現構造器,就會

    JAVA程式設計思想學習筆記(二)一切都是物件

    一切都是物件 用引用操作物件 用一個類名,宣告一個變數,就是聲明瞭一個引用,比如類String String s; s就是類String的一個引用,引用並不是一個物件,但是它是可以控制相應的物件,相當於遙控器。引用不會分配儲存空間,new個物件之後才會分配空間。 必須由

    JAVA程式設計思想學習筆記(十一)容器類List

    容器類 在《java程式設計思想》一書中,容器類本是在持有物件那一章節裡面的,這裡我特意給提出來了,因為內容程式碼比較多,與其放一起顯得太臃腫,倒不如這樣來的清爽些。 List List承諾可以將元素維護在特定的序列中,List介面在Collection的基礎上添加了大量的方法,

    Java程式設計思想學習筆記——第7章 複用類

    7.8 final關鍵字 final指得是“這是無法改變的”。不想做改變可能出於兩種理由:設計或效率。 可能使用到final的三種情況:資料、方法和類。 7.9初始化及類的載入 載入時眾多變得更加容易的動作之一,因為Java中的所有事物都是物件。請記住,每個類的編譯程

    Java程式設計思想學習筆記3

    本章內容承接“Java程式設計思想 - 18.1 - 位元組流和字元流”。JDK 1.4引入了新的Java IO類庫java.nio.*旨在提高IO速度。筆者愚鈍,認為NIO是Java程式設計思想第18章中最難理解的部分,Eckel在這部分內容的安排上也讓人難以

    Java程式設計思想學習(一)----物件導論中多型的理解

    1.1抽象過程 1)萬物皆物件。 2)程式是物件的集合,他們通過傳送訊息來告知彼此所要求做的。 3)每個物件都有自己的由其他物件所構成的儲存。 4)每個物件都擁有其型別。 5)某一特定型別的所有物件都可以接收同樣的訊息。 上面是書上總結的內容,具體程式碼如下: //每個物件都有一個介面,介

    Java程式設計思想學習(二)----一切都是物件

    2.1用應用操作物件 String s; 這裡所建立的只是引用,並不是物件。如果此時向s傳送一個訊息,就會返回一個執行時錯誤。這是因為此時s沒有和任何事物關聯。因此,一種安全的做法是:建立一個引用的同時便進行初始化。 2.2必須由你建立所有物件 一旦建立了一個引用,就希望它能與一個新的物件相關聯。通常

    java程式設計思想讀書筆記二(物件的建立)

    java物件 物件的建立 java的物件是在執行時建立的,建立物件的的觸發條件有以下幾種: 用new語句建立物件,這是最常用的建立物件方法。 運用反射手段,呼叫java.lang.reflect.Constructor類的newInstance()例項方法。