一种纯js判断上传文件编码格式的方法

212 阅读3分钟

以下是一个前端上传组件的示例,使用 JavaScript 来检测上传文件的编码格式。以下代码会创建一个文件上传组件,并尝试通过 FileReader 和分析文件内容的字节模式来判断文件的编码格式(如 UTF-8、GBK 等)。

image.png

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文件上传与编码检测</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 800px;
      margin: 20px auto;
      padding: 20px;
    }
    #upload-container {
      margin-bottom: 20px;
    }
    #result {
      white-space: pre-wrap;
      background: #f5f5f5;
      padding: 10px;
      border-radius: 5px;
    }
  </style>
</head>
<body>
  <div id="upload-container">
    <h2>上传文件并检测编码</h2>
    <input type="file" id="fileInput" accept="*/*">
  </div>
  <div id="result">上传文件后将显示编码信息...</div>

  <script>
    // 获取 DOM 元素
    const fileInput = document.getElementById('fileInput');
    const resultDiv = document.getElementById('result');

    // 文件上传事件监听
    fileInput.addEventListener('change', (event) => {
      const file = event.target.files[0];
      if (!file) {
        resultDiv.textContent = '未选择文件!';
        return;
      }

      // 使用 FileReader 读取文件内容
      const reader = new FileReader();
      reader.onload = function(e) {
        const arrayBuffer = e.target.result;
        const uint8Array = new Uint8Array(arrayBuffer);
        const encoding = detectEncoding(uint8Array);
        displayResult(file, encoding);
      };
      reader.onerror = function() {
        resultDiv.textContent = '读取文件失败!';
      };
      reader.readAsArrayBuffer(file);
    });

    // 检测文件编码
    function detectEncoding(uint8Array) {
      // 检查 BOM(字节顺序标记)
      if (uint8Array.length >= 3 && uint8Array[0] === 0xEF && uint8Array[1] === 0xBB && uint8Array[2] === 0xBF) {
        return 'UTF-8 (with BOM)';
      }
      if (uint8Array.length >= 2 && uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) {
        return 'UTF-16 BE (with BOM)';
      }
      if (uint8Array.length >= 2 && uint8Array[0] === 0xFF && uint8Array[1] === 0xFE) {
        return 'UTF-16 LE (with BOM)';
      }

      // 检查 UTF-8 特征(无 BOM)
      let isLikelyUTF8 = true;
      let i = 0;
      while (i < uint8Array.length && isLikelyUTF8) {
        if (uint8Array[i] < 0x80) {
          // ASCII 字符
          i++;
        } else if (uint8Array[i] >= 0xC2 && uint8Array[i] <= 0xDF && i + 1 < uint8Array.length && uint8Array[i + 1] >= 0x80 && uint8Array[i + 1] <= 0xBF) {
          // 2 字节 UTF-8
          i += 2;
        } else if (uint8Array[i] >= 0xE0 && uint8Array[i] <= 0xEF && i + 2 < uint8Array.length && uint8Array[i + 1] >= 0x80 && uint8Array[i + 1] <= 0xBF && uint8Array[i + 2] >= 0x80 && uint8Array[i + 2] <= 0xBF) {
          // 3 字节 UTF-8
          i += 3;
        } else {
          isLikelyUTF8 = false;
        }
      }
      if (isLikelyUTF8) {
        return 'UTF-8';
      }

      // 检查 GBK 特征(简化的启发式检测)
      let isLikelyGBK = true;
      i = 0;
      while (i < uint8Array.length && isLikelyGBK) {
        if (uint8Array[i] <= 0x7F) {
          // ASCII 字符
          i++;
        } else if (uint8Array[i] >= 0x81 && uint8Array[i] <= 0xFE && i + 1 < uint8Array.length && ((uint8Array[i + 1] >= 0x40 && uint8Array[i + 1] <= 0x7E) || (uint8Array[i + 1] >= 0x80 && uint8Array[i + 1] <= 0xFE))) {
          // GBK 汉字范围
          i += 2;
        } else {
          isLikelyGBK = false;
        }
      }
      if (isLikelyGBK) {
        return 'GBK';
      }

      // 如果无法确定编码
      return '未知编码';
    }

    // 显示检测结果
    function displayResult(file, encoding) {
      resultDiv.textContent = `
文件名称: ${file.name}
文件大小: ${(file.size / 1024).toFixed(2)} KB
文件类型: ${file.type || '未知'}
检测到的编码: ${encoding}
      `;
    }
  </script>
</body>
</html>

这个组件的功能说明:

  1. 用户通过 <input type="file"> 上传文件。
  2. 使用 FileReaderArrayBuffer 格式读取将文件读取为字节数组。
  3. 通过分析字节模式检测编码格式:
    • 检查 BOM(字节顺序标记)以识别 UTF-8、UTF-16 BE/LE。
    • 分析 UTF-8 和 GBK 的字节序列特征。
    • 如果无法确定,返回“未知编码”。
  4. 显示文件名称、大小、类型和检测到的编码。

使用方法:

  • 打开 HTML 文件,上传一个文本文件(如 .txt、.csv 等)。
  • 系统会显示文件的详细信息和推测的编码格式。

注意:

  • 编码检测基于启发式方法,可能不完全准确,尤其是对于小文件或混合编码。
  • 支持 UTF-8、UTF-16、GBK 的检测,可根据需要扩展其他编码(如 GB2312、Big5)。