今天在使用Java NIO的Channel和Buffer进行文件操作时候,报了java.nio.charset.MalformedInputException: Input length = 1异常,具体如下:
  1. java.nio.charset.MalformedInputException: Input length = 1
  2. at java.nio.charset.CoderResult.throwException(CoderResult.java:260)
  3. at java.nio.charset.CharsetDecoder.decode(CharsetDecoder.java:781)
  4. at cn.fuxi.nio.ReadFile.main(ReadFile.java:37)

具体的Java源代码如下:ReadFile.java

  1. public class ReadFile {
  2. public static void main(String[] args) {
  3. FileInputStream fis;
  4. try {
  5. fis = new FileInputStream("a.txt");
  6. FileChannel channel = fis.getChannel();
  7. // 定义一个ByteBuffer,用于重复读取数据
  8. ByteBuffer byteBuffe = ByteBuffer.allocate(64);// 每次取出64字节
  9. // 将FileChannel的数据放入ByteBuffer中
  10. while (channel.read(byteBuffe) != -1) {
  11. // 锁定ByteBuffer的空白区
  12. byteBuffe.flip();
  13. /* 创建Charset对象 */
  14. Charset charset = Charset.forName("GBK");
  15. // 创建解码器
  16. CharsetDecoder charsetDecoder = charset.newDecoder();
  17. // 将ByteBuffer的内容转码
  18. CharBuffer charBuffer = charsetDecoder.decode(byteBuffe);
  19. // CharBuffer charBuffer = charset.decode(byteBuffe);
  20. System.out.println(charBuffer);
  21. // 将ByteBuffer初始化,为下一次读取数据做准备
  22. byteBuffe.clear();
  23. }
  24. } catch (Exception e) {
  25. // TODO: handle exception
  26. e.printStackTrace();
  27. }
  28. }
  29. }

我要读取的a.txt文件内容很简单,如下所示:
  1. This is just test for FileChannel
  2.  
  3. 小心会报异常: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()方法。
即将下面的代码:
  1. /* 创建Charset对象 */
  2. Charset charset = Charset.forName("GBK");
  3. // 创建解码器
  4. CharsetDecoder charsetDecoder = charset.newDecoder();
  5. // 将ByteBuffer的内容转码
  6. // CharBuffer charBuffer = charsetDecoder.decode(byteBuffe);

改为:

  1. /* 创建Charset对象 */
  2. Charset charset = Charset.forName("GBK");
  3. CharBuffer charBuffer = charset.decode(byteBuffe);

但是这样改掉之后,也会出现下面的乱码问题,所以也不提倡。

  1. This is just test for FileChannel
  2. 小心会报异常:java.nio.charset.MalformedInputException: Input length = 1,看到底是什么鬼原因弄成的。
  3. This is just test for FileChannel
  4. 小心会报异常:java.nio.charset.MalformedInputException: Input length = 1,看到底?
  5. 鞘裁垂碓蚺傻摹?


第三个解决方法:每次都去判断一下Bytebuffer中最后一个字节是否合法。如果不合法,则说明这个字节是双字节汉字的一部分,这样我们解码时就不要包含这个字节,而是把这个字节放进下次解码之前的Bytebuffer中。这样做,系统就不会抛出“无法正确解码”这类的异常了。

