您的位置:首页 > Web前端

使用ByteBuffer一个一个字节读取数据

2017-06-25 00:00 423 查看
最近在使用Java NIO读取一篇文章(txt),是使用ByteBuffer读取的。代码如下:

RandomAccessFile aFile = new RandomAccessFile("E:/test1.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int bytesRead = inChannel.read(buf); //read into buffer.
while (bytesRead != -1) {
buf.flip(); //make buffer ready for read
while(buf.hasRemaining()){
System.out.print((char) buf.get());// read 1 byte at a time
}
buf.clear(); //make buffer ready for writing
bytesRead = inChannel.read(buf);
}
aFile.close();

运行的结果显示是乱码,如:￯ᄏ﾿₩ワᆲ￧ロᆴ¥ᄑユ¦ᄌᄎ│﾿ナ←ロᄋ￧ワヒ￧ワヒ￧レト￧ᄐモ¥ᆳリ￧ロᆴ¥ᄑユ ̄タツ

其实也可以预想到不同编码格式,使用的字节数不一样。我读的文本时UTF-8的,但是UTF-8使用的字节数不一样,最大为4个字节。为了等正确的读出文字(不乱码),查看了一下UTF-8的编码格式:

一个utf8数字占1个字节

一个utf8英文字母占1个字节

少数是汉字每个占用3个字节,多数占用4个字节。

那怎么知道一个汉字占几个字节那,原来可以通过第一个字节中高4中1的个数来确定。包含几个1,就说明占几位。先看一下UTF-8的一点知识:

UTF-8是Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

从网上找个图更直观:

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

既然知道规则,那个就按照规则解析了。修改一下代码:

RandomAccessFile aFile = new RandomAccessFile("E:/test1.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int bytesRead = inChannel.read(buf); //read into buffer.
while (bytesRead != -1) {
buf.flip(); //make buffer ready for read
while(buf.hasRemaining()){
byte b = buf.get();
int a=b&0xf0;//获取高4位1的个数
int cout=1;
switch (a) {
case 0x80: //0x80 表示1个1
cout=1;
break;
case 0xC0://0x80 表示2个1
cout=2;
break;
case 0xE0://0x80 表示3个1
cout=3;
break;
case 0xF0://0x80 表示4个1
cout=4;
break;
default:
break;
}
byte[] by=new byte[4]; //用于存储一个UTF-8字符
by[0]=b;
for (int i = 2; i <= cout; i++) { //获取一个完整UTF-8字符
by[i]=buf.get();
}
System.out.print(new String(by,0,cout));
}
buf.clear(); //make buffer ready for writing
bytesRead = inChannel.read(buf);
}
aFile.close();

OK,正确读出文字了,不乱码了。可能不太全面。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  UTF-8 ByteBuffer NIO