java中的printnb_javaI/O系統筆記

1、File類

File類的名字有一定的誤導性;我們可能認為它指代的是文件,實際上卻并非如此。它既能代表一個

特定文件的名稱,又能代表一個目錄下的

一組文件的名稱。

1.1、目錄列表器

如果需要查看目錄列表,可以通過file.list(FilenameFilter)方法來獲取過濾后的文件目錄列表(返回類型是String[])。

例子:https://github.com/xu509/Java-practise/blob/master/src/test/file/directory/DirList2.java

1.2 目錄使用工具

產生文件集的工具類 :

https://github.com/xu509/Java-practise/blob/master/src/test/file/directory/Directory.java

處理文件類:

https://github.com/xu509/Java-practise/blob/master/src/test/file/directory/ProcessFiles.java

1.3 目錄的檢查以及創建 常用File類方法:f.isFile(), f.isDirectory(),f.mkdirs();

2、輸入和輸出

2.1、InputStream類型

InputStream的作用是用來表示那些從不同數據源產生輸入的類。

數據源包括: 1、字節數組。2、String對象。3、文件。4、“管道”,即一端輸入,另一端輸出。5、一個由其他種類的流組成的序列。6、其他數據源,如Internet連接。

其中FilterInputStream為裝飾器類提供基類。

2.2、OutputStream類型

該類別的類決定了輸出所要去往的目標:字節數組、文件或管道。

FilterOutputStream為裝飾器類提供基類。

3、添加屬性和有用的接口

3.1、通過FilterInputStream從InputStream讀取數據

FilterInputStream類能夠完成兩件完全不同的事情。其中,

DataInputStream:允許我們讀取不同的基本類型數據以及String對象。

其他FilterInputStream類則在內部修改InputStream的行為方式:

BufferedInputStream :是否緩沖,可防治每次讀取時都進行實際寫操作。

LineNumberInputStream :跟蹤輸入流的行號,可調用getLineNumber()和setLineNumber(int)。

PushbackInputStream:具有“能彈出一個字節的緩沖區。”因此可以將督導的最后一個字符回退。

3.1、通過FilterInputStream從InputStream讀取數據 以及是否把單一字符推回輸入流等等。

3.2、通過FilterOutPutStream從OutputStream寫入

DataOutputStream? : 可以按照可移植的方式向流中寫入基本類型數據。

PrintStream: 用于格式化輸出打印,具備方法print()和pringln().

BufferedOutputStream:它對數據流使用緩沖技術,可調用flush()清空緩沖區。

4、Reader和Writer

java1.1后加入的,設計Reader和Writer繼承結構主要是為了國際化。老的I/O流繼承層次結構僅支持8位字節流,并且不能很好地處理16位Unicode字符。有時我們必須把來自“字節”層次結構中的類和“字符”層次結構的類結合起來使用。為了實現這個目的,要用到“適配器”類:InputStreamReader可以把InputStream轉換為Reader,而OutputStreamWriter可以把OutputStream轉換為Writer。

4.1、數據的來源和去處

盡量嘗試使用Reader和Writer,一旦程序代碼無法成功編譯,我們就會發現自己不得不使用面向字節的類庫。

來源于去處:Java 1.0 類 相應的 Java 1.1 類InputStream? OutputStream? FileInputStream FileOutputStream StringBufferInputStream(已棄用) 。。Reader 適配器:InputStreamReader Writer 適配器:OutputStreamWriter? FileReader FileWriter StringReader StringWriter

4.2、更改流的行為

過濾器:Java 1.0類相應的Java 1.1類? ? ?FilterInputStream FilterReaderFilterOutputStreamFilterWriter(抽象類,沒有子類)BufferedInputStream? ? ? BufferedReader(有readLine())BufferedOutputStreamBufferedWriterDataInputStream? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DataInputStream,需要readline()時使用BufferedReaderPrintStreamPrintWriterLineNumberInputStream(已棄用)LineNumberReaderStreamTokenizerStreamTokenizer(使用接受Reader的構造器)PushbackInputStreamPushbackReader

4.3、未發生變化的類

DataOutputStream,File,RandomAccessFilemSequenceInputStream

5、自我獨立的類:RandomAccessFile

RandomAccessFile適用于由大小已知的記錄組成的文件,我們可以使用seek()將記錄從一處轉移到另一處,然后讀取或者修改記錄。

RandomAccessFile支持搜尋方法,并且只適用于文件。JDK1.4中,RandomAccessFile的大多數功能由nio存儲映射文件所取代。

6、I/O流的典型使用方式

6.1、緩沖輸入文件

使用BufferedReader的readLine來讀取文件。

public static String

read(String filename) throws IOException {

// Reading input by lines:

BufferedReader in = new BufferedReader(

new FileReader(filename));

String s;

StringBuilder sb = new StringBuilder();

while ((s = in.readLine()) != null)

sb.append(s + "\n");

in.close();

return sb.toString();

}

FileReader來創建輸入流,再通過BufferedReader來裝飾。

例子:https://github.com/xu509/Java-practise/blob/master/src/test/file/excerise/BufferReaderExercise.java

6.2、從內存輸入

使用BufferInputFile.read()讀入的結果來創建StringReader。

public class MemoryInput {

public static void main(String[] args)

throws IOException {

StringReader in = new StringReader(

BufferedInputFile.read("MemoryInput.java"));

int c;

while ((c = in.read()) != -1)

System.out.print((char) c);

}

}

