一个Java的低级错误:不要尝试用字节流读取有中文的内容

大老赖不赖 36 2022-10-29

使用字节流读取

public class GarbledCodeExample {
    public static void main(String[] args) throws IOException {
        File json = new File(Config.JSON_PATH);
        FileInputStream fis = new FileInputStream(json);
        BufferedInputStream bis = new BufferedInputStream(fis);
        byte[] cache = new byte[1024];
        int len = bis.read(cache);
        StringBuffer sb = new StringBuffer();
        while (len != -1) {
            sb.append(new String(cache));
            len = bis.read(cache, 0, cache.length);
        }
        bis.close();
        fis.close();
        //数据处理
        JSONArray array = new JSONArray(sb.toString());
        for (int i = 0; i < array.length(); i++) {
            JSONObject o = array.getJSONObject(i);
            String v = o.getString("name");
            if (!Charset.forName("GBK").newEncoder().canEncode(v)) {
                System.out.println(v);
            }
        }
    }
}

就会出现:
image
我们尝试将字节数组调小,每次读取都判断是否存在乱码

byte[] cache = new byte[50];
···
String str = new String(cache);
if (!Charset.forName("GBK").newEncoder().canEncode(str)) {
	System.out.println(str);
}
sb.append(str);

然后逐步调试:
image-1667050681705
然后发现乱码部分:
image-1667050736997
下一次读取就变成了:
image-1667050802482
出现次数比以往更加频繁。
原因可能出在如果每次读固定个字节,可能会把汉字截断,造成new String(byte[])的乱码
image-1667052505688

正确代码

使用Reader类,处理字符的还得是字符流

public class GarbledCodeExample {
    public static void main(String[] args) throws IOException {
        File json = new File(Config.JSON_PATH);
        FileReader fileReader = new FileReader(json);
        char[] cache = new char[1024];
        BufferedReader br = new BufferedReader(fileReader);
        int len = br.read(cache);
        StringBuffer sb = new StringBuffer();
        while (len != -1) {
            sb.append(new String(cache));
            len = br.read(cache, 0, cache.length);
        }
        br.close();
        fileReader.close();
        //数据处理
        JSONArray array = new JSONArray(sb.toString());
        for (int i = 0; i < array.length(); i++) {
            JSONObject o = array.getJSONObject(i);
            String v = o.getString("name");
            if (!Charset.forName("GBK").newEncoder().canEncode(v)) {
                System.out.println(v);
            }
        }
    }
}

参考
java中如何判断字符串是否乱码