Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 509|回复: 0

Java读带有BOM的UTF-8文件乱码原因及解决方法

[复制链接]
  • TA的每日心情
    奋斗
    2025-3-18 14:43
  • 签到天数: 805 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    73万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    731050
    发表于 2021-4-26 21:50:52 | 显示全部楼层 |阅读模式

    原因:

    关于utf-8编码的txt文件,windows以记事本方式保存时会在第一行最开始处自动加入bom格式的相关信息,大概三个字节! 

    所以java在读取此类文件时第一行时会多出三个不相关的字节,这样对正常的程序产生了不良影响!

    解决方法:

     网上有如下解决方法确实可行

    1.使用UltraEdit将上边的txt文件另存为UTF-8无BOM格式;

    2.使用Notepad++打开上边的txt文件执行如下操作“格式-->以UTF-8无BOM格式编码”,修改后将txt文本进行保存

    不足之处

    但是这样也有不足,这样对文件生产者提出了很高的要求,万一这样的文件是很多人生产的,那就势必会产生各种各样的问题,这归根到底是jdk的一个bug.

    有没有什么办法能够一劳永逸呢,答案是有的,咱们程序里控制,来跟着我一起做!

    终极解决方案

    (1)在工程中增加JDK提供的一个工具类:

      public class UnicodeInputStream extends InputStream {
           PushbackInputStream internalIn;
           boolean             isInited = false;
           String              defaultEnc;
           String              encoding;

            private static final int BOM_SIZE = 4;

            public UnicodeInputStream(InputStream in, String defaultEnc) {
                internalIn = new PushbackInputStream(in, BOM_SIZE);
                this.defaultEnc = defaultEnc;
            }

            public String getDefaultEncoding() {
              return defaultEnc;
           }

           public String getEncoding() {
              if (!isInited) {
                 try {
                    init();
                 } catch (IOException ex) {
                    IllegalStateException ise = new IllegalStateException("Init method failed.");
                    ise.initCause(ise);
                    throw ise;
                 }
              }
              return encoding;
           }

           /**
            * Read-ahead four bytes and check for BOM marks. Extra bytes are
            * unread back to the stream, only BOM bytes are skipped.
            */
           protected void init() throws IOException {
              if (isInited) return;

              byte bom[] = new byte[BOM_SIZE];
              int n, unread;
              n = internalIn.read(bom, 0, bom.length);

              if ( (bom[0] == (byte)0x00) && (bom[1] == (byte)0x00) &&
                          (bom[2] == (byte)0xFE) && (bom[3] == (byte)0xFF) ) {
                 encoding = "UTF-32BE";
                 unread = n - 4;
              } else if ( (bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) &&
                          (bom[2] == (byte)0x00) && (bom[3] == (byte)0x00) ) {
                 encoding = "UTF-32LE";
                 unread = n - 4;
              } else if (  (bom[0] == (byte)0xEF) && (bom[1] == (byte)0xBB) &&
                    (bom[2] == (byte)0xBF) ) {
                 encoding = "UTF-8";
                 unread = n - 3;
              } else if ( (bom[0] == (byte)0xFE) && (bom[1] == (byte)0xFF) ) {
                 encoding = "UTF-16BE";
                 unread = n - 2;
              } else if ( (bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) ) {
                 encoding = "UTF-16LE";
                 unread = n - 2;
              } else {
                 // Unicode BOM mark not found, unread all bytes
                 encoding = defaultEnc;
                 unread = n;
              }      
              //System.out.println("read=" + n + ", unread=" + unread);

              if (unread > 0) internalIn.unread(bom, (n - unread), unread);

              isInited = true;
           }

           public void close() throws IOException {
              //init();
              isInited = true;
              internalIn.close();
           }

           public int read() throws IOException {
              //init();
              isInited = true;
              return internalIn.read();
           }
        }

    (2)读取时使用如下代码:  //因为我这边是服务器上的远程文件,如果是本地文件使用File类

       URL url = new URL("http://****/***/test.txt");   

        // File f  = new File("test.txt"); 


            String enc = null; // or NULL to use systemdefault
            UnicodeInputStream uin = new UnicodeInputStream(url.openStream(),enc);  //如果是本地将url.openStream -> new FileInputStream(f)
            enc = uin.getEncoding(); // check and skip possible BOM bytes
            InputStreamReader in;
            if (enc == null){
                in = new InputStreamReader(uin);
            }else {
                in = new InputStreamReader(uin, enc);
            }
            BufferedReader reader = new BufferedReader(in);
            //BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("D:/tags.txt"),"utf-8"));
            String tmp =reader.readLine();

    这样读取的结果就是正常的了,有什么问题还可以留言!

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-5-7 09:31 , Processed in 0.062259 second(s), 27 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表