注意in.read()是以int形式返回下一字節,因此必須類型轉換為char才能正確打印。

6.3、格式化的內存輸入 要讀取格式化的數據,可以使用DataInputStream,這是一個面向字節的I/O類(不是面向字符)。

例子:

try {

DataInputStream in = new DataInputStream(

new ByteArrayInputStream(

BufferedInputFile.read(

"file/example3.txt").getBytes()));

while (true)

System.out.print((char) in.readByte());

} catch (EOFException e) {

System.err.println("End of stream");

}

通過捕獲異常來檢測輸入末尾,但這是對異常特性的錯誤使用

DataInputStream in = new DataInputStream(

new BufferedInputStream(

new FileInputStream("file/example3.txt")));

while (in.available() != 0)

System.out.print((char) in.readByte());

6.4、基本的文件輸出 FileWriter對象可以向文件寫入數據。通常會用BufferedWriter將其包裝起來用以緩沖輸出。

例:

static String file = "file/BasicFileOutput.out";

public static void main(String[] args)

throws IOException {

BufferedReader in = new BufferedReader(

new StringReader(

BufferedInputFile.read("src/io/BasicFileOutput.java")));

PrintWriter out = new PrintWriter(

new BufferedWriter(new FileWriter(file)));

int lineCount = 1;

String s;

while ((s = in.readLine()) != null)

out.println(lineCount++ + ": " + s);

out.close();

// Show the stored file:

System.out.println(BufferedInputFile.read(file));

}為了格式化輸出,用PrintWriter裝飾BufferedWriter。

文本輸出的快捷方式

JAVA SE5在PrintWriter中添加了一個輔助構造器,使得不需要每次創建PrintWriter的時候都進行包裝工作。

舊 :

PrintWriter out = new PrintWriter(

new BufferedWriter(new FileWriter(file)));

新:

PrintWriter out = new PrintWriter(file);新舊效果相同,其他常見的寫入任務都沒有快捷方式。

使用緩沖(BufferedReader,BufferedWriter)和不使用的區別:

前者將一部分內存作為緩沖區,使每次操作在內存中操作,而不是直接操作文件,等文件關閉或者緩沖區滿后才往文件中寫。

如果需要大量的讀寫,使用緩沖會提高性能。如果需要立即生效,則不需要用緩沖。

6.5、存儲和恢復數據 我們可以用

DataOutputStream寫入數據,并用

DataInputStream恢復數據。另這2個流都是面向字節的,需用使用InputStream以及OutputStream。

public class StoringAndRecoveringData {

public static void main(String[] args)

throws IOException {

DataOutputStream out = new DataOutputStream(

new BufferedOutputStream(

new FileOutputStream("file/Data.txt")));

out.writeDouble(3.14159);

out.writeUTF("That was pi");

out.writeDouble(1.41413);

out.writeUTF("Square root of 2");

out.close();

DataInputStream in = new DataInputStream(

new BufferedInputStream(

new FileInputStream("file/Data.txt")));

System.out.println(in.readDouble());

// Only readUTF() will recover the

// Java-UTF String properly:

System.out.println(in.readUTF());

System.out.println(in.readDouble());

System.out.println(in.readUTF());

}

}

根據API可以發現,DataOutputStream可以寫入所有基于基本類型的數據。

6.6、讀寫隨機訪問文件 使用RandomAccessFile類似組合使用了DataInpuStream和DataOutputStream。

static String file = "rtest.dat";

static void display() throws IOException {

RandomAccessFile rf = new RandomAccessFile(file, "r");

for (int i = 1; i < 3; i++)

System.out.println(

"Value " + i + ": " + rf.readInt());

System.out.println(rf.readUTF());

rf.close();

}

public static void main(String[] args)

