NIO解决乱码问题

造成NIO乱码的问题是因为读取的信息是按照特定编码读取的字节流信息,读取的时候受到读取限定,就有可能出现读取的不是一个完整的字节数组信息。

例如: 你好啊 。

在UTF-8的字节数组是[-28,-67,-96,-27,-91,-67,-27,-107,-118]。

在GBK的字节数组是[-60,-29,-70,-61,-80,-95]。

在unicode中数值是 20320,22909,21834。
   
 转码就需要完整的字节信息,utf-8中[-28,-67,-96]代表  你 ,如果读取字节流信息的时候制度去到[-28]或者[-28,-67]这种不完整的编码,那么转码成unicode就会变成乱码。因此解决乱码就是需要我们将多读取的字节信息截留,下次完整读取。

以下是针对utf-8 与GBK文件的解决代码,其他编码没有测试过。

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class Test {
	public static void main(String[] args) {
             //GBK文件 使用 GBK编码
		new Test().readFile("C:\\Users\\Administrator\\Desktop\\1.txt", "UTF-8");
	}

	public void readFile(String path, String charsetName) {
		Charset c = Charset.forName(charsetName);
		// 解码器,字节流信息转换为字符信息
		CharsetDecoder decoder = c.newDecoder();
		try (RandomAccessFile raf = new RandomAccessFile(path, "r"); FileChannel fc = raf.getChannel();) {
			// 设置成5是因为不管是UTF-8还是GBK在全中文文档都会出字节信息被截取的情况,也就是所谓会出现乱码。
			//这样方便测试
			ByteBuffer bytes = ByteBuffer.allocate(5);
			CharBuffer cb = CharBuffer.allocate(5);
			int size = fc.read(bytes);
			while (size != -1) {
				bytes.flip();
				//size<5,小于5的时候说明文件已经读取结束了
				//为了防止源文件就是一个破损的文件,末尾有不符合规范的字节流
				//当末尾的时候就不做截留操作,直接转码
				decoder.decode(bytes, cb, size<5);
				cb.flip();
				System.out.print(cb.toString());
				//全中文文档第一次读取的时候,五个字节就是说UTF-8和GBK的文档都会有一个字节信息未被读取
				//这个时候需要保存多读取的信息,UTF-8中sub=2,后面两个属于非正常字节信息
				//GBK的时候sub=1 只有一个非正常的自己信息
                            //后面继续读取的时候将会根据实际情况进行截留
				int sub = bytes.limit()-bytes.position();
				bytes.clear();
				cb.clear();
				//将读取的定位值 减去多读取的信息
				fc.position(fc.position()-sub);
				size = fc.read(bytes);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

转载于:https://my.oschina.net/u/3704615/blog/1571573

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值