javanio中⽂乱码_JavaNIO下使⽤ByteBuffer读取⽂本时解决
UTF-8概。。。
场景:
读取⼀个⼤⽂本⽂件,并输出到控制台。
在这⾥我们选择使⽤nio进⾏读取⽂本⽂件,在输出的过程中,有些⽂件中英⽂都显⽰正常,有些则偶尔出现中⽂乱码,经思考发现,在ByteBuffer.allocate 时分配空间,如果中英混合的⽂件中就会出现中⽂字符只读取了⼀部分的问题,如果⽂本为等长编码字符集的时候,可以根据编码集 byte 长度进⾏ allocate ,例如 GBK 为2 byte ,所以我们 allocate 时未2的倍数即可,但像 UTF-8 这类变长的编码字符集时则没那么简单了。
下⾯就是 UTF-8 的编码⽅式
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
对于 UTF-8 编码中的任意字节 B ,如果 B 的第⼀位为0,则 B 为 ASCII 码,并且 B 独⽴的表⽰⼀个字符;
如果 B 的第⼀位为1,第⼆位为0,则B为⼀个⾮ ASCII 字符(该字符由多个字节表⽰)中的⼀个字节,并且不是字符的第⼀个字节编码;
如果 B 的前两位为1,第三位为0,则B为⼀个⾮ ASCII 字符(该字符由多个字节表⽰)中的第⼀个字节,并且该字符由两个字节表⽰;
如果 B 的前三位为1,第四位为0,则B为⼀个⾮ ASCII 字符(该字符由多个字节表⽰)中的第⼀个字节,并且该字符由三个字节表⽰;
如果 B 的前四位为1,第五位为0,则B为⼀个⾮ ASCII 字符(该字符由多个字节表⽰)中的第⼀个字节,并且该字符由四个字节表⽰;
通过分析我们发现,在读取中我们通过处理临界值来解决 UTF-8 编码字符读取问题。
⽰例代码如下:
RandomAccessFile rf = new RandomAccessFile("zh.txt", "rw");
FileChannel channel = rf.getChannel();java语言使用的字符码集是
ByteBuffer buffer = ByteBuffer.allocate(4); // ⾄少为4,因为UTF-8最⼤为4字节
while (ad(buffer) != -1) {
byte b;
int idx;
out :
for (idx = buffer.position()-1; idx >= 0; idx--) {
b = (idx);
if ((b & 0xff) >> 7 == 0) { // 0xxxxxxx
break;
}
if ((b& 0xff & 0xc0) == 0xc0) { // 11xxxxxx,110xxxxx、1110xxxx、11110xxx
idx -= 1;
break;
}
if ((b & 0xff & 0x80) == 0x80) {
for (int i = 1; i < 4; i++) {
b = (idx - i);
if ((b & 0xff & 0xc0) == 0xc0) {
if ((b & 0xff) >> (5 + 1 - i) == 0xf >> (3 - i)) {
break out;
} else {
idx = idx - 1 - i;
break out;
}
}
}
}
}
buffer.flip();
int limit = buffer.limit();
buffer.limit(idx+1); // 阻⽌读取跨界数据
System.out.println(Charset.forName("UTF-8").decode(buffer).toString()); buffer.limit(limit); // 恢复limit
bufferpact();
}
channel.close();
rf.close();
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论