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-8sub=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();
        }
    }
}

你可能感兴趣的:(java)