溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java-IO操作簡介

發(fā)布時(shí)間:2020-07-12 04:34:44 來源:網(wǎng)絡(luò) 閱讀:327 作者:棲木之地 欄目:編程語言

流:字節(jié)流和字符流
字節(jié)流:處理二進(jìn)制數(shù)據(jù),用于處理原始數(shù)據(jù),不應(yīng)該用來處理文本內(nèi)容
字符流:處理字符數(shù)據(jù),自動(dòng)轉(zhuǎn)換本地字符集
行尾結(jié)束符: \r\n 或者\(yùn)r 或者\(yùn)n
對象流:處理對象二進(jìn)制數(shù)據(jù)
需要對流進(jìn)行關(guān)閉:
字符流操作:Reader,Writer
字節(jié)流操作:InputStream,OutputStream
Channel,GatheringByteChannel,InterruptibleChannel
ReadableByteChannel,ScatteringByteChannel,WritableByteChannel
Channels, DatagramChannel,F(xiàn)ileChannel,F(xiàn)ileLock,Pipe
SelectableChannel,SelectionKey,Selector,ServerSocketChannel,SocketChannel

中文兩個(gè)字節(jié),英文1個(gè)字節(jié),一個(gè)字節(jié)8bit,高位補(bǔ)零
字節(jié)流不會(huì)使用內(nèi)存緩沖,文件本身直接操作
字符流操作使用內(nèi)存緩沖,用緩沖操作文件,字符流在輸出前將內(nèi)容保存在內(nèi)容中

主要有四類操作:
1:字節(jié)操作:InputStream和OutputStream
2:字符操作:Reader和Writer
3:磁盤操作:File
4:網(wǎng)絡(luò)操作:Socket

無論是網(wǎng)絡(luò)還是磁盤,存儲(chǔ)單元都是字節(jié),字符是在字節(jié)的基礎(chǔ)上進(jìn)行了轉(zhuǎn)換:
InputStreamReader
拿到字節(jié)數(shù)據(jù)后,要指定編碼字符集,否則采用的是系統(tǒng)默認(rèn)的字符集

磁盤IO機(jī)制:
系統(tǒng)在內(nèi)核空間中加入了緩存機(jī)制,如果用戶訪問的是同一磁盤地址的空間數(shù)據(jù),那么會(huì)從緩存中返回
標(biāo)準(zhǔn)訪問方式:
調(diào)用read時(shí),操作系統(tǒng)檢查內(nèi)核緩存中有沒有數(shù)據(jù),如果沒有則從磁盤讀取并緩存到內(nèi)核緩存
調(diào)用write時(shí):先復(fù)制到緩存中,對于用戶來說操作已經(jīng)完成,什么時(shí)候?qū)懭氪疟P由操作系統(tǒng)決定
直接IO方式:
應(yīng)用直接訪問磁盤,不經(jīng)過系統(tǒng)內(nèi)核數(shù)據(jù)緩存區(qū),通常使用在數(shù)據(jù)庫管理系統(tǒng)中
同步訪問方式:讀取和寫入都是同步操作,寫入經(jīng)過高速緩存然后進(jìn)入磁盤,讀取經(jīng)過磁盤到高速緩存
異步訪問方式:發(fā)起讀寫請求后,線程去處理其他的,等待高速緩存從磁盤讀取回來后再操作
內(nèi)存映射方式:把內(nèi)存的一塊區(qū)域和文件關(guān)聯(lián)起來,文件的數(shù)據(jù)就是內(nèi)存中的數(shù)據(jù)

FileInputStream會(huì)創(chuàng)建一個(gè)FileDescriptor對象,這個(gè)對象是真正代表一個(gè)存在的文件對象的描述
可以通過getFD犯法獲取真正操作與底層操作系統(tǒng)相關(guān)的文件的描述