该方法的具体解决代码怎么改,今天头脑有点痛,没时间改了,下次改了再发上来。(可以看看
http://songjianyong.iteye.com/blog/1399241 寻找思路)

第四种方法:使用FileChannel.map()方法一次将所有文件内容映射到内存中,但是这样如果读取的文件过大的话,会引起性能的下降。代码如下:
  1. public class FileChannelTest {
  2. public static void main(String[] args) {
  3. try {
  4. File file=new File("abc.txt");
  5. //以文件输入流FileInputStream创建FileChannel,以控制输入
  6. FileChannel inChannel=new FileInputStream(file).getChannel();
  7. //以文件输出流FileOutputStream创建FileChannel,以控制输出
  8. FileChannel outChannel=new FileOutputStream("a.txt").getChannel();
  9. //将FileChannel里的全部数据映射成ByteBuffer
  10. MappedByteBuffer buffer=inChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
  11. //直接将buffer里的数据全部输出
  12. outChannel.write(buffer);
  13. //再次调用buffer的clear()方法,复原limit、position的位置
  14. buffer.clear();
  15. //使用GBK字符集来创建解码器
  16. Charset charset=Charset.forName("GBK");
  17. //创建解码器(CharsetDecoder)对象
  18. CharsetDecoder decoder=charset.newDecoder();
  19. //使用解码器将ByteBuffer转换成CharBuffer
  20. CharBuffer charBuffer=decoder.decode(buffer);
  21. System.out.println(charBuffer);
  22. } catch (Exception e) {
  23. // TODO: handle exception
  24. e.printStackTrace();
  25. }
  26. }
  27. }


哎,忙了一个晚上,还是没有真正的解决java.nio.charset.MalformedInputException: Input length = 1异常,惭愧。如果有大神来帮我解决解决,感激不尽。



==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址:http://blog.csdn.net/ouyang_peng

==================================================================================================




我的Java开发学习之旅------>Java NIO 报java.nio.charset.MalformedInputException: Input length = 1异常的更多相关文章

  1. 我的Java开发学习之旅------>工具类:Java使用正则表达式分离出字符串中的中文和英文

    今天看到一个工具类使用正则表达式将一大段字符串中的中文和英文都分离出来了,在此记录一下,读者可以收藏! import java.util.ArrayList; import java.util.Col ...

  2. 我的Java开发学习之旅------>工具类:Java获取字符串和文件进行MD5值

    ps:这几天本人用百度云盘秒传了几部大片到云盘上,几个G的文件瞬秒竟然显示"上传成功"!这真让我目瞪口呆,要是这样的话,那得多快的网速,这绝对是不可能的,也许这仅是个假象.百度了一 ...

  3. 我的Java开发学习之旅------>Java 格式化类(java.util.Formatter)基本用法

    本文参考: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html http://www.blogjava.net/ ...

  4. 我的Java开发学习之旅------>工具类:将播放器的进度值转换成相应的时间格式

    在我的博客<我的Java开发学习之旅------>Java 格式化类(java.util.Formatter)基本用法,地址:http://blog.csdn.net/ouyang_pen ...

  5. org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1

    项目启动报错2018-12-21 14:06:24.917 INFO 23472 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refr ...

  6. scala文件读取报错“java.nio.charset.MalformedInputException: Input length = 1”

    今天写spark程序的时候遇到了一个问题就是,读取文件的时候报了一个错:“Exception in thread "main" java.nio.charset.Malformed ...

  7. protobuf接口调用报错:java.nio.charset.MalformedInputException: Input length = 1

    使用protobuf定义的接口api发起http请求报错,日志如下: [-- ::] DEBUG AbstractPool: - server updated, node=, server={ nod ...

  8. windows中文编码报错 com.google.gson.JsonIOException: java.nio.charset.MalformedInputException: Input length = 1

    昨天碰到一个问题:同一个请求页面,页面经过匹配后调用http的post协议接口,部署在linux环境的没问题,本地Eclipse启动的tomcat也没问题,直接启动本地tomcat却报错了: 18:4 ...

  9. Caused by: java.nio.charset.MalformedInputException: Input length = 1

    java.lang.IllegalStateException: Failed to load property source from location 'classpath:/applicatio ...

随机推荐

  1. [TJOI2014] 上升子序列

    刚刚做的时候一看:这不是个傻逼题吗hhhhh....然后发现写完了过不了样例,仔细一看题:同构的算一种. 这可咋办啊? 其实很简单,设f[i] 为 以a[i] 结尾的上升子序列个数,我们考虑当前如果算 ...

  2. 输出n行等腰三角形(符号为*)

    输出n行等腰三角形(符号为*) 1. 核心操作 First, 找出每一行的第一个*之前需要的空格个数 规律1:设该等腰三角形一共N行, 那么第n行的第一个*之前需要的空格个数就为N-n个空格 推导过程 ...

  3. Android-Handler消息机制实现原理

    一.消息机制流程简介 在应用启动的时候,会执行程序的入口函数main(),main()里面会创建一个Looper对象,然后通过这个Looper对象开启一个死循环,这个循环的工作是,不断的从消息队列Me ...

  4. web.xml文件的 xsd引用(或dtd引用)学习

    1. 为什么web.xml会有不同版本的xsd引用: JDK依赖变化: 或 servlet(JAVA EE)自身API的改变: 2. 为什么会有dtd和xsd两个版本的区别 我是在这篇文章中看到的,作 ...

  5. hdu1061(C++)

    简单的找规律,不妨设N=10*x+a(a=N%10),那么N^N=(10*x+a)^N,用二项式展开定理可以知道N^N%10=a^N%10; 由于0<a<10,打表a^1,a^2,a^3, ...

  6. 简单便捷的纯PHP网盘程序 Veno File Manager 2.6.3(VFM2)

    体验过很多国外网盘程序,例如:Owncloud.Bedrive.YetiShare.XFilesharing.uCloud.Cloudshare 等等,诸如此类,VFM2与这些臃肿的商用或非商用来的程 ...

  7. 自学MVC看这里——全网最全ASP.NET MVC 教程汇总【转】

    自学MVC看这里——全网最全ASP.NET MVC 教程汇总 http://www.cnblogs.com/powertoolsteam/archive/2015/08/13/4667892.html ...

  8. df、du、fdisk:Linux磁盘管理

    磁盘是Linux系统中一项非常重要的资源,如何对其进行有效的管理直接关系到整个系统的性能问题.对Linux磁盘管理稍微有一些学习和经验的朋 友们应该都知道df.du和fdisk这三个常用命令:df用于 ...

  9. grep 精确匹配

    使用grep实现精确过滤的五种方法 (1)当被过滤的内容占据一行时 [root@MySQL scripts]# cat oldboy.log        200 0200 2000 [root@My ...

  10. widget 常用UI控件介绍

        一.单选框 单选框实例程序: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&q ...