@hnefatl 的回答很好,并且可能是您正在寻找的让您的原始代码正常工作的内容。但是,如果其他人在试图弄清楚如何检查文件是否为空时偶然发现了这个问题,那么下面是更高级(但更受欢迎)的答案。
在“真实”的 Haskell 代码中,假设您正在尝试检查普通文件的大小,您可能会使用 getFileStatus 和来自 System.Posix 的辅助函数 fileSize,如本问题所述: What is the best way to retrieve the size of a file in haskell?
具体来说,像下面这样的函数可以在 Linux 上运行:
import System.Posix
isEmpty1 :: FilePath -> IO Bool
isEmpty1 fp = do
stat <- getFileStatus fp
return (fileSize stat == 0)
如果您需要 Windows 兼容性,您可以安装提供跨平台版本的getFileStatus 的unix-compat 包,或者您可以使用System.IO 中的hFileSize:
import System.IO
isEmpty2 :: FilePath -> IO Bool
isEmpty2 fp = do
sz <- withFile fp ReadMode hFileSize
return (sz == 0)
上面isEmpty1 的主要优点是getFileStatus 应该非常高效,因为它只使用一个系统调用(stat 调用)。如果您必须检查大量文件的大小,这将是首选方法。 isEmpty2 解决方案也可以,但它涉及(至少)三个系统调用(open,然后是fstat,然后是close)并且需要临时打开一个文件句柄,如果您正在并行检查大量文件之类的。
两者都将比readFile 方法执行得更好,因为它们不会导致读取任何文件数据。相比之下,readFile 需要从磁盘中读取至少一个数据块才能确定结果字符串为空。
感谢 Haskell 的惰性 I/O,它只会进行初始读取,而不必读取整个文件,但这会导致另一个奇怪的怪癖。 readFile 的方式是设计为打开文件并懒惰地读取其内容,结果文件一直保持打开状态,直到内容读取完成,没有其他方法可以在不读取完整内容的情况下强制关闭文件!因此,除非文件足够短以至于被初始读取完全读取,否则文件句柄将无限期地保持打开状态。因此,如果您有一个程序来检查一大堆文本文件是否为空,如果其中一些大于单个块,您最终可能会用完文件句柄。
一般来说,readFile 不应使用,除非 (a) 将处理整个文件内容;或 (b) 程序将在读取所需的任何部分内容后立即终止。