今天在使用Java NIO的Channel和Buffer进行文件操作时候,报了java.nio.charset.MalformedInputException: Input length = 1异常,具体如下:
java.nio.charset.MalformedInputException: Input length = 1 at java.nio.charset.CoderResult.throwException(CoderResult.java:260) at java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:781) at cn.fuxi.nio.ReadFile.main(ReadFile.java:37)
具体的Java源代码如下:ReadFile.java
public class ReadFile { public static void main(String[] args) { FileInputStream fis; try { fis = new FileInputStream("a.txt"); FileChannel channel = fis.getChannel(); // 定义一个ByteBuffer,用于重复读取数据 ByteBuffer byteBuffe = ByteBuffer.allocate(64);// 每次取出64字节 // 将FileChannel的数据放入ByteBuffer中 while (channel.read(byteBuffe) != -1) { // 锁定ByteBuffer的空白区 byteBuffe.flip(); /* 创建Charset对象 */ Charset charset = Charset.forName("GBK"); // 创建解码器 CharsetDecoder charsetDecoder = charset.newDecoder(); // 将ByteBuffer的内容转码 CharBuffer charBuffer = charsetDecoder.decode(byteBuffe); // CharBuffer charBuffer = charset.decode(byteBuffe); System.out.println(charBuffer); // 将ByteBuffer初始化,为下一次读取数据做准备 byteBuffe.clear(); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
我要读取的a.txt文件内容很简单,如下所示:
This is just test for FileChannel 小心会报异常:java.nio.charset.MalformedInputException: Input length = 1,看到底是什么鬼原因弄成的。
查看了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()方法。
即将下面的代码:
/* 创建Charset对象 */ Charset charset = Charset.forName("GBK"); // 创建解码器 CharsetDecoder charsetDecoder = charset.newDecoder(); // 将ByteBuffer的内容转码 // CharBuffer charBuffer = charsetDecoder.decode(byteBuffe);改为:
/* 创建Charset对象 */ Charset charset = Charset.forName("GBK"); CharBuffer charBuffer = charset.decode(byteBuffe);
但是这样改掉之后,也会出现下面的乱码问题,所以也不提倡。
This is just test for FileChannel 小心会报异常:java.nio.charset.MalformedInputException: Input length = 1,看到底是什么鬼原因弄成的。 This is just test for FileChannel 小心会报异常:java.nio.charset.MalformedInputException: Input length = 1,看到底? 鞘裁垂碓蚺傻摹?
该方法的具体解决代码怎么改,今天头脑有点痛,没时间改了,下次改了再发上来。(可以看看
http://songjianyong.iteye.com/blog/1399241 寻找思路)
第四种方法:使用FileChannel.map()方法一次将所有文件内容映射到内存中,但是这样如果读取的文件过大的话,会引起性能的下降。代码如下:
public class FileChannelTest { public static void main(String[] args) { try { File file=new File("abc.txt"); //以文件输入流FileInputStream创建FileChannel,以控制输入 FileChannel inChannel=new FileInputStream(file).getChannel(); //以文件输出流FileOutputStream创建FileChannel,以控制输出 FileChannel outChannel=new FileOutputStream("a.txt").getChannel(); //将FileChannel里的全部数据映射成ByteBuffer MappedByteBuffer buffer=inChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); //直接将buffer里的数据全部输出 outChannel.write(buffer); //再次调用buffer的clear()方法,复原limit、position的位置 buffer.clear(); //使用GBK字符集来创建解码器 Charset charset=Charset.forName("GBK"); //创建解码器(CharsetDecoder)对象 CharsetDecoder decoder=charset.newDecoder(); //使用解码器将ByteBuffer转换成CharBuffer CharBuffer charBuffer=decoder.decode(buffer); System.out.println(charBuffer); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
==================================================================================================
作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/ouyang_peng
==================================================================================================