日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

think in java i o_《Thinking in Java》学习——18章Java I/O系统(三)

發(fā)布時間:2023/12/19 windows 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 think in java i o_《Thinking in Java》学习——18章Java I/O系统(三) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

ppe#標(biāo)準(zhǔn)I/O

一.從標(biāo)準(zhǔn)輸入中讀取

1.按照標(biāo)準(zhǔn)I/O模型,Java提供了System.in、System.out、System.err。其中System.out已經(jīng)事先被包裝成了PrintStream對象。System.err同樣也是PrintStream,但是System.in卻是一個沒有被包裝過的未經(jīng)加工的InputStream。這意味著盡管我們可以立刻使用System.out和System.err,但是在讀取System.in之前必須對其進行包裝。

2.為了使用readLine()一行一行地讀取,我們將System.in包裝成BufferedReader來使用:

public class Echo {

public static void main(String... args) throws IOException {

BufferedReader stdin = new BufferedReader(

new InputStreamReader(System.in));

String in;

while ((s = stdin.readLine()) != null && s.length != 0) {

System.out.println(s);

}

}

}

注意,System.in和大多數(shù)流一樣,通常應(yīng)該對它進行緩沖。

二.將System.out轉(zhuǎn)換成PrintWriter

PrintWriter有一個可以接受OutputStream作為參數(shù)的構(gòu)造器。因此,只要需要,就可以使用那個那個構(gòu)造器把System.out轉(zhuǎn)換成PrintWriter:

public class ChangeSystemOut {

public static void main(String... args) {

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

out.println("Hello, world");

}

}

第二個參數(shù)需要設(shè)置為true,以便開啟自動清空功能;否則,你可能看不到輸出。

三.標(biāo)準(zhǔn)I/O重定向

1.Java的System類提供了一些簡單的靜態(tài)方法調(diào)用,以允許我們對標(biāo)準(zhǔn)I/O流進行重定向:

setIn(InputStream)

setOut(PrintStream)

setErr(PrintStream)

2.下面是簡單實例:

public class Redirecting {

public static void main(String... args) throws IOException {

PrintStream console = System.out;

BufferedInputStream in = new BufferedInputStream(

new FileInputStream("Redirecting.java"));

PrintStream out = new PrintStream(

new BufferedOutputStream(

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

System.setIn(in);

System.setOut(out);

System.setErr(out);

BufferedReader br = new BufferedReader(

new InputStreamReader(System.in));

String s;

while (s = br.readLine() != null) {

System.out.println(s);

}

out.close();

System.setOut(console);

}

}

I/O重定向操縱的是字節(jié)流,而不是字符流;因此我們使用的是InputStream和OutputStream,而不是Reader和Writer。

進程控制

1.對于需要在Java內(nèi)部之行其他 操作系統(tǒng)程序的需求,Java類庫提供了執(zhí)行這些操作的類。

2.下面的程序的作用是運行程序,并將產(chǎn)生的輸出發(fā)送到控制臺:

class OSExecuteException extends RuntimeException {

public OSExecuteException(String why) { super(why); }

}

class OSExecute {

public static void command(String command) {

boolean err = false;

try {

Process process = new ProcessBuilder(command.split(" ")).start();

BufferedReader results = new BufferedReader(

new InputStreamReader(process.getInputStream()));

String s;

while ((s = results.readLine()) != null) {

System.out.println(s);

}

BufferedReader errors = new BufferedReader(

new InputStreamReader(process.getErrorStream()));

while ((s = results.readLine) != null){

System.err.println(s);

err = true;

}

} catch (Exception e) {

if (!command.startWith("CMD /C"))

command("CMD /C" + command);

else

throw new RuntimeException(e);

}

if (err) {

throw new OSExecuteException("Errors executing" + command);

}

}

}

要想運行一個程序,你需要傳遞一個字符串,它與你在控制臺上運行該程序所鍵入的命令相同。這個命令被傳遞給java.lang.ProcessBuilder構(gòu)造器,然后所產(chǎn)生的ProcessBuilder對象被啟動。程序執(zhí)行過程中調(diào)用getInputStream()和getErrorStream()獲取標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)錯誤流。

新I/O

1.JDK1.4引入了新的Java I/O類庫java.nio.,其目的在于提高速度。速度的提高在文件I/O和網(wǎng)絡(luò)I/O中都有實現(xiàn),這里我們只研究前者。

2.速度的提高來自于所使用的結(jié)構(gòu):通道和緩沖器。但是,我們并沒有必要直接和通道交互,我們只和緩沖器交互,并把緩沖器派送到通道。通道要么從緩沖器獲得數(shù)據(jù),要么向緩沖器發(fā)送數(shù)據(jù)。

3.唯一直接與通道交互的緩沖器是ByteBuffer:通過告知分配多少存儲空間來創(chuàng)建一個ByteBuffer對象,并且還有一個方法集,用于以原始的字節(jié)形式或幾本數(shù)據(jù)類型輸出和讀取數(shù)據(jù)。

4.FileInputStream* 、FileOutputStream和RandomAccessFile提供了方法用以產(chǎn)生可寫的、可讀的及可讀可寫的通道:

public class GetChannel {

private static final int BSIZE = 1024;

public static void main(String... args) throws Exception {

FileChannel fc = new FileOutputStream("data.txt").getChannel();

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

fc.close();

fc = RandomAccessFile("data.txt", "rw").getChannel();

fc.position(fc.size());

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

fc.close();

ByteBuffer buff = ByteBuffer.allocate(BSIZE);

fc.read(buff);

buff.flip();

while (buff.hasRemaining())

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

}

}

/*

Output:

Some text Some more

*/

5.通道時一種相當(dāng)基礎(chǔ)的東西:可以向它傳送用于讀寫的ByteBuffer,并且可以鎖定文件的某些區(qū)域用于獨占式訪問。

6.將字節(jié)存放于ByteBuffer的方法之一是:使用一種“put”方法直接對它們進行填充,填入一個或多個字節(jié),或基本數(shù)據(jù)類型的值。也可以使用warp()方法將已經(jīng)存在的字節(jié)數(shù)組“包裝到”ByteBuffer中。

7.對于只讀訪問,我們必須顯式地使用靜態(tài)的allocate()方法來分配ByteBuffer。

8.一旦調(diào)用read()方法來告知FileChannel向ByteBuffer存儲字節(jié),就必須調(diào)用緩沖器上的flip(),讓它做好讓別人讀取字節(jié)的準(zhǔn)備,如果我們打算使用緩沖器執(zhí)行進一步的read()操作,我們也必須得調(diào)用clear()來為每個read()做好準(zhǔn)備:

public class ChannelCopy {

private static final int BSIZE = 1024;

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

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();

out.write(buffer);

buffer.clear();

}

}

}

每次read()操作之后,就會將數(shù)據(jù)輸入到緩沖器中,flip()則是準(zhǔn)備緩沖器以便它的信息可以由write()提取。write()操作之后,信息仍在緩沖器中,接著clear()操作則對所有的內(nèi)部指針重新安排,以便緩沖器在另一個read()操作期間能夠做好接受數(shù)據(jù)的準(zhǔn)備。

一.轉(zhuǎn)換數(shù)據(jù)

1.緩沖器容納的是普通字節(jié),為了把它們轉(zhuǎn)換成字符,我們要不在輸入它們的時候?qū)ζ溥M行編碼,要么在將其從緩沖器輸出對它們進行解碼。可以使用java.nio.charset.Charset類實現(xiàn)這些功能,該類提供來把數(shù)據(jù)編碼成多種不同類型的字符集的工具。如果我們想對緩沖器調(diào)用rewind()方法(該方法是為了回到數(shù)據(jù)開始的部分),接著使用平臺的默認(rèn)字符集對數(shù)據(jù)進行decode(),那么作為結(jié)果的CharBuffer可以很好地輸出打印到控制臺:

