五.Java IO、NIO、文件、通讯
2019獨角獸企業重金招聘Python工程師標準>>>
Java 的 I/O 大概可以分成四組:
基于字節操作的 I/O :InputStream 和 OutputStream
基于字符操作的 I/O :Writer 和 Reader
基于磁盤操作的 I/O :File
基于網絡操作的 I/O :Socket
輸入流只能讀不能寫.
輸出流只能寫不能讀.
!java.io.RandomAccessFile類是可讀可寫的。
5.1 IO
InputStream/OutputStream的工作原理:
InputStream/OutputStream( 字節流 ) :一次傳送一個字節。
IO中以byte[]作為緩沖,從源(可以是文件,內存中的數據等等)中讀取數據到byte[]中,寫入數據的時候,將byte[]寫入到目標。
InputStream類中的read(byte b[], int off, int len)方法(部分):
[java]?view plaincopy
int?i?=?1;??
?for?(;?i?<?len?;?i++)?{??
?????c?=?read();??
?????if?(c?==?-1)?{??
?????????break;??
?????}??
?????b[off?+?i]?=?(byte)c;??
?}??
每次從源中讀取一個字節,存儲到byte[] b中。最多讀取len個字節。緩沖區讀滿或者到達源末尾后,將緩沖區的數據寫入目標。
read()是一個native方法,正常返回0-255,到達源數據的末尾返回-1
InputStream/OutputStream是抽象類,使用的是其子類,子類會重新定義相關方法。為了性能這些子類中的底層實現都是native方法。
Writer/Reader實現原理相似,不同的是將流數據以一個字符的長度為單位處理,并進行編碼轉換。
5.2 NIO
NIO特性之一:為所有的原始類型提供(Buffer)緩存支持
拷貝文件測試IO和NIO的讀寫速度:
[java]?view plaincopy
//IO方式??
public??void?copyFileByIO(File?file,?File?newFile)??
{??
????try??
????{??
????????FileInputStream?fis?=?new?FileInputStream(file);??
????????FileOutputStream?fos?=?new?FileOutputStream(newFile,?true);??
????????byte[]?bytes?=?new?byte[1024];??
????????while?(fis.read(bytes)?!=?-1)??
????????{??
????????????fos.write(bytes);??
????????}??
????????if(fis!=null)??
????????????fis.close();??
????????if(fos!=null)??
????????????fos.close();??
????}??
????catch?(IOException?e)??
????{??
????????e.printStackTrace();??
????}??
}??
//NIO方式??
public?static?void?copyFileByNIO(File?file,?File?newFile)??
{??
????try??
????{??
????????FileChannel?fcin?=?new?FileInputStream(file).getChannel();??
????????FileChannel?fcout?=?new?FileOutputStream(newFile,?true).getChannel();??
????????ByteBuffer?bb?=?ByteBuffer.allocate(1024);??
????????while?(fcin.read(bb)?!=?-1)??
????????{??
????????????bb.flip();??
????????????fcout.write(bb);??
????????????bb.clear();??
????????}??
????????if(fcin!=null)??
????????????fcin.close();??
????????if(fcout!=null)??
????????????fcout.close();??
????}??
????catch?(IOException?e)??
????{??
????????e.printStackTrace();??
????}??
}??
文件大小:3.2G
>> IO 讀寫耗時:114320 速度:30.45 M/s
>> NIO 讀寫耗時:86009 速度:40.47 M/s
NIO中使用Buffer來作為讀寫中轉,Buffer是一個連續的內存塊。
IO以流的方式處理數據,NIO以塊的方式處理數據。
NIO中通過channel操作Buffer緩沖區,所以NIO速度比IO要快很多。
5.3 文件
文件處理是Java IO系統中的一個子系統。
比如要讀取文件,只需要new一個FileInputStream,即可以流的方式讀取文件。
?public FileInputStream(String name)
?public FileInputStream(File file)
這兩種方式都可以從文件創建一個輸入流。
和其它的一樣read()方法都是native的,FileInputStream命名是以InputStream結尾說明他是一個輸入流,那么它的工作原理就和其它流一樣。
FileInputStream中有一個getChannel(),可以得到一個FileChannel對象。這是NIO中的特性,通過channel讀/寫數據,提高了性能。
File類:
public String getName() {
? ? ? int index = path.lastIndexOf(separatorChar);
? ? ? if (index < prefixLength) return path.substring(prefixLength);
? ? ? return path.substring(index + 1);
? }
得到文件名,其實是獲得完整路徑中的最后一個/(separatorChar根據系統匹配/或者\),然后截取到文件名。
同樣的getParent()也是通過截取字符串來獲得父目錄。
File類包含了許多對文件的操作:
?public boolean isFile()?//判斷是不是一個文件
?public boolean isHidden()?//判斷是不是隱藏
?public long length()?//文件長度
?public boolean exists()?//文件或目錄是否存在
?public boolean createNewFile() //創建文件
?public boolean delete()?//刪除文件
?...
但是,File類并不只是指文件,可以將其表示為目錄。
File file=new File( "D:/");
同樣的File類中也包含了對目錄的操作:
?public boolean isDirectory() //判斷是不是一個文件夾
?public String[] list()?//得到文件夾下的文件和目錄的名字
?public File[] listFiles()?//得到文件夾下的文件
?public boolean mkdir()?//創建目錄
?public boolean renameTo?//重命名
?...
示例:
File file=new File("c:/");
String[] files = file.list();
for(String s:files)
{
System.out.println(s);
}
輸出:
$RECYCLE.BIN
alipay
bcd.dna.LOG1
bcd.dna.LOG2
Boot
bootmgr
BOOTSECT.BAK
cygwin
Documents and Settings
maxldr.mbr
Program Files
Program Files (x86)
ProgramData
Recovery
RECYCLER
System Volume Information
TCKYU
Users
Windows
可以看到list()將所有文件和文件夾都列了出來,包括隱藏文件和文件夾,順序和實際文件夾中的顯示順序一致。
5.4 通訊
NIO特性之二:異步 I/O 支持
在通訊中就是: 提供多路 (non-bloking) 非阻塞式的高伸縮性網絡 I/O?
阻塞式網絡IO:
[java]?view plaincopy
ServerSocket?server=new?ServerSocket(9999);???
?Socket?socket=server.accept();//使用accept()阻塞等待請求??
?BufferedReader?is=new?BufferedReader(new?InputStreamReader(client.getInputStream()));????
?PrintWriter?os=new?PrintWriter(client.getOutputStream());????
?BufferedReader?sin=new?BufferedReader(new?InputStreamReader(System.in));????
?while(true)??
?{????
????String?str=is.readLine();??
?}??
?//...??
accept()如果沒有連接會一直阻塞
readLine()如果沒有讀取到數據,也會一直阻塞。
這樣的方式,每個和客戶端的連接都要用一個單獨的線程來處理,每個線程擁有自己的棧空間并且占用一些 CPU 時間,當沒有請求的時候就會阻塞。
假如每個客戶端一天之和服務器通訊一次,那么這些線程全部都必須存在一天。這樣就會浪費系統資源。
非阻塞式網絡IO:
由一個專門的線程來處理所有的 IO 事件,并負責分發,采用事件驅動機制,事件到的時候才觸發。
5.5 關于TCP、UDP、HTTP
TCP/IP是個協議組,可分為三個層次:
網絡層:IP協議、ICMP協議、ARP協議、RARP協議和BOOTP協議。
傳輸層:TCP協議、UDP協議。
應用層:FTP、HTTP、TELNET、SMTP、DNS等協議
!socket只是一種連接模式,不是協議。
TCP是基于連接的協議,必須建立好了連接,才能通訊。
適合傳輸大量數據,可靠的連接。
UDP不需要建立連接,直接把數據發送過去。因為不需要連接,所以效率高,但是可靠性沒有TCP高。
適合速度快的,數據少的。
!ping命令的實現就是基于UDP。
http是一個協議,但是底層還是基于tcp的,
HTTP協議是建立在請求/響應模型上的。客戶建立給服務器發送一條請求,服務器收到請求,給客戶端返回一個響應。
轉載于:https://my.oschina.net/bv10000/blog/187589
總結
以上是生活随笔為你收集整理的五.Java IO、NIO、文件、通讯的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CentOS虚拟机克隆后网卡配置问题
- 下一篇: 【原创】一种维护型项目升级打包的解决方案