![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Сохранение StringList большого объема в файл [D2005, 2003]
_guest_ © (2013-09-16 16:33:00)Есть StringList с объемом текста в полгига. При попытке сохранить в файл или поток (что в общем то одно и то же) получаю "аут оф мемори", так как SaveTo... пытается сохранить его одним куском. А уже обращение к StringList.Text вызывает эту ошибку. Построчно в текстовый файл - пожалуйста, только времени не один час. Помогите, пожалуйста, буферизировать сохранение в поток. Для меня проблемой является уже даже получить размер результирующей строки. Рассмотрю любые альтернативные варианты. StringList формируется из кусков в количестве от десятков до сотен тысяч размером около 5 килобайт. Можно бы их сразу по получении сливать на диск, но мне перед этим надо их обработать все вместе, а обработка следующих кусков зависит от результатов обработки предыдущих.
DVM (2013-09-17 22:21:00) [21]
> _guest_ (17.09.13 16:19) [57]
> Если можно улучшить подскажите чуть более подробнее, чем
> "используй поток".
Любой сетевой компонент получает из сети в первую очередь бинарные данные, при перекладывании в TStringList или string производится множество совершенно ненужных тебе операций. Стрим там уже будет по-любому. В частности в Indy, любой Get запрос сведется к:
procedure DoRequest(const AMethod: TIdHTTPMethod; AURL: string;
ASource, AResponseContent: TStream; AIgnoreReplies: array of SmallInt); virtual;
И все остальные методы, возвращающие string и прочее все равно вызовут его. Плюс будут преобразования данных и копирования. Тебе ненужные и вот почему.
Ты делаешь Get, получаешь Stream в ответ. Тебе не надо самому в этом Stream как ты написал делать какие то Pos() и прочее. Это неправильный путь. Вот, например, ты написал:
> if Pos('"empty": "false"') > 0 и уже можно парсить или не
> парсить.
А если вдруг добавится лишний пробел после двоеточия? Вывод - JSON надо парсить парсером JSON, а не кустарным методом, который обязательно рано или поздно сломается. Итак, мы будем парсить исключительно парсером.
Смотрим ЛЮБОЙ JSON парсер и видим, что все они принимают на вход TStream. Спрашивается какого лешего гонять данные в памяти туда сюда, когда можно обойтись одним и тем же TStream?
JSON парсер вернет тебе набор объектов, которые ты уже можешь обрабатывать как тебе вздумается.
Плохиш (2013-09-17 18:04:00) [22]Что надо делать с отсутствующими полями?
_guest_ (2013-09-17 16:19:00) [23]
> DVM © (17.09.13 14:03) [56]
Никакой, только AddStrings и SaveToFile. Ну и тот парсер в Д2010 TJSONDocument тоже на вход берет строку. Т.е. как вариант я могу получать данные в строке, парсить тоже строку, сохранять надо в общем то тоже строку. Для меня, как непрофессионала в программировании, выглядит естественным ее родимую и использовать. И если честно, я применительно к моей задаче особой разницы с потоком не вижу, кроме того только, что сам код при работе со строкой будет поменьше и попонятней, хотя может и более медленным. Функции поиска подстроки, ее замены и т.д. уже реализованы. Хотя я допускаю, что кто-то повторил все это и для символов записанных в поток. Вы меня спрашиваете какой функционал я использую для списка строк и добавляете, что можно было использовать все что угодно. Так и есть, просто так сложилось исторически (дней 5 назад), что я использую synapse, а он мне возвращает список строк, вот и все. Я не стою насмерть за этот вариант, просто мои вопросы "чем лучше поток для моей задачи" воспринимаются не как вопрос, на который можно аргументированно ответить, а как нападки на работу с потоком вообще, и "а чем лучше строка". Ничем, просто пока оно вот так, как есть и работает. Если можно улучшить подскажите чуть более подробнее, чем "используй поток".
> Плохиш © (17.09.13 14:00) [55]
Они однотипны вот один:
{ "empty": "false" ,"objects":[ { "object_id":"76:14:10210:1", "source":"1", "object_cn":"76:14:010210:1", "address":"Рыбинский р-н, пос Каменники" } ] }
только количество атрибутов у object варьируется. Есть еще один вариант, почти тоже самое, но переводы строк присутствуют - под рукой сейчас нет, надо на этот комп на флешке перетаскивать.
Возвращаясь к предыдущему вопросу, сейчас:
if Pos('"empty": "false"') > 0 и уже можно парсить или не парсить. А в потоке? Уже есть такое или придется все заново писать?
DVM (2013-09-17 14:03:00) [24]
> _guest_ (17.09.13 13:56) [53]
> Ну хорошо-хорошо, но я так и не услышал чем на малом объеме
> поток лучше списка.
Какой такой функционал TStringList используется, чтобы непременно использовать именно его? Никакой, если переводы строк могут и отсутствовать.
С тем же успехом можно было взять все что угодно.
Плохиш (2013-09-17 14:00:00) [25]
> _guest_ (17.09.13 13:45) [48]
Можно увидеть пару примеров входных данных?
_guest_ (2013-09-17 13:58:00) [26]
> stas © (17.09.13 13:55) [52]
Так я так и делаю. Только в списке. Зачем нужна база или поток?
Я не успеваю уже читать посты и отвечаю невпопад, прервемся, а?
_guest_ (2013-09-17 13:56:00) [27]Ну хорошо-хорошо, но я так и не услышал чем на малом объеме поток лучше списка.
> stas © (17.09.13 13:47) [49]
Я понимаю, что лень это плохо, но вот вместо всего, что Вы написали в [49], я пишу просто HttpGetText с похожим результатом и все. Да мне после этого проще .Text в поток загнать. Еще раз: объясните чем список строк/строка хуже потока на 5000 символов.
stas (2013-09-17 13:55:00) [28]Пришли данные, разобрали что есть, чего нет и записали этот кусок.
stas (2013-09-17 13:53:00) [29]Тут не понял
>я уже говорил: надо собрать плоскую таблицу, а если какого-то атрибута нет, >то это не значит, что это "атр1":"" это значит что его нет совсем и длина >списка будет меньше. И при поступлении данных надо разбираться все ли есть >и если нет то чего именно.
Как это мешает сразу писать в файл?
_guest_ (2013-09-17 13:49:00) [30]Иногда с переводами строк иногда нет, но это же не принципиально, как и в случае xml. А кодировку легко установить встроенными методами самих компонентов, иногда просто указав желаемую кодировку в свойствах.
stas (2013-09-17 13:47:00) [31]_guest_ (17.09.13 13:37) [46]
С помощью wininet еще можно попробовать, забирать данные потоком.
Вот пример с HTTP
uses Wininet
....
function GetInetFileToStream(const fileURL:String; S:TStream): boolean;
const BufferSize = 1024;
var
hSession, hURL: HInternet;
ci: INTERNET_CONNECTED_INFO;
Buffer: array[1..BufferSize] of Byte;
BufferLen: DWORD;
sAppName,h: string;
header:Pchar;
len:Integer;
timeout:Integer;
begin
Result:=False;
sAppName := 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; MRSPUTNIK 2, 1, 0, 8 SW; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)';
hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG,
nil, nil, 0);
ci.dwConnectedState := INTERNET_STATE_CONNECTED;
ci.dwFlags := 0;
timeout := 300 * 1000; // 10 sec
InternetSetOption(hSession, INTERNET_OPTION_CONNECTED_STATE, @ci, sizeof(ci));
InternetSetOptionA(hSession,INTERNET_OPTION_CONNECT_TIMEOUT,@timeout,4);
InternetSetOptionA(hSession,INTERNET_OPTION_RECEIVE_TIMEOUT,@timeout,4);
InternetSetOptionA(hSession,INTERNET_OPTION_SEND_TIMEOUT,@timeout,4);
begin
h:='Accept: */*';
h:=h+#10#13+'Accept-Language: ru';
h:=h+#10#13+'Connection: Keep-Alive';
header:=pchar(h);
len:=Length(header);
end;
try
hURL := InternetOpenURL(hSession, PChar(fileURL),header,len,INTERNET_FLAG_RELOAD,0);
if hUrl=nil then exit;
repeat
InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen);
S.WriteBuffer(Buffer,BufferLen);
until BufferLen = 0;
Result:=True;
InternetCloseHandle(hURL);
finally
InternetCloseHandle(hSession)
end
end;
как сделать https - http://support.microsoft.com/kb/168151/ru
_guest_ (2013-09-17 13:45:00) [32]
> DVM © (17.09.13 13:41) [47]
Блин, не уйти :)
про инди уже написал, в принципе могу и на него перейти.
> Тогда это никак не "страничка".
Я не знаю как это назвать, но в любом из 4-х браузеров я вижу текст json именно как страничку или как назвать то, что на закладке в браузере.
DVM (2013-09-17 13:41:00) [33]
> stas © (17.09.13 13:29) [44]
> idHTTP умеет писать как в поток, так и встринглист
Но на кой он там мне совсем непонятно, особенно учитывая, что данные могут быть в разных кодировках и не содержать переводов строк вообще. Для частных случаев возможно.
> _guest_ (17.09.13 13:34) [45]
> Ну почему HTML, сразу JSON.
Тогда это никак не "страничка".
> Подскажите компонент возвращающий страничку в поток по HTTPS(!
> ) , буду работать с потоком.
TidHTTP
_guest_ (2013-09-17 13:37:00) [34]
> stas © (17.09.13 13:29) [44]
Да, только на indy фиг подберешь библиотеки для работы с HTTPS, а в моем случае еще две разных делфи на двух разных компах - вообще вешалка при миграции туда сюда.
_guest_ (2013-09-17 13:34:00) [35]
> stas © (17.09.13 13:11) [42]
Да мне нужно вытянуть данные, да сохранить в читаемом виде. Что мне может такого дать база, что принципиально бы изменило схему обработки: записал значения через запятую в строку, строку сохранил в файл. Структура данных не известна. Или Вы предлагаете использовать два столбца и как раз в них писать пару имя-значение, а ну еще в третий идентификатор их объединяющий. Ну напишу, что дальше? Буду вытягивать разное количество атрибутов на каждый идентификатор. Или дистинктом вытянуть имена атрибутов склеить по их числу новую таблицу и переписывать значения в нее, потом экспорт. Чем это проще собирания списка имя=значение и сразу сохранения в файл. Напомню, мне на выходе надо отдать текстовый файл.
По поводу
> то почему бы сразу по ходу поступления не писать в файл
я уже говорил: надо собрать плоскую таблицу, а если какого-то атрибута нет, то это не значит, что это "атр1":"" это значит что его нет совсем и длина списка будет меньше. И при поступлении данных надо разбираться все ли есть и если нет то чего именно.
> DVM © (17.09.13 13:21) [43]
Ну почему HTML, сразу JSON.
> Ну не нравится поток
Да нравится, удобный инструмент, но если
function HttpGetText(const URL: string; const Response: TStrings): Boolean;
он берет на входе TStrings, как я ему поток скормлю.
Подскажите компонент возвращающий страничку в поток по HTTPS(!) , буду работать с потоком.
Раз пошла такая дискуссия предупрежу: я отлучусь часа на три. Мне крайне все это интересно и вообще льстит, что со мной возятся, а не отфутболивают, как тут иногда бывает.
stas (2013-09-17 13:29:00) [36]idHTTP умеет писать как в поток, так и встринглист, даже процедура называется одинаково, либо Get либо Post, в зависимости от того что вы делаете.
DVM (2013-09-17 13:21:00) [37]
> _guest_ (17.09.13 12:36) [39]
> так чтобы из меня не тянуть клещами: с сайта идет не файл,
> а сама страничка.
HTML что ли? А JSON тогда откуда?
> _guest_ (17.09.13 13:03) [41]
> Наследник TStream берущий список строк? Если честно, ну
> не понимаю я зачем. Пришло два-три десятка строк, пусть
> без #13#10 одной строкой - без разницы, обработал их, поток
> то зачем?
Ну не нравится поток, возьми массив динамический, указатель на буфер в памяти и т.д. Куда то же данные которые возвращают сетевые компоненты должны быть помещены. Стрим просто самое удобное и универсальное с точки зрения дальнейшего использования средство. Но уж TStringList тут точно не к чему, на мой взгляд. К тому же все парсеры JSON как правило умеют принимать на вход TStream.
stas (2013-09-17 13:11:00) [38]_guest_ (17.09.13 12:30) [38]
Я так понимаю Вам из того что пришло нужно вытянуть данные и сохранить их в каком-то читаемом виде. Или нет?
Если да, то как раз СУБД в этом поможет.
А если анализ никакой не нужен, то почему бы сразу по ходу поступления не писать в файл, а ждать когда загрузятся все данные ? ведь могут свет отключить на 90% закачки и что по новой качать?
_guest_ (2013-09-17 13:03:00) [39]
> DVM © (17.09.13 12:42) [40]
Приходят по одному. Полагаться на строчность не буду. Буду использовать парсер. Наследник TStream берущий список строк? Если честно, ну не понимаю я зачем. Пришло два-три десятка строк, пусть без #13#10 одной строкой - без разницы, обработал их, поток то зачем? Это у меня результирующие данные большие, а входные маленькие. Моя ошибка, что в топике говоря о том, что данные поступают небольшими фрагментами, я не сказал "законченными фрагментами". То есть говорить про неспортивность на больших объемах не совсем корректно. Время тратится в основном на выполнение самого запроса и получения ответа зачастую далеко не с первого раза, я уже писал выше - от суток и более. На фоне этого остальное теряется. Конечно незачем еще увеличивать время работы, с другой это совершенно не принципиально. Сейчас идет процесс отладки в широком смысле, не только о коде. Т.е я смотрю сколько вообще пришло данных и какие, и меня запарило ждать, когда они сохранятся из списка. В рабочем режиме - запустят прогу и пару раз в сутки будут проверять все уже или еще не все.
DVM (2013-09-17 12:42:00) [40]
> _guest_ (17.09.13 12:30) [38]
> Потому что я использую делфийский компонент, любой на выбор:
> IdHTTP (indy), IEHTTP, HTTPSend (synapse). Похоже я сейчас
> узнаю что-то новое для себя. В общем то я с ними вожусь
> всего 3-й день, но по-моему каждый из них возвращает список
> строк в том или ином виде.
Ну понятно. А приходят эти данные порциями ровно по одному JSON документу или одним большим куском из нескольких склеенных?
Кстати, имей в виду, что не факт что твои JSON данные всегда будут поделены на строки. Т.е полагаться на это не стоит. Там вообще может не быть ни одного перевода строки (в JSON или XML) или где то его забудут сделать. Плюс делается явно лишняя работа по перекладыванию данных из одного места в другое. Не спортивно это на больших объемах.
Принимай данные в какой нить наследник TStream, парси его, потом в него принимай очередную порцию и опять парси и т.д.