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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

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

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

ppe#標準I/O

一.從標準輸入中讀取

1.按照標準I/O模型,Java提供了System.in、System.out、System.err。其中System.out已經事先被包裝成了PrintStream對象。System.err同樣也是PrintStream,但是System.in卻是一個沒有被包裝過的未經加工的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和大多數流一樣,通常應該對它進行緩沖。

二.將System.out轉換成PrintWriter

PrintWriter有一個可以接受OutputStream作為參數的構造器。因此,只要需要,就可以使用那個那個構造器把System.out轉換成PrintWriter:

public class ChangeSystemOut {

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

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

out.println("Hello, world");

}

}

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

三.標準I/O重定向

1.Java的System類提供了一些簡單的靜態方法調用,以允許我們對標準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重定向操縱的是字節流,而不是字符流;因此我們使用的是InputStream和OutputStream,而不是Reader和Writer。

進程控制

1.對于需要在Java內部之行其他 操作系統程序的需求,Java類庫提供了執行這些操作的類。

2.下面的程序的作用是運行程序,并將產生的輸出發送到控制臺:

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構造器,然后所產生的ProcessBuilder對象被啟動。程序執行過程中調用getInputStream()和getErrorStream()獲取標準輸出流和標準錯誤流。

新I/O

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

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

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

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

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.通道時一種相當基礎的東西:可以向它傳送用于讀寫的ByteBuffer,并且可以鎖定文件的某些區域用于獨占式訪問。

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

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

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

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()操作之后,就會將數據輸入到緩沖器中,flip()則是準備緩沖器以便它的信息可以由write()提取。write()操作之后,信息仍在緩沖器中,接著clear()操作則對所有的內部指針重新安排,以便緩沖器在另一個read()操作期間能夠做好接受數據的準備。

一.轉換數據

1.緩沖器容納的是普通字節,為了把它們轉換成字符,我們要不在輸入它們的時候對其進行編碼,要么在將其從緩沖器輸出對它們進行解碼。可以使用java.nio.charset.Charset類實現這些功能,該類提供來把數據編碼成多種不同類型的字符集的工具。如果我們想對緩沖器調用rewind()方法(該方法是為了回到數據開始的部分),接著使用平臺的默認字符集對數據進行decode(),那么作為結果的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")可以用來發現默認字符集,它會產生代表字符集名稱的字符串。把該字符串傳送給Charset.forName()用以產生Charset對象,可以用它對字符串進行解碼。

二.獲取基本類型

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

ByteBuffer bb = ByteBuffer.allocate(1024);

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

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

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

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

bb.asIntBuffer().put(1);

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

4.當分配完一個ByteBuffer之后,緩沖器的分配方式會將其內容自動置零。

三.視圖緩沖器

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

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()方法存儲一個數組,接著get()和put()方法調用直接訪問底層ByteBuffer中的某個整數位置。

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

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

四.用緩沖器操縱數據

1.

nio類之間的關系.png

五.緩沖器的細節

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

方法

描述

capacity()

返回緩沖器的容量

clear()

清空緩沖區,將position設置為0,limit設置為容量。我們可以調用此方法覆蓋緩沖區

flip()

將limit設置為position,position設置為0.此方法用于準備蔥緩沖區讀取已經寫入的數據

limit()

返回limit值

limit(int num)

設置limit的值

mark()

將mark設置為position

position()

返回position()的值

position(int pos)

設置position的值

remaining()

返回(limit - positon)

hasRemaining()

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

六.內存映射文件

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

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繼承而來,可以通過調用獲取到的文件上的通道的map()方法獲得,它具有ByteBuffer的所有方法。

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

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

七.文件加鎖

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

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

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

tryLock(long position, long size, boolean shared)

lock(long position, long size, boolean shared)

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

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創建了緩沖區和用于修改的slice,然后在run()方法中,獲得文件通道上的鎖。

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。