首页 > 编程语言 >java读取txt文件解决乱码问题

java读取txt文件解决乱码问题

时间:2023-07-30 18:35:48浏览次数:33  
标签:java bts return first3Bytes 乱码 new byte txt line

说明:由于txt文件有bom和不同的编码方式,导致导入数据时产生乱码,以下代码完美解决乱码问题。
参考他人代码,结合自己的业务加工完成,费了大半天功夫完成,希望对大家有点用处。
废话不多说,直接上代码:

 /**
     * 从txt文件流读取数据
     *
     * @param txtStream
     * @return
     * @throws IOException
     */
    public static List<String> readFromTxt(InputStream txtStream) throws IOException {
        List<String> paragraphList = new ArrayList<>();
        LabelValuePair<InputStream, Charset> result = getStreamCharset(txtStream);
        Charset cs = result.getValue();
        BOMInputStream bomInputStream = new BOMInputStream(result.getLabel());
        boolean hasBom = bomInputStream.hasBOM();
        InputStreamReader sr = hasBom ?
                new InputStreamReader(bomInputStream, Charset.forName(bomInputStream.getBOMCharsetName())) :
                new InputStreamReader(bomInputStream, cs);
        BufferedReader br = new BufferedReader(sr);
        String line = null;
        Integer lineIndex = 0;
        while ((line = br.readLine()) != null) {
            if (!hasBom && lineIndex == 0) {
                lineIndex++;
                if (StringUtils.isNotEmpty(line)) {
                    byte[] bts = line.getBytes(cs);
                    if ((bts[0] == -1 && bts[1] == -2) || bts[0] == -2 && bts[1] == -1) {
                        byte[] newBts = new byte[bts.length - 2];
                        for (int i = 2; i < bts.length; i++) {
                            newBts[i - 2] = bts[i];
                        }
                        line = new String(newBts, cs);
                    }
                }
            }
            if (StringUtils.isNotEmpty(line) && StringUtils.isNotEmpty(line.trim())) {
                paragraphList.add(line);
                log.info("读取数据:{},长度:{},value:{}", line, line.trim().length(), line.getBytes(cs));
            }
        }
        br.close();
        sr.close();
        return paragraphList;
    }

 /**
     * 判断获取字节流 编码格式,主要用于txt文件内容读取
     * 再次读取流,使用返回结果中的流
     *
     * @param stream
     * @return
     */
    public static LabelValuePair<InputStream, Charset> getStreamCharset(InputStream stream) throws IOException {
        LabelValuePair<InputStream, byte[]> result = readSteam(stream, true);
        byte[] buffer = result.getValue();
        if (buffer.length < 2)
            return new LabelValuePair<>(result.getLabel(), CharsetKit.CHARSET_GBK);
        String encode = getFileCharSet(new BufferedInputStream(new ByteArrayInputStream(result.getValue())));// getBytesCharset(buffer);

        return new LabelValuePair<>(result.getLabel(), CharsetKit.charset(encode));
    }

  /**
     * 判断txt编码格式方法
     *
     * @param bis
     * @return
     */
    public static String getFileCharSet(BufferedInputStream bis) {
        String charset = "GBK";
        byte[] first3Bytes = new byte[3];
        try {
            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;
                    }
                }
            }
            bis.close();
        } catch (Exception e) {
            log.error("获取文件编码方式异常", e);
        }
        return charset;
    }

    /**
     * 读取流
     *
     * @param inputStream 输入流
     * @param isRepeat    是否重复读取
     * @return
     */
    public static LabelValuePair<InputStream, byte[]> readSteam(InputStream inputStream, boolean isRepeat) throws IOException {
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        inputStream.mark(0);
        while ((len = inputStream.read(buffer)) != -1) {
            outSteam.write(buffer);
        }
        byte[] fs = outSteam.toByteArray();
        outSteam.close();
        inputStream.close();
        InputStream newSteam = null;
        if (isRepeat) {
            newSteam = new ByteArrayInputStream(fs);
        }

        return new LabelValuePair<>(newSteam, fs);
    }

标签:java,bts,return,first3Bytes,乱码,new,byte,txt,line
From: https://www.cnblogs.com/javacoffeenet/p/17591803.html

相关文章

  • Java学习6-面向对象基础 成员变量、成员方法、构造方法、this关键字、静态字段、静态
    一、面向对象概述面向过程开发,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。面向过程的代表语言:C语言当需求单一,或者简单时,我们一步一步去操作没问题,并且效率也挺高。可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻......
  • “Java:不支持发行版本5”的解决方案
      cltr+shift+alt+s出现此页面 本地安装的jdk是8版本,所以这里显示的就是8版本,这里没有问题向下找module模块发现这里的“langeagelevel”是5将它修改成对应的版本  到File里找Settings→ Build→Compiler → javacompiler 修改成对应java版......
  • Java之异常
    Java之异常概述异常是什么?异常是代码在编译或者执行的过程中可能出现的错误异常分为几类?编译时异常、运行时异常。编译时异常:没有继承RuntimeExcpetion的异常,编译阶段就会出错。运行时异常:继承自RuntimeException的异常或其子类,编译阶段不报错,运行可能报错。学......
  • java中判断图片格式并且等比例压缩图片
    最近项目中需要判断上传的图片必须是png,jpg,gif三种格式的图片,并且当图片的宽度大于600px时,压缩图片至600px,并且等比例的压缩图片的高度。具体的实现形式:大致的思路是:判断根据文件名判断图片的格式是否是png,jpg,gif三种图片文件  定义了 方法如果是的,则进入到scaleImage(Stri......
  • 关于Java的多线程实现
    多线程介绍进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以......
  • JAVA实现海报背景填充qrCode
    packagecom.open.openbank.qrCode;importjavax.imageio.ImageIO;importjava.awt.*;importjava.awt.geom.RoundRectangle2D;importjava.awt.image.BufferedImage;importjava.io.File;importjava.io.IOException;/***生成海报*/publicclassPosterTest{......
  • java基础中(笔记)
    流程控制流程控制语句的分类:1、顺序结构:从上往下,从前往后;2、分支结构(if,switch);3、循环结构(for,while,do...while); if语句if格式:if(关系表达式){语句体;}if(关系表达式){语句体1;}else{语句体2;}if(关系表达式){语句体1;}elseif{语句体2;}elseif{语句体3;}elseif{语......
  • Java 中 == 与 equals() 的区别
    Java中==与equals()的区别1.====是一个比较运算符,在使用时有可以判断两种情况在用于基本类型时,即判断两边数据的值是否相等。在用于引用类型时,即判断两边是否为同一个对象即有相同的地址。2.equals()方法equals()方法是Object的一个方法,只能判断引用类型。O......
  • 懒得改变原始对象?JavaScript代理模式教你怎样一步步偷懒!
    前言系列首发于公众号『非同质前端札记』,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。懒得改变原始对象?JavaScript代理模式教你怎样一步步偷懒!何为代理模式例如,你想预约一家公司的董事长会面,按照正常流程,你只能通过先联系他的秘书,然后跟他的秘书预约时间,约好时......
  • Java利用Rxtx进行串口通讯
    最近在做传感器数据采集的工作,底层是基于Zigbee的无线传感网络,所有数据采集到Zigbee协调器上然后通知上位机数据采集完成,上位机通过USB转串口去读取数据就可以了。那么问题来了,如何进行串口通讯呢?老板说你用Java写个程序好了嘛,用Java写串口程序也是醉了。实验室也没别人写了,所以就......