首页 > 解决方案 > 如何判断文件是否为二进制文件

问题描述

我正在尝试使用以下代码读取文件夹中所有文件的文本:

readALine :: FilePath -> IO ()
readALine fname = do 
  putStr . show $ "Filename: " ++ fname ++ "; "
  fs <- getFileSize fname
  if fs > 0 then do 
      hand <- openFile fname ReadMode
      fline  <- hGetLine hand
      hClose hand
      print $ "First line: " <> fline
  else return ()

但是,其中一些文件是二进制文件。如何查找给定文件是否为二进制文件?我在https://hoogle.haskell.org/?hoogle=binary%20file中找不到任何此类功能

谢谢你的帮助。

编辑:二进制我的意思是文件有不可打印的字符。我不确定这些文件的正确术语。

我安装了 UTF8-string 并修改了代码:

readALine :: FilePath -> IO ()
readALine fname = do 
  putStr . show $ "Filename: " ++ fname ++ "; "
  fs <- getFileSize fname
  if fs > 0 then do 
      hand <- openFile fname ReadMode
      fline  <- hGetLine hand
      hClose hand
      if isUTF8Encoded (unpack fline) then do
        print $ "Not binary file."
        print $ "First line: " <> fline
      else return ()
  else return ()

现在它可以工作了,但是在遇到“二进制”可执行文件(称为 esync.x)时,hGetLine hand表达式出现错误:

"Filename: ./esync.x; "firstline2.hs: ./esync.x: hGetLine: invalid argument (invalid byte sequence)

如何检查文件句柄本身的字符?

标签: filehaskellbinaryfiles

解决方案


二进制的定义非常模糊,但假设您的意思是不是有效的 UTF-8 文本的内容。

您应该使用toStringin Data.ByteString.UTF8which 用替换字符替换非 UTF-8 字符,但不会因错误而失败。

将您的示例转换为使用 UTF-8 ByteStrings:

import Data.Monoid
import System.IO
import System.Directory
import qualified Data.ByteString as B
import qualified Data.ByteString.UTF8 as B

readALine :: FilePath -> IO ()
readALine fname = do
  putStr . show $ "Filename: " ++ fname ++ "; "
  fs <- getFileSize fname
  if fs > 0 then do
      hand <- openFile fname ReadMode
      fline  <- B.hGetLine hand
      hClose hand
      print $ "First line: " <> B.toString fline
  else return ()

此代码不会在二进制文件上失败,但并未真正检测到二进制内容。如果要检测二进制文件,请B.replacement_char在数据中查找。要检测不可打印的字符,您也可以查找小于 32(空格字符)的代码点。


推荐阅读