实习记录——中文编码问题

这次是一个需求,系统需要支持中文的用户pin。
优惠券发放任务创建的时候可以上传txt文件到jss,
发放任务是一个定时任务,每隔三分钟遍历一边待发放任务,从jss上下载pin文件,遍历组装成一个pin的集合,然后根据pin集合发放优惠券。
因此中文编码问题主要出现在从jss上获取输入流读取数据,并正确解析,转成utf-8格式

txt主要有ANSI、UTF-8、Unicode编码
因此首先需要判断这个文件是什么编码格式的,才能正确解析。

附上判断编码格式代码:

private static  String getFilecharset(BufferedInputStream bis) throws IOException {
        String charset = "GBK";
        byte[] first3Bytes = new byte[3];
            boolean checked = false;
            bis.mark(0);
            int read = bis.read(first3Bytes, 0, 3);
            if (read == -1) {
                return charset;  //文件编码为 ANSI
            } else if (first3Bytes[0] == (byte) 0xFF
                    && first3Bytes[1] == (byte) 0xFE) {
                charset = "UTF-16LE"; //文件编码为 Unicode
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xFE
                    && first3Bytes[1] == (byte) 0xFF) {
                charset = "UTF-16BE"; //文件编码为 Unicode big endian
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xEF
                    && first3Bytes[1] == (byte) 0xBB
                    && first3Bytes[2] == (byte) 0xBF) {
                charset = "UTF-8"; //文件编码为 UTF-8
                checked = true;
            }
            bis.reset();
            if (!checked) {
                int loc = 0;
                while ((read = bis.read()) != -1) {
                    loc++;
                    if (read >= 0xF0)
                        break;
                    if (0x80 <= read && read <= 0xBF) // 单独出现BF以下的,也算是GBK
                        break;
                    if (0xC0 <= read && read <= 0xDF) {
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) // 双字节 (0xC0 - 0xDF) (0x80 - 0xBF),也可能在GB编码内
                            continue;
                        else{
                            break;
                        }
                    } else if (0xE0 <= read && read <= 0xEF) {// 也有可能出错,但是几率较小
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) {
                            read = bis.read();
                            if (0x80 <= read && read <= 0xBF) {
                                charset = "UTF-8";
                                break;
                            } else{
                                break;
                            }
                        } else{
                            break;
                        }
                    }
                }
            }
        return charset;
    }

获取到编码格式之后,我们就可以使用这个编码格式读取数据,并且转换成UTF-8格式
如下;

decodein = os.get().getInputStream();
in = os.get().getInputStream();
String oldCharset = getFilecharset(new BufferedInputStream(decodein));
reader = new BufferedReader(new InputStreamReader(in,oldCharset));
String pin = null;
while ((pin = (reader.readLine())) != null) {
    pins.add(pin);
}

为何出现了读取数据为空的情况?
附上产生这个bug的代码;

in = os.get().getInputStream();
//检验编码格式
String oldCharset = getFilecharset(new BufferedInputStream(in));
reader = new BufferedReader(new InputStreamReader(in,oldCharset));
while ((pin = (reader.readLine())) != null) {
    pins.add(pin);
}

这个问题排查了两天,从各种编码问题到jss问题
结果竟然是很简单的原因: inputStream调用了两次
原本我以为使用BufferedInputStream、InputStreamReader封装了inputStream之后就是新的一个流了,毕竟使用了new 。结果发现其实都是封装了同一个inputStream。

这个问题其实很简单,但是很容易被忽视。

猜你喜欢

转载自blog.csdn.net/github_38687585/article/details/81392843
今日推荐