傳入文件名時(shí),創(chuàng)建一個(gè)File對象。讀取File對象內(nèi)容時(shí),創(chuàng)建一個(gè)FileDescriptor操作,使用StreamDecoder類將byte解碼成char格式。然后返回char數(shù)據(jù)

Java序列化技術(shù):java序列化就是將一個(gè)對象轉(zhuǎn)換成一串二進(jìn)制字節(jié)數(shù)組。這樣,對象就能保存和傳輸,進(jìn)行持久化。對象需要實(shí)現(xiàn)Serializable接口
序列化的二進(jìn)制數(shù)組主要包含5個(gè)部分內(nèi)容:
1:序列化文件頭:使用的序列化協(xié)議,序列化協(xié)議,該數(shù)組的類型(比如說是一個(gè)對象)
2:序列化類的描述,比如是Serialize類。包含一個(gè)類聲明,class名字長度,完整類名,序列化ID,如果沒有指定則生成一個(gè)8字節(jié)的ID,還有該類的字段個(gè)數(shù)
3:對象中各個(gè)屬性項(xiàng)的描述
4:該對象的父類信息描述
5:該對象的屬性項(xiàng)的實(shí)際值。

序列化的復(fù)雜情況:
1:父類實(shí)現(xiàn)Serializable接口時(shí),所有子類都可以被序列化
2:子類實(shí)現(xiàn)Serializable接口,而父類沒有實(shí)現(xiàn),則父類屬性不能被序列化,不報(bào)錯(cuò),數(shù)據(jù)丟失,子類仍然能序列化。
3:如果序列化的對象的屬性也是對象,那么子對象也需要實(shí)現(xiàn)序列化接口,否則報(bào)錯(cuò)
4:反序列化時(shí),對象的屬性有修改或刪減,則修改部分的屬性會(huì)丟失,但不會(huì)報(bào)錯(cuò)
5:反序列化時(shí),如果serialVersionUID被修改,則反序列化時(shí)會(huì)失敗

TCP連接:
TCP狀態(tài):
CLOSED:
LISTEN:等待連接狀態(tài)
SYN-SENT:客戶端發(fā)起連接,發(fā)送SYN給服務(wù)器,如果接受不到則直接進(jìn)入CLOSED
SYN-RCVD:服務(wù)器接收請求,返回ACK響應(yīng)
ESTABLISHED:服務(wù)器端和客戶端在完成3次握手后進(jìn)入該狀態(tài),說明可以傳輸數(shù)據(jù)了
FIN-WAIT-1:發(fā)送FIN給對方
FIN-WAIT-2:接收FIN ACK數(shù)據(jù)
CLOSE-WAIT:
LAST-ACK:發(fā)起關(guān)閉請求
CLOSING
TIME-WAIT:

closed--->listen :被動(dòng)打開
closed--->syn-send:主動(dòng)打開,發(fā)送SYN
listen->syn-received:收到syn,發(fā)送syn-ack
syn-send->syn-received:同時(shí)打開,收到syn,發(fā)送syn-ack
syn-received-------->established:收到ack
syn-send---------->established:收到syn-ack,發(fā)送ack
established-------->FIN-WAIT1:關(guān)閉,發(fā)送FIN
FIN-WAIT1-------->FIN-WAIT2:收到對FIN的ACK
FIN-WAIT2------->TIME-WAIT:收到FIN,發(fā)送ACK
FIN-WAIT1------>CLOSING:收到FIN,發(fā)送ACK,同時(shí)關(guān)閉
CLOSING------->TIME-WAIT:收到對FIN的應(yīng)答
ESTABLISHED-------->CLOSE-WAIT:收到FIN,發(fā)送ACK
CLOSE-WAIT--------->LAST-ACK:等待應(yīng)用程序關(guān)閉,發(fā)送FIN
LAST-ACK------------>CLOSED:收到對FIN的ACK

