"Заблокирован ресурс (файл заблокирован)" ошибка в Haskell
Я очень новичок в Haskell. Фактически, я работаю над в этом разделе этого урока.
Я наткнулся на этот фрагмент кода:
import System.IO
import Data.Char
main = do
contents <- readFile "girlfriend.txt"
writeFile "girlfriendcaps.txt" (map toUpper contents)
Что читает содержимое файла под названием "girlfriend.txt" и записывает версию файла с верхним обложением в новый файл под названием "girlfriendcaps.txt".
Итак, я хотел немного изменить код, чтобы принять имя файла. Я изменил код на это:
import System.IO
import Data.Char
main = do
path <- getLine
contents <- readFile path
writeFile path (map toUpper contents)
теперь, очевидно, основное различие здесь в том, что я читаю и записываю в тот же файл. Поскольку я сейчас думаю об этом, это должно быть ленивая оценка, но я получаю сообщение об ошибке "resource busy". Исправьте меня, если я ошибаюсь, но я думаю, что readFile не начинает читать файл, пока writeFile не попросит его содержимое. А затем writeFile пытается записать в файл, но он все равно должен открыть файл, потому что он также запрашивает содержимое. Я рядом?
Итак, реальный вопрос: как мне читать и писать в тот же файл в Haskell? Имеет смысл, что это сложнее, потому что вы будете писать в другой файл из файла, который вы читаете чаще всего, но для моего собственного назидания, как бы вы читали и записывали в тот же файл?
Ответы
Ответ 1
В зависимости от того, что вы пытаетесь сделать. Как правило, на любом языке это, вероятно, плохой дизайн, потому что, если что-то пойдет не так, как внутри программы, так и снаружи (например, пользовательская ошибка), вы уничтожили исходные данные и не можете попробовать снова. Он также требует, чтобы весь файл хранился в памяти, что здорово, если его несколько байт, но не так хорошо, когда кто-то решает запустить его в действительно большом файле.
Если вы действительно хотите это сделать, сгенерируйте временное имя файла для вывода, а затем, как только вы узнаете, что вы написали его успешно, вы можете удалить оригинал и переименовать новый.
Ответ 2
В самом деле, это "ленивая оценка".
import System.IO
import Data.Char
main = do
path <- getLine
contents <- readFile path
writeFile path (map toUpper contents)
Помните, что Haskell в первую очередь ленив в оценке, и поэтому большая часть подсистемы ввода-вывода. Поэтому, когда вы вызываете "readFile", вы начинаете передавать данные из файла. Когда вы сразу вызываете "writeFile", вы начинаете передавать байты обратно в один и тот же файл
Это будет ошибка (т.е. уничтожить ваши данные), поэтому Haskell блокирует ресурс, пока он не будет полностью оценен, и вы получите хорошее сообщение об ошибке.
Существует два решения:
- Не разрушайте файл, а не копируйте его в новый файл
- Или используйте строгий IO
Чтобы использовать строгий IO, рекомендуется использовать "текстовые" или "строгие" пакеты.
Ответ 3
Что вы ищете, так это открыть файл в ReadWriteMode
.
fileHandle <- openFile "fileName.txt" ReadWriteMode
contents <- hGetContents fileHandle
Там более сложный материал для навигации вперед и назад через файл.
См. Работа с файлами и дескрипторами из RWH и Операции над ручками в документах System.IO.