java 检测文本、文件编码

Wesley13
• 阅读 504
/**
       * 默认GB18030
       */
      public static final String detectCharset(byte[] byteArray){
          // 建立InputStream
          ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
          
          // 默认编码
          String utf8 = "UTF-8";
          String charset = "GB18030";
  
          // 开始检测是否为UTF-8
          try {
              // 标记初始位置
              bais.mark(0);
  
              // 读取前3字节
              byte[] first3Bytes = new byte[3];
              bais.read(first3Bytes);
  
              // 如果前三字节为 0xEFBBBF ,则为带签名的UTF-8
              if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB && first3Bytes[2] == (byte) 0xBF) {
                  return utf8;
              }
              
              // 前三字节判定失败,开始检测是否是不带签名的UTF-8
              // 重置读取位置
              bais.reset();
  
              // 逐字节判定,直到遇到一个UTF-8编码字符
              byte[] oneByte = new byte[1];
              boolean isUtf8 = false;
              while (-1 != bais.read(oneByte)) {
                  // 如果是ASCII码,跳过
                  if (CharUtils.isAscii((char) oneByte[0])) {
                      continue;
                  }
                  
                  // 双字节格式
                  // 110yyyyy(C0-DF) 10xxxxxx
                  if ((oneByte[0] & 0xE0) == 0xC0) {
                      bais.mark(0);
                      byte[] nextOneByte = new byte[1];
                      if (bais.available() >= 1 && -1 != bais.read(nextOneByte)) {
                          if ((nextOneByte[0] & 0xC0) == 0x80) {
  
                              // 是GBK双字节重叠部分?暂时当GBK处理,中文系统下,GBK默认编码,UTF-8不常见
                              // 双字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x40到0xFE(不包括0x7F)
                              int oneByteInt = oneByte[0] & 0xff;
                              int nextOneByteInt = nextOneByte[0] & 0xff;
                              if (
                                      ((0x81 & 0xff) < = oneByteInt && oneByteInt <= (0xFE & 0xff))
                                      && ((0x40 & 0xff) <= nextOneByteInt && nextOneByteInt <= (0xfe & 0xff))
                                      && (nextOneByte[0] != 0x7F)
                                  ) {
                                  continue;
                              }
  
                              // 非GBK重叠部分,归于UTF-8
                              isUtf8 = true;
                              break;
                          }
                          bais.reset();
                      }
                  }
  
                  // 三字节格式
                  // 1110xxxx(E0-EF) 10xxxxxx 10xxxxxx
                  if ((oneByte[0] & 0xF0) == 0xE0) {
                      byte[] twoByte = new byte[2];
                      bais.mark(0);
                      if (bais.available() >= 2 && -1 != bais.read(twoByte)) {
                          if (((twoByte[0] & 0xC0) == 0x80) && ((twoByte[1] & 0xC0) == 0x80)) {
                              isUtf8 = true;
                              break;
                          }
                          bais.reset();
                      }
                  }
  
                  // 四字节格式
                  // 11110www(F0-F7) 10xxxxxx 10xxxxxx 10xxxxxx
                  if ((oneByte[0] & 0xF8) == 0xF0) {
                      byte[] threeByte = new byte[3];
                      bais.mark(0);
                      if (bais.available() >= 3 && -1 != bais.read(threeByte)) {
                          if (((threeByte[0] & 0xC0) == 0x80) && ((threeByte[1] & 0xC0) == 0x80)
                                  && ((threeByte[2] & 0xC0) == 0x80)) {
                              isUtf8 = true;
                              break;
                          }
                          bais.reset();
                      }
                  }
  
                  // 五字节格式
                  // 111110xx(F8-FB) 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
                  if ((oneByte[0] & 0xFC) == 0xF8) {
                      byte[] fourByte = new byte[4];
                      bais.mark(0);
                      if (bais.available() >= 4 && -1 != bais.read(fourByte)) {
                          if (((fourByte[0] & 0xC0) == 0x80) && ((fourByte[1] & 0xC0) == 0x80)
                                  && ((fourByte[2] & 0xC0) == 0x80)
                                  && ((fourByte[3] & 0xC0) == 0x80)) {
                              isUtf8 = true;
                              break;
                          }
                          bais.reset();
                      }
                  }
  
                  // 六字节格式
                  // 1111110x(FC-FD) 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
                  if ((oneByte[0] & 0xFE) == 0xFC) {
                      byte[] fiveByte = new byte[5];
                      bais.mark(0);
                      if (bais.available() >= 5 && -1 != bais.read(fiveByte)) {
                          if (((fiveByte[0] & 0xC0) == 0x80) && ((fiveByte[1] & 0xC0) == 0x80)
                                  && ((fiveByte[2] & 0xC0) == 0x80)
                                  && ((fiveByte[3] & 0xC0) == 0x80)
                                  && ((fiveByte[4] & 0xC0) == 0x80)) {
                              isUtf8 = true;
                              break;
                          }
                          bais.reset();
                      }
                  }
              }
  
              // 依据标志位设定返回值
              if (isUtf8) {
                  return utf8;
              }
          } catch (IOException e) {
          } 
  
          // 返回字符编码格式
          return charset;
      }
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
Java日期时间API系列35
  通过Java日期时间API系列1Jdk7及以前的日期时间类(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.cnblogs.com%2Fxkzhangsanx%2Fp%2F12032719.html)中得知,Java8以前除了java.sql.Timestamp扩充
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
JOptionPane修改图标
1.在Linux平台下.JOptionPane会显示Java默认的图标,在window平台不显示图标,如何替换这个图标了?2JOptionPane.setIcon(Icon)修改的是内容区域的icon,而不是左上角的Icon.所以需要通过修改Jdialog/Frame的图标来达到修改默认图标的问题.3.代码:if(JOptio
京东云开发者 京东云开发者
6个月前
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了