Java写文件导致io过高_161108、Java IO流读写文件的几个注意点
平時(shí)寫IO相關(guān)代碼機(jī)會(huì)挺少的,但卻都知道使用BufferedXXXX來讀寫效率高,沒想到里面還有這么多陷阱,這兩天突然被其中一個(gè)陷阱折騰一下:讀一個(gè)文件,然后寫到另外一個(gè)文件,前后兩個(gè)文件居然不一樣?
解決這個(gè)問題之后,總結(jié)了幾個(gè)注意點(diǎn)。
注意點(diǎn)一:Reader/Writer讀寫二進(jìn)制文件是有問題的?:
上面代碼使用BufferedReader一行一行地讀取一個(gè)文件,然后使用BufferedWriter把讀取到的數(shù)據(jù)寫到另外一個(gè)文件中。如果文件是ASCCII形式的,則內(nèi)容還是能夠正確讀取的。但如果文件是二進(jìn)制的,則讀寫后的文件與讀寫前是有很大區(qū)別的。當(dāng)然,把上面的readLine()換成read(char[])仍然不能正確讀寫二進(jìn)制文件的。讀寫二進(jìn)制文件請(qǐng)接著看下面注意點(diǎn)。
注意點(diǎn)二:read(byte[] b, int offset, int length)中的offset不是指全文件的全文,而是字節(jié)數(shù)組b的偏移量
現(xiàn)在已經(jīng)知道使用Reader/Writer不能正確讀取二進(jìn)制文件,這是因?yàn)镽eader/Writer是字符流,那就改用字節(jié)流ufferedInputStream/BufferedOutputStream,網(wǎng)上搜索到的例子大概是這樣的:
每次讀1024字節(jié),然后寫1024字節(jié)。這看似挺正確的,但實(shí)際寫出來的文件與原文件是不同的。這樣就懷疑可能是讀寫沒有接上,因而把代碼改成下面的形式:
這是誤以為:先讀一段,寫一段,然后改變偏移量,然后使用新的偏移量再讀一段、寫一段,直到文件讀寫完畢。但這是錯(cuò)誤的,因?yàn)槭褂肂ufferedXXX后,里面已經(jīng)實(shí)現(xiàn)了這個(gè)過程。而read(byte[] b, int offset, int length)中的offset實(shí)際指的是把讀到的數(shù)據(jù)存入到數(shù)組b時(shí),從數(shù)組的哪個(gè)位置(即offset)開始放置數(shù)據(jù);同理,write(byte[] b, int offset, int length)就是把b中的數(shù)據(jù),從哪個(gè)位置(offset)開始寫到文件中。
注意點(diǎn)三:使用?length=read?(b, 0, 1024)讀數(shù)據(jù)時(shí),應(yīng)該使用write(b, 0, length)來寫
第二個(gè)注意點(diǎn)中的第一段代碼的做法雖然在網(wǎng)上比較常見,但是有問題的。問題在哪呢?答案是:問題在byte[] b這個(gè)數(shù)組上。由于二進(jìn)制文件使用比較工具時(shí),只知道不同、但不能知道哪些不同(是否有更先進(jìn)的比較工具?)。怎樣確定它的不同呢?方法很簡(jiǎn)單:就把二進(jìn)制文件改成文本文件就能看出結(jié)果了(Reader/Writer這種字符流雖然不能正確讀寫二進(jìn)制文件,但I(xiàn)nputStream/OutputStream這些字節(jié)流能既能正確讀寫二進(jìn)制文件,也能正確讀寫文本文件)。由于使用了每次讀1K(1024字節(jié))的方式,所以會(huì)看到的結(jié)果是:寫后的文件后面多出一段,這一段的長(zhǎng)度與原文件大小以及b數(shù)組的大小有關(guān)。為了進(jìn)一步確定是什么關(guān)系,把讀的文件內(nèi)容改為"1234567890123",而把b數(shù)組的大小改為10字節(jié),這時(shí)結(jié)果就出來了:寫后的文件內(nèi)容變成"12345678901234567890",就是讀了兩遍。多出的內(nèi)容的根源在這里:b數(shù)組的大小是10字節(jié),而要讀的內(nèi)容長(zhǎng)度是13字節(jié),那就要讀兩次,第一次讀了前10字節(jié),此時(shí)b數(shù)組內(nèi)的元素為前10個(gè)字符;再讀第二次時(shí),由于可讀內(nèi)容只有3個(gè)字符,那b數(shù)組的內(nèi)容只有前3個(gè)字符被改變了,后面7個(gè)字符仍然保持上一次讀取的內(nèi)容。所以直接采用write(b)的方式,在第二次寫文件時(shí),內(nèi)容就多寫了一段不是第二次讀取到的內(nèi)容。
下面是正確的讀寫(即每次讀了多少內(nèi)容,寫入的是多少內(nèi)容,而不是寫入整個(gè)數(shù)組):
注意點(diǎn)四:flush()和close()
flush()是把寫緩沖區(qū)內(nèi)的內(nèi)容全部”吐“到文件上,如果沒有它,就有可能很多內(nèi)容還存在于寫緩沖區(qū)內(nèi),而不是在文件中,也就是還有丟失的可能。
close()中會(huì)調(diào)用flush()。它是文件真正完成的標(biāo)志,文件內(nèi)容寫完成后不關(guān)閉文件流,會(huì)導(dǎo)致一些”古怪“的問題。這個(gè)在網(wǎng)絡(luò)中的流更能體現(xiàn)。
所以,寫文件完成后注意關(guān)閉文件讀寫流。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Java写文件导致io过高_161108、Java IO流读写文件的几个注意点的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cyb2k.exe是安全进程吗 cyb2
- 下一篇: java生命小游戏_Java修炼——飞机