
今天在使用Java NIO的Channel和Buffer進行檔案操作時候,報了java.nio.charset.MalformedInputException: Input length = 1異常,具體如下:
具體的Java源代碼如下:ReadFile.java
我要讀取的a.txt檔案内容很簡單,如下所示:
檢視了Java API的官方關于 MalformedInputException的說明如下:
Checked exception thrown when an input byte sequence is not legal for given charset, or an input character sequence is not a legal sixteen-bit Unicode sequence.
翻譯過來就是:當輸入位元組序列對于給定 charset 來說是不合法的,或者輸入字元序列不是合法的 16 位 Unicode 序列時,抛出此經過檢查的異常。
說白了,會出現java.nio.charset.MalformedInputException異常,原因是“半個中文問題”。分析上面的程式,就是因為CharsetDecoder對ByteBuffer進行解碼的時候,不能保證都可以成功解碼成漢字,也許裡面有“半個漢字“也說不準。說以當有半個漢字的時候就會出現該異常。
舉個例子,因為在GBK中字母占1byte,漢字占2byte。如"我ABC漢字d"這個字元串,截取5個位元組的時候,應該是"我ABC",而截取8個位元組的時候,應該是"我ABC漢",而不應該是"我ABC漢?",其中"?"為半個漢字,可了解為向前截取 。是以就會報異常。 (備注:将字元編碼GBK改為UTF-8,則每個中文長度按3個字元計算 )
我第一個的解決方法是:
将ByteBuffer byteBuffe = ByteBuffer.allocate(64);這行代碼改為ByteBuffer
byteBuffe = ByteBuffer.allocate(1024);
因為我要讀取的a.txt檔案不大,如果一次性讀取1024個位元組的話,大于a.txt檔案的總大小,是以a.txt檔案一次性就讀完了。是以并不會報異常了。
但是如果我要讀取的a.txt檔案的大小大于1024個位元組的話,該異常還是有可能會爆出來。是以該方法不對。
我第二個解決方法是:
将CharsetDecoder.decode()方法去掉,直接直接使用Charset.decode()方法。
即将下面的代碼:
改為:
但是這樣改掉之後,也會出現下面的亂碼問題,是以也不提倡。
第三個解決方法:每次都去判斷一下Bytebuffer中最後一個位元組是否合法。如果不合法,則說明這個位元組是雙位元組漢字的一部分,這樣我們解碼時就不要包含這個位元組,而是把這個位元組放進下次解碼之前的Bytebuffer中。這樣做,系統就不會抛出“無法正确解碼”這類的異常了。
該方法的具體解決代碼怎麼改,今天頭腦有點痛,沒時間改了,下次改了再發上來。(可以看看
第四種方法:使用FileChannel.map()方法一次将所有檔案内容映射到記憶體中,但是這樣如果讀取的檔案過大的話,會引起性能的下降。代碼如下:
哎,忙了一個晚上,還是沒有真正的解決java.nio.charset.MalformedInputException: Input length = 1異常,慚愧。如果有大神來幫我解決解決,感激不盡。
==================================================================================================
作者:歐陽鵬 歡迎轉載,與人分享是進步的源泉!