throws IOException {

RandomAccessFile rf = new RandomAccessFile(file, "rw");

for (int i = 1; i < 3; i++)

rf.writeInt(i);

rf.writeUTF("The end of the file");

rf.close();

display();

rf = new RandomAccessFile(file, "rw");

rf.seek(2 * 2);//使用seek在文件中移動 查找精度類型,int2字節,第二個即是2*2

rf.writeInt(9);//修改第二個

rf.close();

display();

構造參數第二個自行選擇:r? - 只讀,rw - 讀寫。

6.7、管道流

PipedInputStream、PipedOutputStream、PipedReader和PipedWriter的價值在于多線程,管道流用于任務之間的通信。

7、文件讀寫的實用工具 因為javaI/O中使用裝飾者模式,使得類使用起來無比復雜,故需要設計添加幫助類完成基本任務。

https://github.com/xu509/Java-practise/blob/master/src/net/mindview/util/TextFile.java

該工具類實現讀取文件為String類型,寫入str等簡單功能。

7.1、讀取二進制文件

public class BinaryFile {

public static byte[] read(File bFile) throws IOException {

BufferedInputStream bf = new BufferedInputStream(

new FileInputStream(bFile));

try {

byte[] data = new byte[bf.available()];

bf.read(data);

return data;

} finally {

bf.close();

}

}

public static byte[]

read(String bFile) throws IOException {

return read(new File(bFile).getAbsoluteFile());

}

}

練習:使用上述工具類,統計文件中字符出現的次數/

統計字節出現的次數:

https://github.com/xu509/Java-practise/blob/master/src/test/file/excerise/RecordKeyMap.java

8、標準I/O 標準I/O既是Unix中的 “程序所使用單一信息流”的概念。程序中所有輸入都可以來自

標準輸入,所有輸出也都可以發送到

標準輸出,所有錯誤信息都可以發送到

標準錯誤。

標準I/O的意義在于:我們可以很容易地把程序串聯起來,一個程序的標準輸出可以成為另一個程序的標準輸入。

8.1、從標準輸入中讀取

JAVA提供了 System.in、System.out和System.err 標準I/O模型。

System.out和System.err已經事先包裝成了printStream對象。

System.in卻是一個沒有包裝過的未經加工的InputStream。所以使用需要對其進行包裝。

包裝步驟:

BufferedReader stdin = new BufferedReader(

new InputStreamReader(System.in));其中InputStreamReader是適配器。

8.2、將System.out轉換成PrintWriter

public class ChangeSystemOut {

public static void main(String[] args) {

PrintWriter out = new PrintWriter(System.out, true);

out.println("Hello, world");

}

} System.out 是一個 PrintStream,也是OutputStream,PrintWriter有一個可以接受OutputStream的構造器。

8.3、標準I/O重定向 java 的 System 類提供了 setIn(InputStream),setOut(PrintStream),setErr(PrintStream) 來對標準輸入、輸出和錯誤I/O流進行重定向。

例子:https://github.com/xu509/Java-practise/blob/master/src/io/Redirecting.java

例子中將標準輸出和標準錯誤重定向到另一個文件,并且在最后恢復了標準輸出。需注意的是,I/O重定向操縱的是字節流。

9、進程控制

提供一個工具類讓java內部執行其他操作系統的程序。

工具類:https://github.com/xu509/Java-practise/blob/master/src/net/mindview/util/OSExecute.java

自定義異常:https://github.com/xu509/Java-practise/blob/master/src/net/mindview/util/OSExecuteException.java

執行類:https://github.com/xu509/Java-practise/blob/master/src/io/OSExecuteDemo.java

10、新I/O

JDK1.4后提供了新的I/O類庫,其目的在于提高速度。

新I/O提出了通道和緩沖器的概念,我們可以把通道理解為一個包含煤層(數據)的礦藏,而緩沖器則是派送到礦藏的卡車。我們只和緩沖器交互,而通道也只和緩沖器交互。

ByteBuffer對象就是唯一與通道交互的緩沖器,可以存儲未加工字節的緩沖器。ByteBuffer用于基礎類型和字節形式的讀取或輸出,但無法輸出或讀取對象,包括字符串類型。

舊I/O類庫中的FileInputStream,FileOutputStream以及RandomAccessFile都被修改,用以產生FileChannel(通道),這些都是字節操縱流,而Reader和Writer就不能用于產生通道;但是Channels類提供了實用方法,用于在通道中產生Reader和Writer。

上述三種流產生通道的例子:

private static final int BSIZE = 1024;

public static void main(String[] args) throws Exception {

// Write a file:

FileChannel fc =

new FileOutputStream("file/nio/data.txt").getChannel();

fc.write(ByteBuffer.wrap("Some text ".getBytes()));

fc.close();

// Add to the end of the file:

fc =

new RandomAccessFile("file/nio/data.txt", "rw").getChannel();

fc.position(fc.size()); // Move to the end

fc.write(ByteBuffer.wrap("Some more".getBytes()));

fc.close();

// Read the file:

fc = new FileInputStream("file/nio/data.txt").getChannel();

ByteBuffer buff = ByteBuffer.allocate(BSIZE);

fc.read(buff);

buff.flip();//告知buff做好被讀取字節的準備

while (buff.hasRemaining())

System.out.print((char) buff.get());

}

注意如果打算使用FileChannel在通知ByteBuffer讀取后執行進一步的read()操作,每當進行read()后都必須使用flip()方法告知緩沖器做好被讀取的準備,我們就必須調用clear()來為下一次的read()做好準備,如下:

public class ChannelCopy {

private static final int BSIZE = 1024;

public static void main(String[] args) throws Exception {

args = new String[2];

args[0] = "file/example3.txt";

args[1] = "file/nio/copy.out";

if (args.length != 2) {

System.out.println("arguments: sourcefile destfile");

System.exit(1);

}

FileChannel

in = new FileInputStream(args[0]).getChannel(),

out = new FileOutputStream(args[1]).getChannel();

ByteBuffer buffer = ByteBuffer.allocate(BSIZE);

while (in.read(buffer) != -1) {

buffer.flip(); // Prepare for writing

out.write(buffer);

buffer.clear();? // Prepare for reading

}

}

}

創建2個通道,一個用于讀,而另一個用于寫,使用緩沖器進行讀寫,注意緩沖器flip(),clear()的使用。

上面程序并不是處理此類問題最理想的方式,特殊方法transferTo()和transferFrom()允許我們將一個通道和另一個通道直接相連。

關鍵代碼:

in.transferTo(0, in.size(), out);

ByteBuffer b = ByteBuffer.allocate(BSIZE);

while (in.read(b,in.size()) != -1) {

b.flip();

in.write(b,in.size()+1);

b.clear();

}

注意通道read和write的改變,以及2個連接方法的用法。

10.1、轉變數據

使用CharBuffer()進行轉換字符,然后通過asCharBuffer()可輸出緩沖器。

例子:https://github.com/xu509/Java-practise/blob/master/src/io/BufferToText.java

對于獲取的字節,要么在寫入文件的時候就轉換成字符,要么就在緩沖器輸出的時候進行編碼轉換為字符。可以使用Charset類來實現功能。

如:(1)

buff.rewind();//返回數據開始部分

String encoding = System.getProperty("file.encoding");

System.out.println("Decoded using " + encoding + ": "

+ Charset.forName(encoding).decode(buff));通過Charset.forName(encoding)獲取Charset對象,然后對緩沖器進行解碼。

(2)

fc = new FileOutputStream("data2.txt").getChannel();

fc.write(ByteBuffer.wrap(

"Some text".getBytes("UTF-16BE")));//輸入時進行編碼

fc.close();在寫入時即使用編碼。

(3)通過CharBuffer向ByteBuffer寫入

buff = ByteBuffer.allocate(24); // More than needed

buff.asCharBuffer().put("Some text");//緩沖器輸出時進行編碼

fc.write(buff);

10.2、獲取基本類型 ByteBuffer只保存字節類型,但可以從其所容納的字節中產生不同的基本類型。

完整例子:

https://github.com/xu509/Java-practise/blob/master/src/io/GetData.java

獲取char:

bb.asCharBuffer().put("Howdy!");

char c;

while ((c = bb.getChar()) != 0)

printnb(c + " ");

獲取short:

bb.asShortBuffer().put((short) 471142);

print(bb.getShort());

bb.rewind();

其中asCharBuffer()和asShortBuffer()都獲取了該緩沖器上的視圖。

10.3、視圖緩沖器(View buffer) 視圖緩沖器可以讓我們通過某個特定的基本數據類型的視窗查看其底層的ByteBuffer。ByteBuffer依然是實際存儲數據的地方,“支持”著前面的視圖,因此,對視圖的任何修改都會映射稱為對ByteBuffer中數據的修改(即視圖的put方法)。

訪問即修改底層ByteBuffer的例子:

public class IntBufferDemo {

private static final int BSIZE = 1024;

public static void main(String[] args) {

ByteBuffer bb = ByteBuffer.allocate(BSIZE);

IntBuffer ib = bb.asIntBuffer();

// Store an array of int:

ib.put(new int[]{11, 42, 47, 99, 143, 811, 1016});

// Absolute location read and write:

System.out.println(ib.get(3));

ib.put(3, 1811);

// Setting a new limit before rewinding the buffer.

ib.flip();

while (ib.hasRemaining()) {

int i = ib.get();

System.out.println(i);

}

}

}

ByteBuffer通過不同的視圖顯示方式也不同

例子 : https://github.com/xu509/Java-practise/blob/master/src/io/ViewBuffers.java

當數據為8字節數組 :

new byte[]{0, 0, 0, 0, 0, 0, 0, 'a'}不同的視圖顯示不同:

Byte Buffer 0 -> 0, 1 -> 0, 2 -> 0, 3 -> 0, 4 -> 0, 5 -> 0, 6 -> 0, 7 -> 97,

Float Buffer 0 -> 0.0, 1 -> 1.36E-43,

Int Buffer 0 -> 0, 1 -> 97,

Long Buffer 0 -> 97,

Short Buffer 0 -> 0, 1 -> 0, 2 -> 0, 3 -> 97,

Double Buffer 0 -> 4.8E-322,Char Buffer 0 -> ,1 -> , 2-> ,3 -> a

字節存放次序:不同的機器可能會使用不同的字節排序方法來存儲數據。“big endian”(高位優先)將最重要的字節放在地址最低的存儲單元。“little endian”(低位優先) 則是將最重要的字節放在地址最高的存儲器單元。當存儲量大于一個字節時,就要考慮字節的順序問題。

ByteBuffer是以高位優先的形式存儲數據的,并且數據在網上傳送時也常常使用高位優先的形式。

我們可以使用帶參數的ByteOrder.BIG_ENDIAN或ByteOrder.LITTLE_ENDIAN的order()方法改變排序方式。

bb.order(ByteOrder.BIG_ENDIAN);完整: https://github.com/xu509/Java-practise/blob/master/src/io/Endians.java

10.4、用緩沖器操縱數據當需要將字節數組寫入文件中時,使用ByteBuffer.wrap()方法將字節數組包裝,使用getChannel方法在FileOutputStream上打開一個通道,接著將緩沖器的數據寫入通道中。

10.5、緩沖器的細節Buffer由數據與4個索引組成,這4個索引hi:mark(標記)、position(位置)、limit(界限)和 capacity(容量)。

flip() : 將limit設置為position,position設置為0。此方法用于準備從緩沖區讀取已經寫入的數據。

remaining(): 返回(limit - position)。

hasRemaining(): 若介于position和limit之間的元素,則返回true()

研究方法對索引影響的例子 : https://github.com/xu509/Java-practise/blob/master/src/io/UsingBuffers.java

10.6、內存映射文件內存映射文件允許我們創建和修改那些因為太大而不能放入內存的文件。有了內存映射文件,我們就可以假定整個文件都放在內存中,而且可以完全把它當做非常大的數組來訪問。

public class LargeMappedFiles {

static int length = 0x8FFFFFF; // 128 MB

public static void main(String[] args) throws Exception {

MappedByteBuffer out =

new RandomAccessFile("file/example1.txt", "rw").getChannel()

.map(FileChannel.MapMode.READ_WRITE, 0, length);

for (int i = 0; i < length; i++)

out.put((byte) 'x');

print("Finished writing");

for (int i = length / 2; i < length / 2 + 20; i++)

printnb((char) out.get(i));

}

}如上圖,為了能同時讀寫大文件,使用RandomAccessFile來獲取通道,然后使用map()方法來產生MappedByteBuffer。

MappedByteBuffer是由ByteBuffer繼承而來,因此它具有ByteBuffer的所有方法。

性能上使用映射文件訪問要比舊的緩沖輸入輸出要高出不少。

測試類: https://github.com/xu509/Java-practise/blob/master/src/io/MappedIO.java

10.7、文件加鎖

JDK1.4引入了文件加鎖機制,允許我們同步訪問某個作為共享資源的文件,通過通道的tryLock,或者lock方法,可以獲得整個文件的鎖,或部分的

FileLock fl = fos.getChannel().tryLock();

fl.release();

可通過添加參數來對文件的一部分上鎖

tryLock(long position,long size,boolean shared) 或者 lock(...,...,...)

第三個參數決定了鎖是獨占鎖還是共享鎖,第一第二個參數決定了文件的加鎖區域,而沒有參數的加鎖方法會對整個文件進行加鎖。

獨占鎖或者共享鎖的支持必須通過底層的操作系統提供,如果操作系統不支持共享鎖,則會提供獨占鎖。可以通過FileLock.isShared()查詢。

對映射文件的部分上鎖

對大文件的不同部分加鎖:

https://github.com/xu509/Java-practise/blob/master/src/io/LockingMappedFiles.java

11、壓縮

Java I/O庫提供讀寫壓縮格式的數據流,使用它們進行封裝以提供壓縮功能,這些類不是從 Reader 和 Writer 派生出來,而是屬于InputStream 和 OutputStream。

壓縮類功能CheckedInputStream GetCheckSum() 為任何InputStream產生校驗和(不僅是解壓縮)CheckedOutputStreamGetCheckSum()為任何OutputStream產生校驗和(不僅是壓縮)DeflaterOutputStream壓縮類的基類ZipOutputStream一個DeflaterOutputStream,用于將數據壓縮成Zip文件格式GZIPOutputStream一個DeflaterOutputStreamm,用于將數據壓縮成GZIP文件格式InflaterInputStream解壓縮類的基類ZipInputStream一個InflaterInputStream,用于解壓縮Zip文件格式的數據GZIPInputStream 一個InflaterInputStream,用于解壓縮GZIP文件格式的數據

11.1 用GZIP進行簡單壓縮

如果對單個數據流(而不是互異數據)進行壓縮,那么它可能是比較適合的選擇

BufferedReader in2 = new BufferedReader(

new InputStreamReader(new GZIPInputStream(

new FileInputStream("test.gz"))));

BufferedOutputStream out = new BufferedOutputStream(

new GZIPOutputStream(

new FileOutputStream("test.gz")));

11.2 用Zip進行多文件壓縮

支持Zip格式的Java庫更加全面。利用該庫可以方便的保存多個文件,甚至一個獨立的類,使得讀取Zip文件更加方便。

如下例,Checksum有2個類型,Adler32(更快)和CRC32(更準確)。

寫入ZIP文件:

FileOutputStream f = new FileOutputStream("test.zip");

CheckedOutputStream csum =

new CheckedOutputStream(f, new Adler32());

ZipOutputStream zos = new ZipOutputStream(csum);

BufferedOutputStream out =

new BufferedOutputStream(zos);

zos.setComment("A test of Java Zipping");

// No corresponding getComment(), though.

for (String arg : args) {

print("Writing file " + arg);

BufferedReader in =

new BufferedReader(new FileReader(arg));

zos.putNextEntry(new ZipEntry(arg));

int c;

while ((c = in.read()) != -1)

out.write(c);

in.close();

out.flush();

}

out.close();對每一個要加入壓縮檔案的文件,都需要調用putNextEntry(),將其傳遞個一個ZipEntry對象。

讀取ZIP文件:

FileInputStream fi = new FileInputStream("test.zip");

CheckedInputStream csumi =

new CheckedInputStream(fi, new Adler32());

ZipInputStream in2 = new ZipInputStream(csumi);

BufferedInputStream bis = new BufferedInputStream(in2);

ZipEntry ze;

while ((ze = in2.getNextEntry()) != null) {

print("Reading file " + ze);

int x;

while ((x = bis.read()) != -1)

System.out.write(x);

}

if (args.length == 1)

print("Checksum: " + csumi.getChecksum().getValue());

bis.close();

更簡單的方法:

ZipFile zf = new ZipFile("test.zip");

Enumeration e = zf.entries();

while (e.hasMoreElements()) {

ZipEntry ze2 = (ZipEntry) e.nextElement();

print("File: " + ze2);

// ... and extract the data as before

}

完整例子:https://github.com/xu509/Java-practise/blob/master/src/io/ZipCompress.java

11.3 Java檔案文件

jar [options] destination [manifest] inputfile(s)

options 是一個字母集合(不需要輸入任何“-”或其他任何標示符),一下字符在Unix和Linux系統的tar文件中也具有相同的意義.

c? ? ? ? ? ? ? ? 創建一個新的或空的壓縮文檔t列出目錄表x解壓所有文件x file解壓該文件f? ? ? ? ? ? ? ? ? ? ? ? ? ? ?意指:“我打算指定一個文件名。” 如果沒有用這個選項, jar假設所有的輸入都來自于標準輸入。m表示第一個參數將是用戶自建的清單文件的名字v 產生詳細輸出,描述jar所做的工作O只存儲文件,不壓縮文件(用來創建一個可放在類路徑中的JAR文件)M不自動創建文件清單

典型用法:

jar cf myJarFile.jar *.class? -

創建一個名為myJarFile.jar的JAR文件,該文件包含了當前目錄中的所有類文件,以及自動產生清單文件

jar cmf myJarFile.jar myManifestFile.mf *.class - 其他與上例相同,添加一個名為myManifestFile.mf的用戶自建清單文件

jar tf myJarFile.jar? - 產生myJarFile.jar內所有文件的一個目錄表

jar tvf myJarFile.jar? - 提供有關myJarFile.jar中的文件的更詳細的信息

假定audio、classes和image是子目錄,下面的命令將所有子目錄合并到文件myApp.jar中,其中也包括了 "v"標志,當jar程序運行時,該標志可以提供更詳細的信息 -? ?jar cvf myApp.jar audio classes image

12、對象序列化

Java的對象序列化將那些實現了Serializable接口的對象轉換成一個字節序列,并能夠在以后將這個字節序列完全恢復為原來的對象。

利用對象的序列化可以實現輕量級持久性。

要序列化一個對象,首先需要創建一個OutputStream對象,然后使用ObjectOuptStream進行裝飾。然后,只需要調用writeObject()即可將對象序列化,并將其發送給OutputStream。要反響進行該過程,需要將一個InputStream封裝在ObjectInputStream內,然后調動readObject(),獲得一個Object引用,然后對其向下轉型則能直接設置他們。

輸出序列化對象:

OutputStream outstream = new FileOutputStream(filepath);

ObjectOutputStream out = new ObjectOutputStream(outstream);

//? ? ? ? out.writeObject("test write");

out.writeObject(a1);

out.close();

輸入序列化對象:

ObjectInputStream in = new ObjectInputStream(new FileInputStream(filepath));

String s = (String) in.readObject();

Object obj = in.readObject();

in.close();

詳細例子 : https://github.com/xu509/Java-practise/blob/master/src/io/Worm.java

12.1 尋找類

獲取序列化后的文件,重新進行包裝時需要原類的.class文件,否則無法包裝。

12.2 序列化的控制 如果需要考慮特殊的安全問題,希望對象的一部分被序列化,或者一個對象被還原后,其子對象需要重新創建。

在這些特殊情況下,可通過實現Externalizable接口代替Serializable接口,來對序列化過程進行控制。這個接口增添兩個方法:writeExternal()、readExternal()。這兩個方法會在序列化與反序列化還原的過程中被自動調用。

https://github.com/xu509/Java-practise/blob/master/src/io/Blips.java

如上例,Blip2因為構造方法非public所以無法反序列化還原。這是Externalizable和Serializable的不同,Serizalizable接口不依賴構造方法還原,而Externalizable還原時會調用所有的默認構造方法,然后再調用readExternal()。

https://github.com/xu509/Java-practise/blob/master/src/io/Blip3.java

Externalizable在反序列化時,需要向對象內所有的成員對象寫入數據,否則還原后的對象中的成員對象數據為空。

public void writeExternal(ObjectOutput out)

throws IOException {

out.writeObject(s);

out.writeInt(i);

}

public void readExternal(ObjectInput in)

throws IOException, ClassNotFoundException {

s = (String) in.readObject();

i = in.readInt();

}

transient(瞬時)關鍵詞

除了Externalizeable外,可以用transient在Serializable對象中逐個字段關閉序列化。

例子: https://github.com/xu509/Java-practise/blob/master/src/io/Logon.java

private transient String password;

private Date date = new Date();

當對象被恢復時,password域會變成"null",date對象不會發生變化,序列化的時候是多少還原時就是多少。

Externalizable的替代方法

如果不希望實現Externalizable方法,我們可以實現Serializable接口,并且

添加名為writeObject()和readObject()方法。這樣一旦對象被序列化或者反序列化還原,就會自動地分別調用這兩個方法,這些方法必須有準確的方法特征簽名:

private void writeObject(ObjectOutputStream stream)

throws IOException ;

private void readObject(ObjectInputStream stream)

throws IOException, ClassNotFoundException;

https://github.com/xu509/Java-practise/blob/master/src/io/SerialCtl.java

private void writeObject(ObjectOutputStream stream)

throws IOException {

stream.defaultWriteObject();

stream.writeObject(b);

}

private void readObject(ObjectInputStream stream)

throws IOException, ClassNotFoundException {

stream.defaultReadObject();

b = (String) stream.readObject();

}版本控制

由于Java版本控制機制國語簡單,因而對于序列化的支持,只適用于短期存儲或應用之間的RMI。

12.3 使用”持久性“

我們將2個對象(他們都具有指向第三個對象的引用 )進行序列化,當我們恢復他們時,第三個對象會只出現一次嗎?如果兩個對象序列化成獨立的文件,然后在代碼的不同部分對它們進行反序列化還原,又會怎么樣呢?

https://github.com/xu509/Java-practise/blob/master/src/io/MyWorld.java

經過上述程序的試驗,在同一個流內,2個對象引用了相同的地址。

https://github.com/xu509/Java-practise/blob/master/src/io/StoreCADState.java

在上面這個例子里,xPos,yPos,dimension都成功的序列化與反序列化了,但是static的color并沒有成功的恢復。而Line類中的

/*序列化時記錄static變量的值*/

public static void

serializeStaticState(ObjectOutputStream os)

throws IOException {

os.writeInt(color);

}

/*序列化時記錄static變量的值*/

public static void

deserializeStaticState(ObjectInputStream os)

throws IOException {

color = os.readInt();

}方法則的作用就是將靜態變量的序列化和反序列化。

13、XML

書中使用XOM類庫來完成對XML的操作。

14、Preferences

Preferences API 與對象序列化相比,與對象持久性更密切,因為它可以自動存儲和讀取信息。不過它只能用于小的、受限的數據集合——我們只能存儲基本類型和字符串,并且每個字符串的存儲長度不能超過8K。

顧名思義,Preferences API用于存儲和讀取用戶的偏好,以及程序配置項的設置。

Preferences是一個鍵值集合(類似映射),存儲在一個節點層次結構中。簡單例子:

public class PreferencesDemo {

public static void main(String[] args) throws Exception {

Preferences prefs = Preferences

.userNodeForPackage(PreferencesDemo.class);

prefs.put("Location", "Oz");

prefs.put("Footwear", "Ruby Slippers");

prefs.putInt("Companions", 4);

prefs.putBoolean("Are there witches?", true);

int usageCount = prefs.getInt("UsageCount", 0);

usageCount++;

prefs.putInt("UsageCount", usageCount);

for (String key : prefs.keys())

print(key + ": " + prefs.get(key, null));

// You must always provide a default value:

print("How many companions does Dorothy have? " +

prefs.getInt("Companions", 0));

}

}

/* Output: (Sample)

Location: Oz

Footwear: Ruby Slippers

Companions: 4

Are there witches?: true

UsageCount: 53

How many companions does Dorothy have? 4

*///:~

每次PreferencesDemo運行后,usageCount都會+1。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532017.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532017.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532017.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

outlook反應慢的原因_保險管怎么區分慢熔和快熔?

保險絲快熔與慢熔的區別所有雙帽;對于這樣的產品特性和安全性熔絲; gG的”&#xff0c;即&#xff0c;與接觸帽組合接觸;即&#xff0c;所述雙(內/外蓋)的蓋。和一般的小型或地下加工廠&#xff0c;以便執行切割角&#xff0c;降低生產成本&#xff0c;這將選擇單個帽鉚接“單&…

java成員內部類_Java中的內部類(二)成員內部類

Java中的成員內部類(實例內部類)&#xff1a;相當于類中的一個成員變量&#xff0c;下面通過一個例子來觀察成員內部類的特點public classOuter {//定義一個實例變量和一個靜態變量private inta;private static intb;//定義一個靜態方法和一個非靜態方法public static voidsay(…

word 通配符_學會Word通配符,可以幫助我們批量處理好多事情

長文檔需要批量修改或刪除某些內容的時候&#xff0c;我們可以利用Word中的通配符來搞定這一切&#xff0c;當然&#xff0c;前提是你必須會使用它。通配符的功能非常強大&#xff0c;能夠隨意組合替換或刪除我們定義的規則內容&#xff0c;下面易老師就分享一些關于查找替換通…

java存儲鍵值結構_java-鍵值存儲為主數據庫

我將要開始一個項目,該項目的讀寫操作非常頻繁且頻繁.因此,環顧四周,我發現內存數據庫正是為此目的而創建的.經過更多調查后,我進入了redis.Redis看起來很酷(雖然剛開始閱讀,但是對此有很多了解).但是我主要只看過關系數據庫,并且以元組和關系的方式來考慮數據(我認為我可以隨著…

python 輸入文件名查找_python 查找文件名包含指定字符串的方法

編寫一個程序&#xff0c;能在當前目錄以及當前目錄的所有子目錄下查找文件名包含指定字符串的文件&#xff0c;并打印出絕對路徑。import osclass searchfile(object):def __init__(self,path.):self._pathpathself.abspathos.path.abspath(self._path) # 默認當前目錄def fin…

java 運行 出現選擇_Eclipse?運行出現java.lang.NoClassDefFoundError的解決方法

上篇博文也提到了這個問題&#xff0c;但沒有深入的講解。這次特意做了整理&#xff0c;詳細解釋其原因。先看錯誤java.lang.NoClassDefFoundError&#xff0c;顯然是java虛擬機找不到指定的類&#xff0c;多數情況下是外部jar中的類。Eclipse的自動化&#xff0c;集成化&#…

設置熄屏_剛買的手機微信收不到信息提醒耽誤事情,手機到手一定要這樣設置...

手機使用過程中經常會遇到第三方軟件接收不到信息提醒的狀況&#xff0c;常常因此耽誤了很多重要的事情&#xff0c;造成損失。特別是剛換新手機或者手機剛升級系統時發生的最多。一般都覺得是手機問題&#xff0c;其實只是手機的系統設置出現了問題&#xff0c;只要跟我按照以…

java判斷對稱素數_SM2非對稱算法的原理及實現 Java SM2的代碼案例 | 一生孤注擲溫柔 | 小奮斗...

SM2橢圓曲線公鑰密碼算法&#xff1a;我國自主知識產權的商用密碼算法&#xff0c;是ECC(Elliptic Curve Cryptosystem)算法的一種&#xff0c;基于橢圓曲線離散對數問題&#xff0c;計算復雜度是指數級&#xff0c;求解難度較大&#xff0c;同等安全程度要求下&#xff0c;橢圓…

multipartfile 獲取音頻時長_抖音音頻下載捷徑:一鍵提取音頻,安卓+ios全通用,完全免費...

本文相關&#xff1a;抖音音頻提取、抖音音頻快捷指令、捷徑怎么獲取抖音音樂…昨天有抖友分享了一個抖音短視頻鏈接&#xff0c;告訴我&#xff0c;她很喜歡這個視頻里的歌曲&#xff0c;但是在很多歌曲app上面卻找不到相同的版本&#xff0c;然后就問我&#xff0c;有沒有什么…

python可以做特效嗎_學習mel語言,Python,JavaScript到什么程度才能做一下大型特效,要自已開發插件腳本呢?...

感謝邀請。首先自己要在某一方面要擅長&#xff0c;認準一個定位。比如android是鑰匙做前端應用軟件的&#xff0c;python可以做爬蟲及其人工智能&#xff0c;js做全段網頁&#xff0c;java主要是做后端的1、我們程序員對于開發軟件來說&#xff0c;無論你選擇的是那種語言&…

POJ2513-Colored Sticks

/*思路&#xff1a;類似圖論中“一筆畫”問題&#xff0c;兩根木棒的相連接的端點是一樣的顏色&#xff0c;&#xff08;a,b&#xff09;--(b,c)--(c, d)....方法&#xff1a;trie樹并查集&#xff0c; 利用trie樹建立字符串和某一個節點的映射&#xff0c;并將這些和字符串構成…

php windows共享內存,給PHP開啟shmop擴展實現共享內存

這篇文章主要介紹了關于給PHP開啟shmop擴展實現共享內存&#xff0c;有著一定的參考價值&#xff0c;現在分享給大家&#xff0c;有需要的朋友可以參考一下在項目開發中&#xff0c;想要實現PHP多個進程之間共享數據的功能&#xff0c;讓客戶端連接能夠共享一個狀態&#xff0c…

導入ansys的實體怎么進行parameter_ANSYS在線纜線束設計中的仿真應用

ANSYS采用ANSYS Maxwell、Q3D、Twin Builder等電磁仿真軟件&#xff0c;從線纜線束設計、寄生參數RLCG提取、到系統電磁兼容提供了全面仿真分析。創建模型ANSYS在Maxwell軟件基礎上提出針對用戶定制化的“線纜線束設計工具包”&#xff0c;幫助客戶參數化建立特定幾何模型&…

怎么做95置信區間圖_這種動態的OD圖怎么做?簡單3步快速搞定

之前在視頻號中發過一個單車的出行數據可視化效果。動態展示了某天單車不同時段的運行情況&#xff0c;這種動態的OD可視化效果是如何制作的呢&#xff1f;使用的是kepler.gl進行制作的&#xff0c;其實非常簡單&#xff0c;3步即可快速搞定。一、數據軟件準備1、軟件制作這種動…

php抖音跳轉地址,PHP如何實現解析抖音無水印視頻

問題來源很多時候你在douyin里看到了一個短視頻&#xff0c;想復制下來自己編輯文字來發布&#xff0c;可是視頻里的水印卻是原者的。這個時候你想把水印去掉&#xff0c;你要如何做呢&#xff1f;這里提供PHP實現去除水印的主要方法&#xff0c;其實很簡單。使用方法&#xff…

php 分割二維數組,拆分二維數組 php

把以下數組拆分&#xff1a;{"errcode": 0,"msg": "成功","data": {"list": [{"ticket_no": "1","options": ["周四301","周四302","周四303"],"play_ty…

Dijkstra算法優先隊列實現與Bellman_Ford隊列實現的理解

1 /*2 Dijkstra算法用優先隊列來實現&#xff0c;實現了每一條邊最多遍歷一次。 要知道&#xff0c;我們從隊列頭部找到的都是到3 已經"建好樹"的最短距離以及該節點編號, 并由該節點去更新 樹根 到其他點&#xff08;被更新的節點可以在隊列中4 &#xff0c;也可以是…

php times33,PHP Hash算法:Times33算法代碼實例

最近看書&#xff0c;里面提到了一些Hash算法。比較有印象的是Times33&#xff0c;當時理解不是很透測&#xff0c;今天寫了段程序來驗證了一下。先上代碼&#xff1a;復制代碼 代碼如下:/*** CRC32 Hash function* param $str* return int*/function hash32($str){return crc3…

撿到vivo手機怎么清除賬號_為什么現在買手機,很少會去考慮OPPO和vivo呢?看一下老板怎么說...

不知道大家是否注意到&#xff0c;近年來OPPO和vivo的報道越來越少&#xff0c;而華為、榮耀和小米出現的頻率越來越高。此外&#xff0c;網絡上還有另外一個聲音&#xff0c;一個專業的機友朋友說&#xff0c;寧可選擇小米、OPPO和vivo&#xff0c;為什么熟悉自己手機的人不考…

php分析圖片中水印的位置,關于ThinkPHP打水印及設置水印位置的分析

這篇文章主要介紹了ThinkPHP打水印及設置水印位置的方法,結合實例形式分析了thinkPHP打印與設置水印的相關操作步驟與具體實現技巧,需要的朋友可以參考下本文實例講述了ThinkPHP打水印及設置水印位置的方法。分享給大家供大家參考&#xff0c;具體如下&#xff1a;最近在用Thin…