java randomaccessfile 乱码_Java 8 RandomAccessFile 读取 UTF-8 乱码

问题结论

为什么 RandomAccessFile 的 readLine() 读 UTF-8 文件是乱码?

RandomAccessFile 的函数 readLine() 使用 ISO-8859-1 解码文件,所以读取 UTF-8 的文件会造成乱码。解决方式就是再使用ISO-8859-1编码得到原先的byte[]数组,再用这个数组重新构造 String 即可。

但是使用ISO-8859-1解码并没有在文档中提及,这个隐藏特性的来源是什么呢?

源码之下,了无秘密

首先查看 readLine() 的源码

public final String readLine() throws IOException {

StringBuffer input = new StringBuffer();

int c = -1;

boolean eol = false;

while (!eol) {

switch (c = read()) {

case -1:

case '\n':

eol = true;

break;

case '\r':

eol = true;

long cur = getFilePointer();

if ((read()) != '\n') {

seek(cur);

}

break;

default:

input.append((char)c);

break;

}

}

if ((c == -1) && (input.length() == 0)) {

return null;

}

return input.toString();

}

readLine 实际上就是通过迭代 read() 函数读取单个字节,并把每个字节转化成 char 类型依次装入 input 中,在遇到换行符之后停止操作。这里我们可以注意到有趣的一点,就是他对于不同协议中的两种换行符都做了考虑。

所以我们继续探索 read() 函数

read() 源码

public int read() throws IOException {

return read0();

}

read() 函数非常的简单,通过注释我了解到,read() 的作用就是读取一个字节的内容,并把这个字节装入 int 中返回。

思考

再回头看 readLine(),这两个函数都非常的简单,无论是代码还是注释根本就没有提什么 ISO-8859-1标准,那这一行是怎么莫名其妙的被以 ISO-8859-1 解码的呢。

这是因为,Java 的 char 类型使用的是Unicode。而ISO-8859-1是一位定长的字符集,Unicode 的前256位和ISO-8859-1是重合的。换句话说,Unicode的前256位就是ISO-8859-1。所以在 readLine() 中对每一字节进行读取并立即转化成 char 类型的过程,就相当于完成了 ISO-8859-1 解码。

而我们要想得到原始的 byte 串怎么办呢?有两种方法,一种就是把 readLine() 读出的 String 用 ISO-8859-1 编码转回 编码前的 byte[] 数组。

import java.io.IOException;

import java.io.RandomAccessFile;

public class LearnBytes {

public static void main(String[] args) throws IOException {

String path = "files/t.txt";

RandomAccessFile rf = new RandomAccessFile(path, "rw");

String buffer = rf.readLine();

byte[] originalBytes = buffer.getBytes("ISO-8859-1”); //反编码回文件中本原始的字节流

String utf8 = new String(originalBytes); //String 构造函数默认接受 UTF-8 编码

}

}

另一种方法就是通过 read() 自己写一个readLine()函数,返回值是byte[]类型。

总结

It’s not a bug. It’s an undocumented feature.

参考及补充

严格来讲,ISO-8859-1 和 Java char 使用的 Unicode 是字符集。而 UTF-8 是基于 Unicode 的编码方式。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值