![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Сохранение StringList большого объема в файл [D2005, 2003]
_guest_ © (2013-09-16 16:33:00)Есть StringList с объемом текста в полгига. При попытке сохранить в файл или поток (что в общем то одно и то же) получаю "аут оф мемори", так как SaveTo... пытается сохранить его одним куском. А уже обращение к StringList.Text вызывает эту ошибку. Построчно в текстовый файл - пожалуйста, только времени не один час. Помогите, пожалуйста, буферизировать сохранение в поток. Для меня проблемой является уже даже получить размер результирующей строки. Рассмотрю любые альтернативные варианты. StringList формируется из кусков в количестве от десятков до сотен тысяч размером около 5 килобайт. Можно бы их сразу по получении сливать на диск, но мне перед этим надо их обработать все вместе, а обработка следующих кусков зависит от результатов обработки предыдущих.
_guest_ (2013-09-19 12:14:00) [1]
> DVM © (19.09.13 12:10) [78]
В очередной раз могу, только поблагодарить всех и особенно Вас.
DVM (2013-09-19 12:10:00) [2]
> _guest_ (19.09.13 12:01) [77]
> Я заглянул в реализацию методов парсера, но никаких перекодировок
> там не увидел и поэтому нахожусь в сомнениях, а как же он
> разделители то узнает.
Как правило текстовые данные передаваемые по сети имеют либо однобайтную кодировку, например, cp1251, либо UFT-8. По крайней мере остальное встречается крайне редко. В любом случае символы, которые критичны для парсера, все имеют размер по одному байту. Парсер как правило читает по одному байту и переводит свою машину состояний в нужное состояние, попутно аккумулируя необходимые себе данные во внутренних структурах. Непосредственно на парсинг кодировка в этом случае не влияет. Но может получиться, что строки которые он выдаст перекодировать легко не получится. Вот если бы парсер выдавал строки в RawByteString тогда все было бы проще. Но попробуй.
_guest_ (2013-09-19 12:01:00) [3]
> DVM © (19.09.13 11:47) [75]
Ну в целом, понял. Но уж для полной ясности: если данные в потоке приходят не в той кодировке, которую хочется получить при выводе данных, то без строчного преобразования не обойтись? Функции перекодировки ведь только со строками работают? Я заглянул в реализацию методов парсера, но никаких перекодировок там не увидел и поэтому нахожусь в сомнениях, а как же он разделители то узнает. И если все-таки ему все равно с какой кодировкой работать, то может тогда пусть он отработает, а уже те строки, что он возвращает перекодировать куда надо, ведь теоретически перекодируемых данных становится меньше.
DVM (2013-09-19 11:50:00) [4]
> Попутно, еще вопрос: это, конечно, не принципиально, но
> после парсинга в перечислителе данные идут в совершенно
> другом порядке, чем в исходнике. На это можно как-то влиять?
>
Зависит от парсера, свой парсер если написать если только.
DVM (2013-09-19 11:47:00) [5]
> _guest_ (19.09.13 11:39) [74]
По уму надо делать так (вариант для Indy):
Кодировка возможно указана в HTTP заголовках сервера. У TIdHTTP есть событие OnHeadersAvailable кажется, там ты еще до получения данных в свой стрим сможешь получить имя кодировки. Далее возможны 2 варианта:
1) Получаем данные TStringStream, указывая кодировку для него, далее забираем строку из нее в Unicode и отдаем парсеру. Будет копирование данных, что неизбежно при декодировании.
2) Более сложный. Делаем наследника от TMemoryStream, переопределяем в нем метод Write таким образом, чтобы поток при записи данных в него сразу перекодировал их, используя кодировку переданную ему скажем в конструктор, которую в свою очередь мы получили из HTTP заголовков.
Сложность тут в том, чтобы конвертировать данные, нужно получить их некое минимальное количество, определяемое кодировкой (для UTF8 например один символ может занимать различное число байт).
Это первое что пришло в голову, придумаю еще варианты - напишу.
_guest_ (2013-09-19 11:39:00) [6]
> DVM © (19.09.13 10:58) [73]
Хороший вопрос... Когда получил первые данные, вставил в мемо, увидел проблемы, в онлайн-декодере посмотрел исходную кодировку и utf8 в cp1251 тем или и иным способом. Хотя понятно, что тот же браузер кодировку уже знает перед отображением данных, так как кириллица сразу читается нормально.
Попутно, еще вопрос: это, конечно, не принципиально, но после парсинга в перечислителе данные идут в совершенно другом порядке, чем в исходнике. На это можно как-то влиять?
DVM (2013-09-19 10:58:00) [7]
> _guest_ (19.09.13 09:25) [72]
> строкой - подал на вход нужную кодировку - в ней и получил
> ответ
Как ты определяешь кодировку JSON данных?
_guest_ (2013-09-19 09:25:00) [8]Я извиняюсь, и уж последний вопрос, хотя уже и офтоп. А если данные скармливать парсеру в потоке, как он будет разбираться с кодировкой? Или кодировку править при получении из перечислителя? В случае со строкой - подал на вход нужную кодировку - в ней и получил ответ. А подал я поток и получил нечто, для чего не могу подобрать кодировку ни я, ни онлайн перекодировщики.
_guest_ (2013-09-18 15:37:00) [9]
> DVM © (18.09.13 13:30) [70]
Спасибо, возьму на заметку. Но время, как обычно, поджимает, посмотрю позже.
DVM (2013-09-18 13:30:00) [10]Кстати, по поводу SSL/TLS. Недавно обнаружил, что всем давно известная библиотека Delphi Fundamentals весьма сильно преобразилась в лучшую сторону и обрела поддержку SSL/TLS (причем нативную, без сторонних dll!). JSON парсер там тоже имеется. Можно ее попробовать. SSL я проверял - отлично работает: http://sourceforge.net/p/fundementals/code/HEAD/tree/trunk/
_guest_ (2013-09-18 10:46:00) [11]
> Плохиш © (18.09.13 10:32) [66]
Нет, структура неизвестна. Т.е. можно, конечно, на какой то выборке посмотреть глазами, составить структуру и пользоваться ей. Но я уже натыкался на то, что обязательно встретится что-нибудь не учтенное. Но решение у меня почти готово. Что такое "стандартный" Text ? файл?
> DVM © (18.09.13 10:36) [68]
Да, спасибо, именно его и нашел уже. обычно предлагаются 4: JSON delphi library
Delphi Web Utils
json-superobject
tiny-json
но все советуют именно его.
DVM (2013-09-18 10:36:00) [12]
> _guest_ (18.09.13 08:44) [60]
> Спасибо за подсказки, сейчас поищу парсер, работающий с
> потоком.
Delphi SuperObject лучший имхо: https://code.google.com/p/superobject/
_guest_ (2013-09-18 10:35:00) [13]
> stas © (18.09.13 10:14) [64]
Он отпал, начиная с [10], но все что было дальше - было крайне полезным для меня.
> stas © (18.09.13 10:18) [65]
Речь не идет о выкачанных процентах, я всегда могу продолжить с любого места, так как это происходит в режиме запрос-ответ и запрос посылаю я. Речь о том, что у меня есть некий эталон по количеству данных - общее количество участков. И если на сайте их значительно меньше, то они не могут использоваться при анализе.
Плохиш (2013-09-18 10:32:00) [14]
> _guest_ (18.09.13 08:44) [60]
>
> > Плохиш © (17.09.13 18:04) [58]
>
> Ничего, на месте пустого поля пропуск, разделитель и поехали
> дальше.
Т.е. структура известна. Тогда совершенно не понятна проблема. Загружаешь данные, парсируешь, сохраняешь. Никаких гигабайтов в памяти. Открою страшную тайну, даже в стандартный Textможно дописывать данные.
stas (2013-09-18 10:18:00) [15]по поводу 98%, я к тому что, допустим качали качали, вырубили электричество, но 98% на диске закачаны, и теперь не качаем все заново, а делаем докачку 2%, но тут надо запоминать точку остановки,и докачать.
Правда не знаю все сервера это могут делать или нет.
stas (2013-09-18 10:14:00) [16]_guest_ (18.09.13 09:55) [63]
т.е. вопрос о том что не получается сохранить большой кусок текста отпадает, т.к. можно сохранять кусками по ходу? или нет? )
_guest_ (2013-09-18 09:55:00) [17]
> stas © (18.09.13 09:33) [62]
> Я так и не понял, Вам надо все выкачать, а потом обработать
> или получил часть обработал, сохранил ?
На конечный результат последовательность действий не влияет, можно и так и этак. Как я получаю данные, я писал уже несколько раз, повторюсь: данные получаю в виде небольших законченных json-объектов, пример в [57]. И, имхо, нет особой разницы все ли выкачать и сохранить, а потом обрабатывать и сохранять снова или же получил-обработал-сохранил, за исключением того, что во втором случае исключается промежуточная запись/чтение, но повторюсь: на сам результат это не влияет. Не надо кидать в меня камнями за первый вариант. Объясняю: данные нужны все или не нужны вовсе. Поэтому если я скачал и обработал 98% информации, значит я проделал лишнюю (в основном по времени) работу. А если я скачал, увидел, что 2% не хватает, то я могу и не обрабатывать. По-хорошему, надо реализовывать оба варианта и давать оператору выбор, чтобы он поработав на реальных данных смог определится, каким способом он хочет пользоваться.
stas (2013-09-18 09:33:00) [18]_guest_ (18.09.13 08:50) [61]
А если поток сделаете TFileStream, то будет напрямую писаться на диск, только не понятно как парсер будет работать, забирать все в ОЗУ или частями.
Я так и не понял, Вам надо все выкачать, а потом обработать или получил часть обработал, сохранил ?
_guest_ (2013-09-18 08:50:00) [19]ЗЗЫ. Вот сейчас, когда Вы меня замотивировали, я обнаружил, что и synapse может вернуть поток, так что все упрощается, дело за парсером.
_guest_ (2013-09-18 08:44:00) [20]
> Плохиш © (17.09.13 18:04) [58]
Ничего, на месте пустого поля пропуск, разделитель и поехали дальше. Просто у разных объектов могут отсутствовать разные поля. Поэтому общую структуру надо или считывать после загрузки всех данных или создавать в процессе загрузки, правда при этом связанные по смыслу поля могут разъехаться друг от друга, плюс структура в выходных файлах в этом случае будет варьироваться и как то придется их потом склеивать, очевидно за два прохода.
> DVM © (17.09.13 22:21) [59]
Вот. Аргументированный ответ. Блестяще и убедительно. И если бы мне удалось подобрать openssl к тому indy что в 2007-й на работе, я прямо сейчас бы стал переделывать. А так придется ждать до вечера.
А насчет парсера, никакой кустарщины не будет. Я прямо сейчас не гоню данные на выход, только оцениваю их количество и качество. Т.е. вполне возможна ситуация, что я выдам не программу, а вывод, что данных на сайте недостаточно и программа не нужна. И только поэтому на этапе оценки использую такую ерунду. И да, лишние или недостающие пробелы, прямые и обратные слеши в данных - все это встречается. Я пока просто отсекаю - полпроцента потерь пока несущественны. Все что не прошло входной контроль - в отдельный файл, и потом буду разбираться с этим.
Спасибо за подсказки, сейчас поищу парсер, работающий с потоком.