public class BufferToText {

private static final int BSIZE = 1024;

public static void main(String[] args) {

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

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

fc.close();

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

ByteBuffer buff = ByteBuffer.allocate(BSIZE);

fc.read(buff);

buff.flip();

System.out.println(buff.asCharBuffer());

buff.rewind();

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

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

+ Charset.forName(encoding).decode(buff));

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

fc.write(ByteBuffer.wrap("Some text".getBytes("UTF-16BE")));

fc.close();

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

buff.clear();

fc.read(buff);

buff.flip();

System.out.println(buff.asCharBuffer());

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

buff = ByteBuffer.allocate(24);

buff.asCharBuffer().put("Some text");

fc.write(buff);

fc.close();

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

buff.clear();

fc.read(buff);

buff.flip();

System.out.println(buff.asCharBuffer());

}

}

/*

Output:

????

Decoded using Cp1252: Some text

Some text

Some text

*/

2.System.getProperty("file.encoding")可以用來發(fā)現(xiàn)默認(rèn)字符集,它會產(chǎn)生代表字符集名稱的字符串。把該字符串傳送給Charset.forName()用以產(chǎn)生Charset對象,可以用它對字符串進行解碼。

二.獲取基本類型

1.盡管ByteBuffer只能保存字節(jié)類型的數(shù)據(jù),但是它可以具有可以從所容納的字節(jié)中產(chǎn)生出各種不同基本類型值的get方法:

ByteBuffer bb = ByteBuffer.allocate(1024);

System.out.println(String.valueof(bb.getInt()));

2.向ByteBuffer插入基本數(shù)據(jù)類型的方法是:利用asCharBuffer()、asShortBuffer()等獲得該緩沖器上的視圖,然后使用視圖的put()方法。此方法適用于所有基本數(shù)據(jù)類型的轉(zhuǎn)換,唯一的例外就是使用asShortBuffer()方法等時候,需要進行數(shù)據(jù)類型轉(zhuǎn)換:

bb.asCharBuffer().put("ByteBuffer");

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

bb.asIntBuffer().put(1);

3.ByteBuffer中提供了limit()方法,以便獲取ByteBuffer可使用空間的上限。

4.當(dāng)分配完一個ByteBuffer之后,緩沖器的分配方式會將其內(nèi)容自動置零。

三.視圖緩沖器

1.視圖緩沖器可以讓我們通過某個特定的基本數(shù)據(jù)類型的視窗查看其底層的ByteBuffer。ByteBuffer依然是實際存儲數(shù)據(jù)的地方,支持著前面的視圖,因此,對視圖的任何修改都會映射成對ByteBuffer中數(shù)據(jù)的修改:

public class IntBufferDemo {

private static final int BSIZE = 1024;

public static void main(String[] args) {

ByteBuffer bb = ByteBuffer.allocate(BSIZE);

IntBuffer ib = bb.asIntBuffer();

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

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

ib.put(3, 1811);

ib.flip();

while (ib.hasRemaining()) {

int i = ib.get();

System.out.println(i);

}

}

}

/*

Output:

99

11

42

47

1811

143

811

1016

*/

先用重載后的put()方法存儲一個數(shù)組,接著get()和put()方法調(diào)用直接訪問底層ByteBuffer中的某個整數(shù)位置。

2.不同的機器可能會使用不同的字節(jié)排序方法來存儲數(shù)據(jù)。“big endian”(高位優(yōu)先)將最重要的字節(jié)存放在地址最低的存儲器單元。而“l(fā)ittle endian”(低位優(yōu)先)則是將最重要的字節(jié)放在地址最高的存儲器單元。因此,當(dāng)存儲量大于一個字節(jié)的時候,就要考慮字節(jié)的順序問題了。如有兩個字節(jié)b1:00000000,b2:01100001,如果我們以short(ByteBuffer.asShortBuffer())形式讀取數(shù)據(jù),得到的數(shù)字是97(二進制形式為000000000110010),如果在讀取之前將排序方式改為低位優(yōu)先,得到的數(shù)字為24832(二進制形式為011001000000000)。

3.改變排序方式可以使用order()方法,這里需要傳入一個參數(shù),為ByteOrder.BIG_ENDIAN或ByteOrder.LITTLE_ENDIAN。

四.用緩沖器操縱數(shù)據(jù)

1.

nio類之間的關(guān)系.png

五.緩沖器的細(xì)節(jié)