影響網(wǎng)絡(luò)傳輸因素:
1:帶寬:1秒傳輸最大比特?cái)?shù)
2:傳輸距離:光纖的折射率導(dǎo)致有傳輸延遲。
3:TCP擁堵:停-等-停-等

NIO工作方式:非阻塞IO
一旦發(fā)生阻塞,線程就會(huì)失去CPU的使用權(quán),在大規(guī)模訪問下是不能允許的。

工作過程:
0:創(chuàng)建一個(gè)ByteBuffer來獲取數(shù)據(jù)
ByteBuffer buffer = ByteBuffer.allocate(1024);
1:Selector靜態(tài)工廠方法創(chuàng)建一個(gè)選擇器selector
Selector selecotr = Selector.open();
2:創(chuàng)建一個(gè)服務(wù)器端的Channel,然后綁定到一個(gè)Socket對象,并注冊到selector上
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);//非阻塞模式
ssc.socket.bind(new InetSocketAddress(8080));
ssc.register(selector,SelectionKey.OP_ACCEPT);//注冊監(jiān)聽事件
3:調(diào)用selector的selectedKeys方法來檢查是否有事件發(fā)生,如果有事件發(fā)生則返回SelectionKey,通過這個(gè)對象的Channel方法獲得通信信道對象:
Set selectedKeys = selector.selectedKeys();
SelectionKey key = 遍歷selectedKeys
if(key.readOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT){
ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
SocketChannel sc = ssChannel.accept();//
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ)
} else if((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
SocketChannel sc = (SocketChannel) key.channel();
sc.read(buffer);
buffer.flip();
}

RAID策略:
RAID0:數(shù)據(jù)被平均寫入多個(gè)磁盤陣列,寫數(shù)據(jù)和讀數(shù)據(jù)都是并行的,所以磁盤的IOPS可以提高一倍
RAID1:將一份數(shù)據(jù)復(fù)制到多個(gè)磁盤陣列中,不能提高IOPS,但能提高安全性
RAID5:前兩種方式的折中。將數(shù)據(jù)平均寫到所有磁盤陣列總數(shù)減1的磁盤中,往另外一個(gè)磁盤中寫入這份數(shù)據(jù)的奇偶校驗(yàn)信息。如果其中一個(gè)磁盤數(shù)據(jù)損壞,可以通過其他磁盤的數(shù)據(jù)和這個(gè)數(shù)據(jù)的奇偶校驗(yàn)信息來恢復(fù)這份數(shù)據(jù)。
RAID0+1:根據(jù)數(shù)據(jù)的備份情況進(jìn)行分組,一份數(shù)據(jù)同時(shí)寫入多個(gè)備份磁盤分組中,同時(shí)多個(gè)分組也會(huì)進(jìn)行并行讀寫。

java中操作字符的Reader和Writer中有StreamDecoder,StreamEncoder,負(fù)責(zé)字符和字節(jié)的轉(zhuǎn)換。
內(nèi)存中的編碼:在內(nèi)存中進(jìn)行從字符到字節(jié)的轉(zhuǎn)換。String類提供了getBytes(字符集)來轉(zhuǎn)換
和new String(bytes, 字符集);
已經(jīng)廢棄的ByteToCharConverter和CharToByteConverter,使用Charset取代,Charset提供encode和decode方法
還有一個(gè)ByteBuffer類,提供char和byte的軟交換,他們之間的轉(zhuǎn)換不需要編碼,僅僅只是把一個(gè)16bit的char拆分成2個(gè)8bit的byte表示。

java內(nèi)存編碼使用的是utf-16編碼,效率高,但不利于網(wǎng)絡(luò)之前傳輸。
因?yàn)榫W(wǎng)絡(luò)傳輸容易損壞字節(jié)流,字節(jié)流損壞將很難恢復(fù),所以相比較utf-8更適合網(wǎng)絡(luò)傳輸。
utf-8對ascii字符使用單字節(jié)存儲(chǔ),另外單個(gè)字符損壞也不會(huì)影響后面的其他字符。是理想的編碼方式。

