文件操作 #
一、基本文件操作 #
1.1 读取文件 #
haskell
-- readFile:读取整个文件(惰性)
readFile :: FilePath -> IO String
-- 示例
main :: IO ()
main = do
contents <- readFile "input.txt"
putStrLn contents
1.2 写入文件 #
haskell
-- writeFile:写入文件(覆盖)
writeFile :: FilePath -> String -> IO ()
-- 示例
main :: IO ()
main = do
writeFile "output.txt" "Hello, World!"
putStrLn "File written"
1.3 追加文件 #
haskell
-- appendFile:追加到文件
appendFile :: FilePath -> String -> IO ()
-- 示例
main :: IO ()
main = do
appendFile "log.txt" "New log entry\n"
putStrLn "Log appended"
二、文件句柄 #
2.1 打开文件 #
haskell
import System.IO
-- 打开文件
openFile :: FilePath -> IOMode -> IO Handle
-- IOMode
data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
-- 示例
main :: IO ()
main = do
handle <- openFile "input.txt" ReadMode
contents <- hGetContents handle
putStrLn contents
hClose handle
2.2 句柄操作 #
haskell
import System.IO
main :: IO ()
main = do
handle <- openFile "input.txt" ReadMode
-- 读取操作
line <- hGetLine handle
contents <- hGetContents handle
-- 写入操作
hPutStrLn handle "text"
hPutStr handle "text"
hClose handle
2.3 withFile #
haskell
import System.IO
-- withFile:自动关闭文件
withFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
-- 示例
main :: IO ()
main = do
contents <- withFile "input.txt" ReadMode $ \handle -> do
hGetContents handle
putStrLn contents
三、目录操作 #
3.1 目录操作 #
haskell
import System.Directory
-- 获取当前目录
getCurrentDirectory :: IO FilePath
-- 设置当前目录
setCurrentDirectory :: FilePath -> IO ()
-- 获取目录内容
getDirectoryContents :: FilePath -> IO [FilePath]
-- 创建目录
createDirectory :: FilePath -> IO ()
-- 删除目录
removeDirectory :: FilePath -> IO ()
-- 示例
main :: IO ()
main = do
cwd <- getCurrentDirectory
putStrLn $ "Current directory: " ++ cwd
createDirectory "test_dir"
contents <- getDirectoryContents "."
print contents
removeDirectory "test_dir"
3.2 文件检查 #
haskell
import System.Directory
-- 检查文件是否存在
doesFileExist :: FilePath -> IO Bool
-- 检查目录是否存在
doesDirectoryExist :: FilePath -> IO Bool
-- 示例
main :: IO ()
main = do
fileExists <- doesFileExist "input.txt"
if fileExists
then putStrLn "File exists"
else putStrLn "File not found"
dirExists <- doesDirectoryExist "src"
putStrLn $ "Directory exists: " ++ show dirExists
3.3 文件操作 #
haskell
import System.Directory
-- 复制文件
copyFile :: FilePath -> FilePath -> IO ()
-- 移动/重命名文件
renameFile :: FilePath -> FilePath -> IO ()
-- 删除文件
removeFile :: FilePath -> IO ()
-- 示例
main :: IO ()
main = do
copyFile "input.txt" "input_backup.txt"
renameFile "input.txt" "renamed.txt"
removeFile "renamed.txt"
四、异常处理 #
4.1 基本异常处理 #
haskell
import Control.Exception
-- catch:捕获异常
catch :: IO a -> (SomeException -> IO a) -> IO a
-- 示例
main :: IO ()
main = do
result <- catch (readFile "nonexistent.txt") handleError
putStrLn result
handleError :: SomeException -> IO String
handleError e = return $ "Error: " ++ show e
4.2 特定异常类型 #
haskell
import Control.Exception
import System.IO.Error
-- 捕获IO错误
catchIOError :: IO a -> (IOError -> IO a) -> IO a
-- 示例
main :: IO ()
main = do
result <- catchIOError (readFile "nonexistent.txt") handleIOError
putStrLn result
handleIOError :: IOError -> IO String
handleIOError e
| isDoesNotExistError e = return "File not found"
| isPermissionError e = return "Permission denied"
| otherwise = return $ "Error: " ++ show e
4.3 try #
haskell
import Control.Exception
-- try:返回Either
try :: IO a -> IO (Either SomeException a)
-- 示例
main :: IO ()
main = do
result <- try (readFile "nonexistent.txt") :: IO (Either SomeException String)
case result of
Left e -> putStrLn $ "Error: " ++ show e
Right s -> putStrLn s
4.4 bracket #
haskell
import Control.Exception
-- bracket:确保资源释放
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
-- 示例
main :: IO ()
main = do
contents <- bracket
(openFile "input.txt" ReadMode) -- 获取资源
hClose -- 释放资源
hGetContents -- 使用资源
putStrLn contents
五、文件信息 #
5.1 获取文件大小 #
haskell
import System.Directory
-- 获取文件大小
getFileSize :: FilePath -> IO Integer
-- 示例
main :: IO ()
main = do
size <- getFileSize "input.txt"
putStrLn $ "File size: " ++ show size ++ " bytes"
5.2 文件时间 #
haskell
import System.Directory
-- 获取修改时间
getModificationTime :: FilePath -> IO UTCTime
-- 示例
main :: IO ()
main = do
time <- getModificationTime "input.txt"
putStrLn $ "Last modified: " ++ show time
六、实践示例 #
6.1 文件复制程序 #
haskell
import System.Directory
main :: IO ()
main = do
putStrLn "Enter source file:"
src <- getLine
exists <- doesFileExist src
if not exists
then putStrLn "Source file not found"
else do
putStrLn "Enter destination file:"
dst <- getLine
copyFile src dst
putStrLn "File copied successfully!"
6.2 文件搜索 #
haskell
import System.Directory
import System.FilePath
searchFiles :: FilePath -> String -> IO [FilePath]
searchFiles dir pattern = do
exists <- doesDirectoryExist dir
if not exists
then return []
else do
entries <- getDirectoryContents dir
let files = filter (not . isSpecial) entries
results <- mapM (checkEntry dir pattern) files
return (concat results)
where
isSpecial "." = True
isSpecial ".." = True
isSpecial _ = False
checkEntry :: FilePath -> String -> FilePath -> IO [FilePath]
checkEntry dir pattern entry = do
let path = dir </> entry
isDir <- doesDirectoryExist path
if isDir
then searchFiles path pattern
else if match pattern entry
then return [path]
else return []
match :: String -> String -> Bool
match pattern entry = pattern `elem` entry
6.3 日志文件 #
haskell
import System.Directory
import Data.Time
logFile :: FilePath
logFile = "app.log"
logMessage :: String -> IO ()
logMessage msg = do
time <- getCurrentTime
let entry = show time ++ " - " ++ msg ++ "\n"
appendFile logFile entry
main :: IO ()
main = do
logMessage "Application started"
logMessage "Processing data..."
logMessage "Application finished"
putStrLn "Log contents:"
contents <- readFile logFile
putStrLn contents
6.4 配置文件 #
haskell
import System.Directory
import Data.Maybe
type Config = [(String, String)]
readConfig :: FilePath -> IO Config
readConfig path = do
exists <- doesFileExist path
if not exists
then return []
else do
contents <- readFile path
return $ parseConfig contents
parseConfig :: String -> Config
parseConfig = map parseLine . filter (not . null) . lines
where
parseLine line =
let (key, value) = span (/= '=') line
in (trim key, trim (drop 1 value))
trim = dropWhile (== ' ') . reverse . dropWhile (== ' ') . reverse
getConfig :: String -> Config -> Maybe String
getConfig key = lookup key
main :: IO ()
main = do
config <- readConfig "config.txt"
case getConfig "host" config of
Just host -> putStrLn $ "Host: " ++ host
Nothing -> putStrLn "Host not configured"
七、总结 #
文件操作要点:
- 基本操作:
readFile、writeFile、appendFile - 文件句柄:
openFile、hGetLine、hClose - 目录操作:
getDirectoryContents、createDirectory - 文件检查:
doesFileExist、doesDirectoryExist - 异常处理:
catch、try、bracket - 资源管理:使用
withFile确保资源释放
掌握文件操作后,让我们继续学习高级特性。
最后更新:2026-03-27