читать значения? (аналог fseek)
но это же не связанные вещи. bytestring ниоткуда не читает. может быть, у вас ленивый IO, читающий из файла?
bytestring - это упрощённо набор байт. есть же ещё lazy bytestring. и я так написал, потому что не знаю, как они работают. я подумал, что с помощью lazy bytestring можно абстрагироваться от файловой системы (хотя зачем? может, при передаче данных по сети можно более эффективно обрабатывать эти данные, однако ведь данные всё равно будут передаваться последовательно (т.е. не получится сделать fseek)) проблема в том, что файл может быть большим, но его не надо весь грузить в память, а только по мере надобности (честно, у меня плохое представление по этом всем вещам, поэтому могу писать какую-то фигню)
Lazy.ByteString — это очень простой и местами вредный способ абстрагироваться от входящего потока байт. про файловую систему он ничего не знает. но вы можете открыть файл, сделать fseek по нему, а потом с нужного места читать, через Lazy I/O или другим способом
может, лучше получить представление о лени, а потом прикладывать её к файлам?
да. получается, я хочу применить то, чего не понимаю. итог будет очевиден
а можно пример вредности?
когда файл на носителе меняется в процессе чтения
1. System.IO.withBinaryFile "file" ReadMode 2. System.IO.hSeek 3. Data.ByteString.Lazy.hGet, hGetContents
а на маленьких файлах может быть такое, что лучше будет загружать весь файл полностью? тогда придётся иметь две реализации (правда, придётся получать срез, что довольно неэффективно)
а в чём проблема? маленькие файлы тоже можно читать по частям
можно, да, но может лучше из маленького файла читать данные сразу?
будет более эффективно (предположение, обоснованное тем, что данные будут уже в памяти и не придётся лишний раз обращаться к диску)
BSL.getContents читает блоками. если файл маленький и полностью помещается в блок, то будет прочитан за раз
блочное чтение для этого сделано
получается, чтобы считывать с файла и считывать со строки мне придётся иметь две реализации? (я занимаюсь разбором MS CFB (FAT в файле), в котором нужно делать fseek, чтобы перемещаться по секторам)
что такое "считывать со строки"?
перемещайтесь по секторам (hSeek) и читайте файл (hGet). нет никаких проблем
строка в данном случае ByteString. На входе целая строка, а не файл
да, с файлами никаких проблем
на выходе возможность обратиться к какому-нибудь сектору (или цепочке секторов, но не суть. одно и то же)
что такое обратиться? прочитать строку? из строки строку не надо читать, она уже строка
дело в том, что в файлах формата MS CFB есть собственная, можно сказать, файловая система (с директориями и файлами). файловая система в файле, в общем. чтобы прочитать файл (в этой ФС), нужно сначала загрузить таблицу FAT-секторов (цепочку секторов, т.е. какой сектор следует за каким), далее понять, какой сектор является начальным для файла в этой ФС, а потом последовательно прочитать сектора, соединив все части. в общем, изначально нет смысла читать все сектора (и с файлами всё понятно, можно использовать, как вы писали выше, hSeek & hGet) со строкой я попробовал использовать splitAt, но он в память загружается вся строка (ведь результат — кортеж с началом и хвостом), но это в любом случае неизбежно
строка в любом случае должна быть в память загружена. что такое строка, не загруженная в память?
да, это так. дело в том, что я думаю над тем, можно ли не писать две реализации для строки и для файла. ведь отличается лишь метод получения секторов, но так как функция используется везде, то придётся писать две реализации не только этой функции, что очень плохо
можно написать один интерфейс произвольного доступа с двумя реализациями. только у сетевого потока нет произвольного доступа
нормальной ли практикой будет засунуть эту функцию в ReaderT?
у меня получилось что-то такое: class SectorGetter a where getSector :: a -> Integer -> Integer -> BL.ByteString однако, я понял, что если a = ByteString, то всё хорошо, но если a = Handle, то придётся возвращать IO ByteString, что не соответствует сигнатуре. может, тогда не пытаться писать единый интерфейс, а всё-таки написать две реализации (пусть, они и будут почти идентичны)?
да, DRY не закон. можно сначала покопировать, а потом обобщить, если будет нужда
всё же я смог обобщить, но похоже на какую-то фигню. и далее можно использовать (извините за скрины. если так нельзя, то ок. да вообще, наверное, вопросы такие глупые не стоит задавать, но дело в том, что годных мануалов по парсингу я не нашёл. ну либо я просто не хочу разбираться, поэтому задаю вопросы)
snd . BL.splitAt ~ BL.drop
вроде норм. почему фигня? что не нравится?
я бы здесь убрал Identity, оставив чистую функцию, а в конфиге её можно завернуть в pure
DRY-driven development не закон. Покопировать и обобщить — это как раз DRY.
не обязательно любые повторы обобщать, только те, которые жмут и выражают общую абстракцию
не нравится, что надо писать ненужные runGet, из конфига доставать функцию, которая получает сектор и т.п. наверное, если подумать, то можно написать без этого всего. как-то так: someFunc = do sectorNo <- getWord32le count <- getWord32le sector <- getSector return $ ... sector sectorNo count
да, можно всё в одну монаду спрятать
Обсуждают сегодня