You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Haskell中不使用openFile获取句柄判断文件文本编码?

识别UTF-16LE编码文件并转换为UTF-8(Haskell实现)

问题背景

需要处理学生提交的文件,其中存在UTF-16LE编码的文件(仅含BOM标记,无ASCII范围外字符),需识别这类文件并转换为UTF-8编码。

现有代码问题

尝试通过openFile获取文件句柄并调用hGetEncoding判断编码,但openFile默认以UTF-8编码打开文件,导致hGetEncoding始终返回UTF-8,与文件实际编码不符(已通过Unix的file命令验证真实编码)。

现有代码:

fixFileEncoding fname =
  do hdl <- openFile fname ReadMode
     menc <- hGetEncoding hdl
     hClose hdl
     case menc of
       Nothing   ->  system ("cp "++fname++" safe"++fname)
       Just enc  -> 
         do let encstr = show enc
            putStrLn ("@@@@@@" ++ fname ++ " is "++encstr)
            if take 6 encstr == "UTF-16"
            then 
              system ("iconv -f UTF-16LE -t UTF-8 "++fname++" > safe"++fname)
            else 
              system ("cp "++fname++" safe"++fname)

解决方案

由于目标文件仅通过BOM标记区分UTF-16LE编码,可直接以二进制模式读取文件开头的字节判断BOM;也可调用外部file命令解析编码信息。

方案1:读取文件BOM判断编码

UTF-16LE的BOM为0xFF 0xFE,以二进制模式读取文件前2字节即可识别:

import System.IO
import System.Process (system)

fixFileEncoding :: FilePath -> IO ()
fixFileEncoding fname = do
  -- 以二进制模式打开文件,避免编码自动转换
  hdl <- openBinaryFile fname ReadMode
  -- 读取前2字节判断BOM
  bom <- hGetNBytes hdl 2
  hClose hdl
  case bom of
    "\xFF\xFE" -> do
      putStrLn $ "@@@ Converting UTF-16LE file: " ++ fname
      _ <- system $ "iconv -f UTF-16LE -t UTF-8 " ++ fname ++ " > safe" ++ fname
      return ()
    _ -> do
      putStrLn $ "@@@ Copying non-UTF-16LE file: " ++ fname
      _ <- system $ "cp " ++ fname ++ " safe" ++ fname
      return ()

方案2:调用file命令检测编码

依赖Unix系统的file工具解析文件编码,适合更通用的编码检测场景:

import System.Process (readProcess, system)
import Data.List (isInfixOf)

fixFileEncoding :: FilePath -> IO ()
fixFileEncoding fname = do
  -- 调用file命令获取编码信息
  fileOutput <- readProcess "file" ["-b", fname] ""
  if "UTF-16LE" `isInfixOf` fileOutput
    then do
      putStrLn $ "@@@ Converting UTF-16LE file: " ++ fname
      _ <- system $ "iconv -f UTF-16LE -t UTF-8 " ++ fname ++ " > safe" ++ fname
      return ()
    else do
      putStrLn $ "@@@ Copying non-UTF-16LE file: " ++ fname
      _ <- system $ "cp " ++ fname ++ " safe" ++ fname
      return ()

内容的提问来源于stack exchange,提问作者Andrew Butterfield

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 04:53:17