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

简介: 今天在使用Java NIO的Channel和Buffer进行文件操作时候,报了java.nio.charset.MalformedInputException: Input length = 1异常,具体如下: java.

今天在使用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,看到底?
鞘裁垂碓蚺傻摹?


第三个解决方法:每次都去判断一下Bytebuffer中最后一个字节是否合法。如果不合法,则说明这个字节是双字节汉字的一部分,这样我们解码时就不要包含这个字节,而是把这个字节放进下次解码之前的Bytebuffer中。这样做,系统就不会抛出“无法正确解码”这类的异常了。
该方法的具体解决代码怎么改,今天头脑有点痛,没时间改了,下次改了再发上来。(可以看看 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();
		}
	}
}


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


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

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

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

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






相关文章
|
15天前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
|
1天前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
26天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
110 13
|
1月前
|
算法 Java API
如何使用Java开发获得淘宝商品描述API接口?
本文详细介绍如何使用Java开发调用淘宝商品描述API接口,涵盖从注册淘宝开放平台账号、阅读平台规则、创建应用并申请接口权限,到安装开发工具、配置开发环境、获取访问令牌,以及具体的Java代码实现和注意事项。通过遵循这些步骤,开发者可以高效地获取商品详情、描述及图片等信息,为项目和业务增添价值。
63 10
|
24天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
59 2
|
6月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
8月前
|
存储 监控 Java
深入探索Java语言的NIO(New I/O)技术
深入探索Java语言的NIO(New I/O)技术
|
6月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
|
6月前
|
Java 大数据
如何在Java中进行网络编程:Socket与NIO
如何在Java中进行网络编程:Socket与NIO
|
6月前
|
Java
Java中的NIO编程详解
Java中的NIO编程详解
下一篇
开通oss服务