大多數(shù)IO都是沒有緩沖的,這意味著每個(gè)讀寫請求都是底層OS直接處理的。這讓程序比較低效,因?yàn)槊看握埱蠖紩?huì)觸發(fā)磁盤訪問,網(wǎng)絡(luò)活動(dòng)或一些相對昂貴的操作
為了減少這種類型的開銷,java平臺(tái)實(shí)現(xiàn)緩沖IO stream。緩沖的輸入流從內(nèi)存區(qū)域讀取數(shù)據(jù)作為buffer,僅當(dāng)buffer為空的時(shí)候,才會(huì)調(diào)用原生輸入api。類似的,緩沖的輸出流寫入數(shù)據(jù)到一個(gè)buffer,當(dāng)buffer滿了的時(shí)候原生輸出api才會(huì)被調(diào)用。
flush緩沖流:在關(guān)鍵點(diǎn)寫出緩沖區(qū)而不需要等它填充是有意義的。這個(gè)被稱為flush
一些緩沖輸出類支持自動(dòng)flush,通過構(gòu)造參數(shù)指定一個(gè)選項(xiàng)。當(dāng)自動(dòng)刷新開啟,特定關(guān)鍵事件會(huì)導(dǎo)致緩沖會(huì)被flush

NIO:
標(biāo)準(zhǔn)IO是面向字節(jié)流和字符流的,而NIO是面向通道和緩沖區(qū)的,數(shù)據(jù)總是從通道中讀到buffer緩沖區(qū)內(nèi),或者從buffer寫入通道
核心組件:
Channels:Buffer的數(shù)據(jù)從Channel中讀取或?qū)懭?br/>FileChannel,DatagramChannel,SocketChannel,ServerSocketChannel
Buffers:實(shí)際就是一個(gè)塊內(nèi)存,有三個(gè)主要屬性:capacity容量,position位置,limit限制
ByteBuffer,CharBuffer,DoubleBuffer,F(xiàn)loatBuffer,IntBuffer,LongBuffer,ShortBuffer

Selectors:選擇器允許單線程操作多個(gè)通道,Channel需要注冊到Selector上

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
buf.flip(); //make buffer ready for read
while(buf.hasRemaining()){
System.out.print((char) buf.get()); // read 1 byte at a time
}
buf.clear(); //make buffer ready for writing
bytesRead = inChannel.read(buf);

FileChannel類型可以把數(shù)據(jù)直接傳輸?shù)搅硪粋€(gè)channel上:
兩個(gè)都是FileChannel:
aChannel.transferFrom(bChannel);
aChannel.transferTo(bChannel);

注冊selector:
Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

Unrecognized Windows Sockets error: 0: recv failed:
socket連接中有數(shù)據(jù)未處理

=================
編寫Socket服務(wù)器:
只需要返回http協(xié)議中的內(nèi)容即可
BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write("HTTP/1.1 200 OK");
writer.newLine();
writer.write("Server: Apache-Coyote/1.1");
writer.newLine();
writer.write("Content-Type: text/html;charset=UTF-8");
writer.newLine();
String body = "<html><head></head><body>1234</body></html>";
writer.write("Content-Length: " + body.length());
writer.newLine();
writer.write("Date: Mon, 03 Nov 2014 06:37:28 GMT");
writer.newLine();
writer.write("\n" + body);
writer.flush();
writer.close();
在body處需要\n,否則瀏覽器不能正確識(shí)別響應(yīng)實(shí)體
在讀取請求的數(shù)據(jù)時(shí),只能判斷最后的內(nèi)容為空字符串,不能判斷為null
ServerSocket serverSocket = new ServerSocket(1099);
Socket socket = serverSocket.accept();
BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String lineStr = null;
while (!(lineStr=reader.readLine()).equals("")){
System.out.println(lineStr);
}

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI