Аналог конструктора >:
для строк байтов называется >cons
. Он принимает байт и строку байтов и помещает байт в начало строки.
>ghci> B.cons 85 $ B.pack [80,81,82,84]
>Chunk "U" (Chunk "PQRT" Empty)
Модули для работы со строками байтов содержат большое количество функций, аналогичных функциям в модуле >Data.List
, включая следующие (но не ограничиваясь ими): >head
, >tail
, >init
, >null
, >length
, >map
, >reverse
, >foldl
, >foldr
, >concat
, >takeWhile
, >filter
и др.
Есть и функции, имя которых совпадает с именем функций из модуля >System.IO
, и работают они аналогично, только строки заменены значениями типа >ByteString
. Например, функция >readFile
в модуле >System.IO
имеет тип
>readFile :: FilePath –> IO String
а функция >readFile
из модулей для строк байтов имеет тип
>readFile :: FilePath –> IO ByteString
ПРИМЕЧАНИЕ. Обратите внимание, что если вы используете строгие строки и выполняете чтение файла, он будет считан в память целиком! При использовании ленивых байтовых строк файл будет читаться аккуратными порциями.
Копирование файлов при помощи Bytestring
Давайте напишем простую программу, которая принимает два имени файла в командной строке и копирует первый файл во второй. Обратите внимание, что модуль >System.Directory
уже содержит функцию >copyFile
, но мы собираемся создать нашу собственную реализацию.
>import System.Environment
>import qualified Data.ByteString.Lazy as B
>main = do
> (fileName1:fileName2:_) <– getArgs
> copy fileName1 fileName2
>copy :: FilePath –> FilePath –> IO ()
>copy source dest = do
> contents <– B.readFile source
> bracketOnError
> (openTemplFile "." "temp")
> (\(tempName, tempHandle) -> do
> hClose templHandle
> removeFile tempName)
> (\(tempName, tempHandle) -> do
> B.hPutStr tempHandle contents
> hClose tempHandle
> renameFile tempName dest)
В функции >main
мы получаем аргументы командной строки и вызываем функцию >copy
, в которой всё волшебство и происходит. Вообще говоря, можно было бы просто прочитать содержимое одного файла и записать его в другой. Однако если бы что-то пошло не так (например, закончилось бы место на диске), у нас в каталоге остался бы файл с некорректным содержимым. Поэтому мы пишем во временный файл, который в случае возникновения ошибки просто удаляется.
Сначала для чтения содержимого входного файла мы используем функцию >B.readFile
. Затем с помощью >bracketOnError
организуем обработку ошибок. Мы получаем ресурс посредством вызова >openTemplFile "." "temp"
, который возвращает пару из имени временного файла и его дескриптора. После этого указываем, что должно произойти при возникновении исключения. В этом случае мы закроем дескриптор и удалим временный файл. Наконец, выполняется собственно копирование. Для записи содержимого во временный файл используется функция