content: package cn.xeblog.plugin.util;
  
  import java.io.BufferedInputStream;
  import java.io.FileInputStream;
  import java.nio.charset.Charset;
  
  /**
   * @author LYF
   * @date 2022-06-23
   */
  public class CharsetUtils {
      /**
       * 近似判断文本文件的字符集，文件开头三个字节表明编码格式。
       */
      public static Charset charset(String path) {
          String charset = "GBK";
          byte[] first3Bytes = new byte[3];
          try {
              boolean checked = false;
              BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
              bis.mark(0);
              int read = bis.read(first3Bytes, 0, 3);
              if (read == -1) {
                  bis.close();
                  // 文件编码为 ANSI
                  return Charset.forName(charset);
              } else if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
                  // 文件编码为 Unicode
                  charset = "UTF-16LE";
                  checked = true;
              } else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {
                  // 文件编码为 Unicode big endian
                  charset = "UTF-16BE";
                  checked = true;
              } else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB
                      && first3Bytes[2] == (byte) 0xBF) {
                  // 文件编码为 UTF-8
                  charset = "UTF-8";
                  checked = true;
              }
              bis.reset();
              if (!checked) {
                  while ((read = bis.read()) != -1) {
                      if (read >= 0xF0) {
                          break;
                      }
                      // 单独出现BF以下的，也算是GBK
                      if (0x80 <= read && read <= 0xBF) {
                          break;
                      }
                      if (0xC0 <= read && read <= 0xDF) {
                          read = bis.read();
                          // 双字节 (0xC0 - 0xDF),也可能在GB编码内
                          if (!(0x80 <= read && read <= 0xBF)) {
                              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;
                      }
                  }
              }
              bis.close();
          } catch (Exception e) {
              e.printStackTrace();
          }
          return Charset.forName(charset);
      }
  }
  