之前在面試中被問到過兩次Java中文件讀入輸出怎麼寫,當時只記得一個大概,沒有辦法很清晰的說出一個條理,今天特地看出總結了一下這方面的內容,想要寫出來給大家分享。
首先檔案讀入輸出流常用有三種:FileInputStream/FileOutputStream,FileReader/FileWriter,RandomAccessFile。以下具體列出一些簡單的例子參考:
基礎篇:
1.
FileRead fr = new FileReader(filename); String s; while( (s=fr.readLine())!=null){ ... } fr.close(); //FileWriter同理,输出时可用write()函数 //Java I/O中所有的Reader、Writer都是面向字符流的输出输出
2.
FileInputStream fi =new FileInputStream(filename); int in; while( (in=fi.read())!=-1){ ... } fi.close(); //FileOutputStream同理 //Java I/O中所有的Reader、Writer都是面向字节流的输出输出
3.
RandomAccessFile ra =new RandomAccessFile(filename,"rw");//后面的参数指定的是 打开文件流的方式,“rw”是指读写,“r”是只读,Java不提供只写 ra.seek(number);//将文件指针移动到number处,这里文件指针可以理解为文件开始读的位置 ra.skipByte(number);//跳过number个字节 ra.read(); ra.close(); //RandomAccessFile既可以读也可以写,而且可以利用seek()函数指定位置
下面是百度百科全書的一些介紹:
RandStreampippippppp生活裡是不屬於人類的一些介紹:
RandStream系的。實際上,除了實作DataInput和DataOutput介面之外(DataInputStream和DataOutputStream也實作了這兩個介面),它和這兩個類別系毫不相干,甚至沒有用InputStream和OutputStream已經準備好的功能;它是一個完全獨立的類,所有方法(絕大多數都只屬於它自己)都是從零開始寫的。這可能是因為RandomAccessFile能在文件裡面前後移動,所以它的行為與其它的I/O類別有些根本性的不同。總而言之,它是一個直接繼承Object的,獨立的類別。
進階篇:
在nio中,Java重新實現了I/O流,並且引入了一些新的方法來提高速度。我主要介紹通道、記憶體映射檔
1.通道:
通道和緩衝器是一個成對的概念,Thinking in Java中的一個例子特別好理解:我們把想要讀入的文件看作一個煤礦,數據就是我們想要的煤炭。通道好比是傳送煤礦的傳送帶,我們沒有辦法直接從傳送帶上拿走煤炭,只好利用卡車來裝載這些煤炭,卡車就是緩衝器,它主要負責從通道中取出數據,傳給我們寫的程序。唯一能與通道互動的緩衝器是ByteBuffer。可以看出和通道支援的解析流的方式是位元組流。所以它配套使用的是FileInputStream/FileOutputStream,RandomAccessFile
例子:
a.
FileChannel fc =new FileOutputStream(filename).getChannel(); fc.write(ByteBuffer.wrap("something test".getBytes() ));//这里使用ByteBuffer比较简单,其实ByteBuffer可以利用个put()函数写入byte数组 fc.close();
b.
fc= new FileOutputStream(filename).getChannel(); ByteBuffer buff = ByteBuffer.allocate(size);//没错,ByteBuffer是不提供显示构造函数的,想要新建一个对象必须利用allocate()函数来分配空间。 fc.read(buff); fc.close();
為什麼想到要用通道來做I/O?主要考慮的是性能問題,通道加緩衝器能夠讓程式一些讀寫一定量的字符,而只使用InputStream/OutputStream,Reader/Writer只能一次讀寫一個位元組/字符。而程式在進行I/O時要交給作業系統去解決這部分功能(呼叫系統呼叫),減少交給作業系統的次數可以有效的消減I/O花費的時間
2.記憶體映射檔:
記憶體映射檔案主要的意思其實假定將檔案都放入記憶體中,把它當作非常大的數組來訪問,效率特別好。為什麼比較好呢?這要從Java虛擬機和作業系統開始說起le(其實我也不太懂,剛才看了一篇文章講的比較清晰,連結是http://www.360doc.com/content ...)這篇文章主要介紹了Java I/O的原理以及記憶體映射檔案的原理。我嘗試概括一下:Java I/O主要的實作手段肯定是利用系統調用,而係統調用先將想要使用的檔案從硬碟調入到核心的I/O緩衝區中,這次會導入比Java程序想要的檔案更多的內容(拷入更多的內容是因為程式的局部性原理,能夠得到更好的效率),然後再從核心的I/O緩衝區導入到Java進程自己的私有記憶體空間中。而記憶體映射檔案放棄了兩次拷貝的方法,直接將Java進程的虛擬空間與檔案物件構成一個映射,當私有記憶體空間找不打想要的內容時發生缺頁異常,然後利用更底層的系統呼叫解決這個問題(其實在I/O的系統呼叫中也涉及到了缺頁異常處理),好處就是減少了一次從內核I/O緩衝區到進程私有地址的開銷。
例子:
FileChannel fc = new RandomAccessFile(filename,"rw").getChannel(); MappedByteBuffer mb = fc.map(FileChannel.MapMode.READ_WRITE,start,length); mb.put((byte)'x'); mb.get(); fc.close();