1.Buffer由數(shù)據(jù)和可以高效地訪問及操縱這些數(shù)據(jù)的四個索引組成,這四個索引是:mark(標(biāo)記),position(位置),limit(界限),和capacity(容量):

方法

描述

capacity()

返回緩沖器的容量

clear()

清空緩沖區(qū),將position設(shè)置為0,limit設(shè)置為容量。我們可以調(diào)用此方法覆蓋緩沖區(qū)

flip()

將limit設(shè)置為position,position設(shè)置為0.此方法用于準(zhǔn)備蔥緩沖區(qū)讀取已經(jīng)寫入的數(shù)據(jù)

limit()

返回limit值

limit(int num)

設(shè)置limit的值

mark()

將mark設(shè)置為position

position()

返回position()的值

position(int pos)

設(shè)置position的值

remaining()

返回(limit - positon)

hasRemaining()

若有介于position和limit之間的元素,則返回true

六.內(nèi)存映射文件

1.內(nèi)存映射文件允許我們創(chuàng)建和修改那些因為太大而不能放入內(nèi)存的文件。有了內(nèi)存映射文件,我們就可以假定整個文件都放在內(nèi)存中,而且王權(quán)可以把它當(dāng)作非常大的數(shù)組來訪問:

public class LargeMappedFiles {

static int length = 0x8FFFFFF;

public static void main(String... args) {

MappedByteBuffer out = new RandomAccessFile("test.dat", "rw").getChannel()

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

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

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

}

fro (int i = length / 2; i < length / 2 + 6; i ++) {

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

}

}

}

MappedByteBuffer由ByteBuffer繼承而來,可以通過調(diào)用獲取到的文件上的通道的map()方法獲得,它具有ByteBuffer的所有方法。

2.盡管“映射寫”似乎要用到FileOutputStream,但是映射文件中的所有輸出必須使用RandomAccessFile。

3.盡管“舊”的I/O流在使用nio實現(xiàn)后性能有所提高,但是“映射文件訪問”往往可以更加顯著地加快速度,即使簡歷映射文件的話費很大。

七.文件加鎖

1.JDK1.4引入了文件加鎖機制,它允許我們同步訪問某個作為共享資源的文件。為了解決競爭統(tǒng)一文件的兩個線程可能在不同的進程里的問題,文件鎖被設(shè)定為對其他的操作系統(tǒng)的進程是可見的,因為Java的文件加鎖直接映射到了本地操作系統(tǒng)的加鎖工具。

2.通過對FileChannel調(diào)用tryLock()或lock(),就可以獲得整個問價的FileLock。tryLock()是非阻塞式的,它設(shè)法獲取鎖,但是如果不能獲得,它將直接從方法調(diào)用返回。lock()則是阻塞式的,它要阻塞進程直至鎖可以獲得,或調(diào)用lock()的線程中斷,或調(diào)用lock()的通道關(guān)閉。使用FileLock.release()可以釋放鎖。

3.tryLock()和lock()方法也有其重載方法提供使用對文件等一部分上鎖:

tryLock(long position, long size, boolean shared)

lock(long position, long size, boolean shared)

4.文件映射通常應(yīng)用于極大的文件。我們可能需要對這種巨大的文件進行部分加鎖,以便其他進程可以修改文件中未被加鎖的部分:

public class LockAndModify extends Thread {

private ByteBuffer buff;

private int start, end;

public LockAndModify(ByteBuffer mob, int start, int end) {

this.start = start;

this.end = end;

mbb.limit(end);

mbb.position(start);

buff = mbb.slice();

start();

}

public void run() {

try {

FileLock fl = fc.lock(start, end, false);

System.out.println("Locked: " + start + " to " + end);

while (buff.position() < buff.limit() - 1) {

buff.put((byte) (byte.get() + 1));

}

fl.release();

System.out.println("Release: " + start + " to " + end);

} catch (IOException e) {

throw new RuntimeException(e);

}

}

}

在上面的程序中,線程類LockAndModify創(chuàng)建了緩沖區(qū)和用于修改的slice,然后在run()方法中,獲得文件通道上的鎖。

總結(jié)

以上是生活随笔為你收集整理的think in java i o_《Thinking in Java》学习——18章Java I/O系统(三)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。