Haskell IO и заключительные файлы

39
задан Don Stewart 17 April 2011 в 19:26
поделиться

5 ответов

Как другие заявили, это из-за отложенных вычислений. Дескриптор является полузамкнутым после этой операции и будет закрыт автоматически, когда все данные считаны. И hGetContents и readFile ленивы таким образом. В случаях, где у Вас есть проблемы с дескрипторами, сохраняемыми открытыми, обычно Вы просто вызываете чтение. Вот простой способ:

import Control.Parallel.Strategies (rnf)
-- rnf means "reduce to normal form"
main = do inFile <- openFile "foo" 
          contents <- hGetContents inFile
          rnf contents `seq` hClose inFile -- force the whole file to be read, then close
          putStr contents

В эти дни, однако, никто не использует строки для файлового ввода-вывода больше. Новый путь состоит в том, чтобы использовать Данные. ByteString (доступный на hackage), и Данные. ByteString. Ленивый, когда Вы хотите ленивые чтения.

import qualified Data.ByteString as Str

main = do contents <- Str.readFile "foo"
          -- readFile is strict, so the the entire string is read here
          Str.putStr contents

ByteStrings являются способом пойти для больших строк (как содержание файла). Они намного быстрее и больше памяти, эффективной, чем Строка (= [Символ]).

Примечания:

я импортировал rnf из Управления. Параллель. Стратегии только удобства. Вы могли записать что-то как он сами довольно легко:

  forceList [] = ()
  forceList (x:xs) = forceList xs

Это просто вызывает обход позвоночника (не значения) списка, который имел бы эффект чтения целого файла.

Ленивый ввод-вывод становится продуманным злом экспертами; я рекомендую использовать строгие строки байтов для большей части файлового ввода-вывода в настоящее время. Существует несколько решений в духовке, которые пытаются возвратить компонуемые возрастающие чтения, самое многообещающее из которых называет "Iteratee" Oleg.

38
ответ дан luqui 27 November 2019 в 02:49
поделиться

[ Обновление : Prelude.readFile вызывает проблемы, как описано ниже, но переключающийся на использование Данных. Версии ByteString всего работы: Я больше не получаю исключение.]

новичок Haskell здесь, но в настоящее время я не покупаю заявление, которое "readFile строго, и закрывает файл, когда он сделан":

go fname = do
   putStrLn "reading"
   body <- readFile fname
   let body' = "foo" ++ body ++ "bar"
   putStrLn body' -- comment this out to get a runtime exception.
   putStrLn "writing"
   writeFile fname body'
   return ()

, Который работает как есть на файле, который я тестировал с, но если Вы комментируете putStrLn тогда, по-видимому, сбои writeFile. (Интересный, как сообщения об исключениях lame Haskell, испытывая недостаток в номерах строки и т.д.?)

Test> go "Foo.hs"
reading
writing
Exception: Foo.hs: openFile: permission denied (Permission denied)
Test> 

?!?!?

4
ответ дан 27 November 2019 в 02:49
поделиться

Это вызвано тем, что hGetContents ничего еще не делает: это - ленивый ввод-вывод. Только при использовании строки результата, файл на самом деле читается (или часть его, которая необходима). Если Вы хотите вынудить его быть считанным, можно вычислить его длину и использовать функцию seq, чтобы вынудить длину быть оцененной. Ленивый ввод-вывод может быть прохладным, но это может также сбивать с толку.

Для получения дополнительной информации, см. часть о ленивом вводе-выводе в Реальном мире Haskell, например.

2
ответ дан Erik Hesselink 27 November 2019 в 02:49
поделиться

Как ранее отмечено, hGetContents лениво. readFile строго, и закрывает файл, когда он сделан:

main = do contents <- readFile "foo"
          putStr contents

урожаи следующее в Объятиях

> main
blahblahblah

, где foo

blahblahblah

Интересно, seq, только гарантирует, что некоторая часть из входа читается, не все это:

main = do inFile <- openFile "foo" ReadMode
          contents <- hGetContents $! inFile
          contents `seq` hClose inFile
          putStr contents

урожаи

> main
b

А хороший ресурс: Создание программы Haskell, быстрее и меньшие: hGetContents, hClose, readFile

1
ответ дан Chris Conway 27 November 2019 в 02:49
поделиться

Объяснение довольно долго, чтобы быть включенным здесь. Простите мне за распределение короткой подсказки только: необходимо читать о "полузакрытых дескрипторах файлов" и "unsafePerformIO".

Короче говоря - это поведение является компромиссом дизайна между семантической четкостью и отложенными вычислениями. Необходимо или отложить hClose, пока Вы не абсолютно уверены Вы woudnt сделать что-либо с содержанием файла (как, назовите его в обработчике ошибок или somesuch), или используйте что-то еще помимо hGetContents для получения содержания файла нелениво.

0
ответ дан ADEpt 27 November 2019 в 02:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: