Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2014.08.03;
Скачать: [xml.tar.bz2];

Вниз

Сохранение StringList большого объема в файл   Найти похожие ветки 

 
_guest_   (2013-09-16 16:33) [0]

Есть StringList с объемом текста в полгига. При попытке сохранить в файл или поток (что в общем то одно и то же) получаю "аут оф мемори", так как SaveTo... пытается сохранить его одним куском. А уже обращение к StringList.Text вызывает эту ошибку.  Построчно в текстовый файл - пожалуйста, только времени не один час. Помогите, пожалуйста, буферизировать сохранение в поток. Для меня проблемой является уже даже получить размер результирующей строки. Рассмотрю любые альтернативные варианты. StringList формируется из кусков в количестве от десятков до сотен тысяч размером около 5 килобайт. Можно бы их сразу по получении сливать на диск, но мне перед этим надо их обработать все вместе, а обработка следующих кусков зависит от результатов обработки предыдущих.


 
DVM ©   (2013-09-16 16:56) [1]

Попробуй вот этот буферизованный поток, пиши в него построчно, должно стать быстрее, размер буфера подбери только.

http://pastebin.com/70wj5mTS


 
_guest_   (2013-09-16 17:22) [2]

Спасибо, попробую, хотя сомнения и одолевают - больше 14 млн. строк ...


 
brother ©   (2013-09-16 17:41) [3]

я даже боюсь предположить что там...


 
DVM ©   (2013-09-16 17:45) [4]


> _guest_   (16.09.13 17:22) [2]

Это логи что ли какие? А зачем все в память то грузить было? Просто дело в том, что сейчас оно у тебя влезло, а завтра не влезет и без сохранения даже ты получишь Out Of Memory на 32 бит системе. На 64 не получишь, но будет все тормозить сильно.


 
_guest_   (2013-09-16 17:54) [5]


> brother ©   (16.09.13 17:41) [3]

Какая-то фигня о земельных участках на один район в формате json. Только мне кажется, эта информация не слишком поможет в решении задачи. Скорее всего придется сразу в поток или файл писать Получение данных процесс длительный - от суток и больше, операция сохранения кусками не будет сильно заметной на этом фоне. Просто со списком работать немного удобнее, плюс мне удалось разбить весь процесс на несколько операций, каждая из которых сохраняет свой результат в виде файла, который попадает на вход следующей. В случае каких-либо проблем можно будет начинать не с самого начала, а с той операции, которая не завершилась успешно.

> DVM ©   (16.09.13 16:56) [1]

К сожалению процесс не слишком ускорился: обработалось чуть больше
1.5 млн. строк за 10 минут. Еще умножаем на 10, плюс за этим само сохранение из потока в файл..., в общем пока ищу дальше. А кстати, какого типа поток надо давать на вход  TStreamProxy? Может я чего впопыхах не понял у меня memoty.


 
_guest_   (2013-09-16 17:58) [6]


> DVM ©   (16.09.13 17:45) [4]

Печально, сейчас 64 бита, но куда поставят прогу, я не знаю. Буду думать.


 
DVM ©   (2013-09-16 18:02) [7]


> _guest_   (16.09.13 17:54) [5]


> А кстати, какого типа поток надо давать на вход  TStreamProxy?
>  Может я чего впопыхах не понял у меня memoty.

Неееее.  TStreamProxy это лишь обертка. Понятно почему у тебя нет ускорения.

Использовать надо так:
BuffStream := TBufferedStream.Create(TFileStream.Create(...), true);

Далее пишешь в BuffStream


 
Юрий Зотов ©   (2013-09-16 19:16) [8]

> _guest_   (16.09.13 17:54) [5]
>  у меня memoty.

То есть, и стринглист в памяти, и поток тоже в памяти. То есть, мы копируем здоровенную инфу из одного места памяти в другое место той же памяти. И удивляемся, что получили "аут оф мемори".


 
Sha ©   (2013-09-16 23:42) [9]

> Просто со списком работать немного удобнее

а что именно надо сделать с данными?


 
_guest_   (2013-09-17 09:17) [10]


> DVM ©   (16.09.13 18:02) [7]

Да-да. Я в первую очередь FileStream и попробовал, но прироста скорости практически не получил. Очевидно, это обусловлено тем, что строк много, но они короткие типа "имя":"значение". Поэтому при построчной перезаписи преимуществ буферизации почти и нет.

> Юрий Зотов ©   (16.09.13 19:16) [8]
То есть, и стринглист в памяти, и поток тоже в памяти. То есть, мы копируем здоровенную инфу из одного места памяти в другое место той же памяти. И удивляемся, что получили "аут оф мемори".

Нет. В результате этого действия ошибка не возникает, поэтому и не удивляюсь. И, между нами, даже если я пару-тройку раз растиражирую поток такого объема она не возникает, тормозится при свопинге - это да. Ошибки нет при работе со списком такого объема, она  возникает при обращении к StringList.Text см.[1]. И то, что он нормально обрабатывается меня и подвело. Идея, что называется в лоб, была простой: получить строку, выдергивать из нее куски, а уж куда их писать в поток файловый или нет, непосредственно в файл ли - это не принципиально. Куски были бы заметно больше, чем одна строка и сохранение не заняло бы настолько много времени, ведь перезапись файла такого объема никого не шокирует. Я уткнулся в то, что не смог получить доступ к этой строке.

> Sha ©   (16.09.13 23:42) [9]
> а что именно надо сделать с данными?

Небольшой анализ, а потом все вывалить в mid он же csv он же просто текстовый файл со значениями через какой-нибудь разделитель. Потом аналитики его заберут в Excel или Access или еще куда-то, но требуют именно текстовый файл в виде плоской таблицы.

Я уже понял, что придется данные разбить по кварталам, каждый из них сохранить в свой файл, а после обработки слить в один. Ничего страшного с любой точки зрения в этом нет, на мой взгляд - нормальное решение. Я не очень много знаю о Делфи, вот и решил спросить. может кто-то уже натыкался на такую задачу.


 
_guest_   (2013-09-17 09:17) [11]


> DVM ©   (16.09.13 18:02) [7]

Да-да. Я в первую очередь FileStream и попробовал, но прироста скорости практически не получил. Очевидно, это обусловлено тем, что строк много, но они короткие типа "имя":"значение". Поэтому при построчной перезаписи преимуществ буферизации почти и нет.

> Юрий Зотов ©   (16.09.13 19:16) [8]
То есть, и стринглист в памяти, и поток тоже в памяти. То есть, мы копируем здоровенную инфу из одного места памяти в другое место той же памяти. И удивляемся, что получили "аут оф мемори".

Нет. В результате этого действия ошибка не возникает, поэтому и не удивляюсь. И, между нами, даже если я пару-тройку раз растиражирую поток такого объема она не возникает, тормозится при свопинге - это да. Ошибки нет при работе со списком такого объема, она  возникает при обращении к StringList.Text см.[1]. И то, что он нормально обрабатывается меня и подвело. Идея, что называется в лоб, была простой: получить строку, выдергивать из нее куски, а уж куда их писать в поток файловый или нет, непосредственно в файл ли - это не принципиально. Куски были бы заметно больше, чем одна строка и сохранение не заняло бы настолько много времени, ведь перезапись файла такого объема никого не шокирует. Я уткнулся в то, что не смог получить доступ к этой строке.

> Sha ©   (16.09.13 23:42) [9]
> а что именно надо сделать с данными?

Небольшой анализ, а потом все вывалить в mid он же csv он же просто текстовый файл со значениями через какой-нибудь разделитель. Потом аналитики его заберут в Excel или Access или еще куда-то, но требуют именно текстовый файл в виде плоской таблицы.

Я уже понял, что придется данные разбить по кварталам, каждый из них сохранить в свой файл, а после обработки слить в один. Ничего страшного с любой точки зрения в этом нет, на мой взгляд - нормальное решение. Я не очень много знаю о Делфи, вот и решил спросить. может кто-то уже натыкался на такую задачу.


 
_guest_   (2013-09-17 09:19) [12]

Извините, кнопку "Добавить" нажал один раз. Или мышку менять или указательный палец.


 
Sha ©   (2013-09-17 09:48) [13]

> Небольшой анализ, а потом все вывалить в mid он же csv он же просто
> текстовый файл со значениями через какой-нибудь разделитель.

Тогда и свойство Text не нужно, и, вероятно, сам StringList.


 
_guest_   (2013-09-17 09:57) [14]


> Sha ©   (17.09.13 09:48) [13]

А где же держать данные, если они в виде списка строк и приходят?


 
brother ©   (2013-09-17 10:00) [15]

array of string?


 
Sha ©   (2013-09-17 10:05) [16]

> А где же держать данные

до сих пор не ясно, зачем их держать или зачем держать их все


 
_guest_   (2013-09-17 10:06) [17]


> brother ©   (17.09.13 10:00) [15]

Не думал о массиве. А его можно быстро сохранить, т.е. можно ли получить кусок массива как буфер? Если нет, то в чем собственно выигрыш?


 
brother ©   (2013-09-17 10:06) [18]

можно многое, но [16]?


 
Inovet ©   (2013-09-17 10:06) [19]

> [15] brother ©   (17.09.13 10:00)
> array of string?

А в чём принципиальная разница? Я понимаю - в БД какую загрузить и её средствами обрабатывать, может быть.


 
DVM ©   (2013-09-17 10:22) [20]


> _guest_   (17.09.13 09:17) [10]


> Да-да. Я в первую очередь FileStream и попробовал, но прироста
> скорости практически не получил. Очевидно, это обусловлено
> тем, что строк много, но они короткие типа "имя":"значение".
>  Поэтому при построчной перезаписи преимуществ буферизации
> почти и нет.

Ну именно запись в файл у тебя должна была ускориться при буфере достаточного размера. Но раз ты прироста не заметил, то можно предположить, что узкое место у тебя не запись в файл или ты вообще что-то не так делаешь.


 
_guest_   (2013-09-17 10:23) [21]


> Sha ©   (17.09.13 10:05) [16]
> до сих пор не ясно, зачем их держать или зачем держать их все

Да, в общем то, не за чем. От инертности моего мышления. ТЗ нету, состава приходящих данных нету, в смысле "ты сам посмотри, что там приходит", а оно приходит далеко не однородное. Я уже решил разбивать на кварталы [10]. С другой стороны, не каждый же участок сразу в свой файл писать, их же сотни тысяч - даже на харде так хранить не выгодно.


 
Sha ©   (2013-09-17 10:24) [22]

_guest_   (17.09.13 10:23) [21]

Очевидно, что если надо посчитать сумму большого объема данных,
то нет смысла сначала грузить их стринглист, а потом считать.

Похожим образом можно поступить и для поквартальных сумм.

Довольно редко попадаются так зависимые данные,
чтобы была абсолютно необходима их полная загрузка в память.


 
_guest_   (2013-09-17 10:37) [23]


> Sha ©   (17.09.13 10:24) [22]

Да я согласен, конечно. Только мне не посчитать, а упорядочить эти данные надо, а они, как я уже говорил, неоднородные. Где-то есть такое значение, где-то нет, но есть другое, которого нет еще где-либо - нет жестко заданной структуры. Что при преобразовании в общую таблицу доставляет определенные неудобства. Собственно, я уже придумал как это сделать, работаю над реализацией.
Ветку можно закрывать, направление работы понятно. Получил даже больше, чем хотел :) общение с умными людьми не проходит бесследно. Всем большое спасибо.


 
DVM ©   (2013-09-17 10:40) [24]


> _guest_   (17.09.13 10:23) [21]

Если ты говоришь, что это JSON, и он грузится долго, то имеет смысл обрабатывать его на лету по мере загрузки. Для этого нужно будет разработать потоковый JSON парсер по аналогии с SAX парсером для XML. Я бы так и поступил. Получили кусок данных отдали парсеру - он выплюнул нужные нам данные, потом следующий кусок и так далее. Это если по уму делать.


 
_guest_   (2013-09-17 10:54) [25]


> DVM ©   (17.09.13 10:40) [24]

Какой-то json парсер есть прямо в делфи по крайней мере в 2010. И в финале, так и будет, как Вы описали. Со дня на день пересяду с 2007 на xe. Проблема не в этом. Вот прямо сейчас мне без разницы распарсенные у меня данные или нет (уберутся всякие скобочки и вместо двоеточия будет стоять равно), если они разные по составу, а максимально возможного состава я не узнаю, пока не получу их все.


 
DVM ©   (2013-09-17 11:14) [26]


> _guest_   (17.09.13 10:54) [25]


> Какой-то json парсер есть прямо в делфи по крайней мере
> в 2010.

Я не видел JSON парсеров которые бы работали так как я описал. Да и с XML то не густо, писал сам для ограниченного применения такой.


 
_guest_   (2013-09-17 11:25) [27]


> DVM ©   (17.09.13 11:14) [26]

Я не силен в этом, и мне не очень понятно зачем нужен "потоковый" парсер. Если данные приходят кусками, а так оно и есть, то: пришли данные, распарсили их обычным, не потоковым парсером, полученные данные сохранили. Я не знаю что такое SAX, правда. Могу быстренько глянуть в инете для уменьшения своей безграмотности, но для xml куча обычных парсеров. Очевидно, я не уловил того, что Вы хотели донести в [24], каких то особенностей работы. Или имеется ввиду обработка в другом потоке для уменьшения времени работы? Если можно, то чуть подробнее.


 
DVM ©   (2013-09-17 11:44) [28]


> _guest_   (17.09.13 11:25) [27]


> Я не силен в этом, и мне не очень понятно зачем нужен "потоковый"
> парсер. Если данные приходят кусками, а так оно и есть,
> то: пришли данные, распарсили их обычным, не потоковым парсером,
>  полученные данные сохранили.

Потоковый парсер или SAX парсит данные по мере поступления,  в отличие от DOM парсера который строит некоторую структуру (дерево) в памяти из элементов. Первый не потребляет памяти вообще и работает быстро, т.к. просто из потока данных вычленяет элементы и отдает их в событиях. Что делать с найденными элементами решать тому кто парсер использует, либо отбрасывать, либо сохранять где то.  Преимущество такого парсера - он может обработать сравнительно быстро любой объем данных при незначительном потреблении памяти.

DOM парсер же потребляет памяти пропорционально размеру входных данных и результат его работы мы увидим только после того, как он полностью распарсит данные, а распарсит он их только когда закроется последний тег и в стеке его тегов не останется ничего. Тогда он нам выплюнет дерево. Очевидно, что в большом документе это будет только тогда, когда мы его считаем весь.


 
DVM ©   (2013-09-17 11:49) [29]


> _guest_   (17.09.13 11:25) [27]

Вот пример из википедии:


{
  "firstName": "Иван",
  "lastName": "Иванов",
  "address": {
      "streetAddress": "Московское ш., 101, кв.101",
      "city": "Ленинград",
      "postalCode": 101101
  },
  "phoneNumbers": [
      "812 123-1234",
      "916 123-4567"
  ]
}

<person>
 <firstName>Иван</firstName>
 <lastName>Иванов</lastName>
 <address>
   <streetAddress>Московское ш., 101, кв.101</streetAddress>
   <city>Ленинград</city>
   <postalCode>101101</postalCode>
 </address>
 <phoneNumbers>
   <phoneNumber>812 123-1234</phoneNumber>
   <phoneNumber>916 123-4567</phoneNumber>
 </phoneNumbers>
</person>


DOM парсеры не распарсят нам данные файлы, пока в первом случае мы не получим последнюю скобочку }, а во втором тег < /person>


 
_guest_   (2013-09-17 11:59) [30]


> DVM ©   (17.09.13 11:44) [28]

Данные приходят небольшими законченными кусками. Их можно считать элементами какого-то общего документа, а можно и не считать. Если по аналогии с xml, то меня вполне устроит модель dom, т.к. приходит не какой-то большой документ, а очень много маленьких и данные из них нужны абсолютно все. Я потому и не заострял на этом моменте внимания, что сама структура данных простая: имя-значение, и если я выкину все скобки а двоеточие заменю на знак равенства, то получу список типа name=value, вот и весь парсинг. Логически что там приходит, мне все равно, раскидал по столбцам и сохранил.


 
DVM ©   (2013-09-17 12:02) [31]


> _guest_   (17.09.13 11:59) [30]


> т.к. приходит не какой-то большой документ, а очень много
> маленьких

А, ну это меняет дело. Придется в потоке данных находить границы этих маленьких документов, если они известны и отдавать найденное парсеру. Несколько неоптимальный путь, но рабочий.


 
_guest_   (2013-09-17 12:05) [32]


> DVM ©   (17.09.13 12:02) [31]

Нет никаких границ и потока, данные приходят в виде StringList"ов.


 
_guest_   (2013-09-17 12:08) [33]

Собственно, я извиняюсь, что сразу все не написал, просто на момент обращения на форум, я решал конкретную задачу по сохранению большого списка в файл, а дискуссия вышла намного более познавательной для меня.


 
DVM ©   (2013-09-17 12:13) [34]


> Нет никаких границ и потока, данные приходят в виде StringList"ов.

Откуда они приходят в таком виде?


 
_guest_   (2013-09-17 12:14) [35]


> DVM ©   (17.09.13 12:13) [34]

С сайта


 
DVM ©   (2013-09-17 12:16) [36]


> _guest_   (17.09.13 12:14) [35]

Че то я не понимаю, как с сайта может прийти дельфийский объект TStringList?
Приходит именно поток данных TStream или буфер (массив данных) из которого потом кто-то перекладывает данные за каким то лешим в TStringList, хотя парсить можно прям оригинальный буфер без лишних телодвижений.


 
stas ©   (2013-09-17 12:17) [37]

_guest_   (17.09.13 12:08) [33]
С такими объемами Вам придется освоить СУБД.


 
_guest_   (2013-09-17 12:30) [38]


> DVM ©   (17.09.13 12:16) [36]

Потому что я использую делфийский компонент, любой на выбор: IdHTTP (indy), IEHTTP, HTTPSend (synapse). Похоже я сейчас узнаю что-то новое для себя. В общем то я с ними вожусь всего 3-й день, но по-моему каждый из них возвращает список строк в том или ином виде.

> stas ©   (17.09.13 12:17) [37]

Зачем? Чтобы текст в одном виде сохранить как текст в другом. Вся обработка исключительно строчная, ничего не надо искать, ничего выбирать или вычислять. Из-за объемов? Так пока что результирующие файлы блокнотом++ спокойно открывались, ну вот до последнего раза. Так мне смотреть на него и не надо.


 
_guest_   (2013-09-17 12:36) [39]

> DVM ©   (17.09.13 12:16) [36]
так чтобы из меня не тянуть клещами: с сайта идет не файл, а сама страничка. Так что если я чего недопонимаю, то Вы меня поправьте.


 
DVM ©   (2013-09-17 12:42) [40]


> _guest_   (17.09.13 12:30) [38]


> Потому что я использую делфийский компонент, любой на выбор:
>  IdHTTP (indy), IEHTTP, HTTPSend (synapse). Похоже я сейчас
> узнаю что-то новое для себя. В общем то я с ними вожусь
> всего 3-й день, но по-моему каждый из них возвращает список
> строк в том или ином виде.

Ну понятно. А приходят эти данные порциями ровно по одному JSON документу или одним большим куском из нескольких склеенных?

Кстати, имей в виду, что не факт что твои JSON данные всегда будут поделены на строки. Т.е полагаться на это не стоит. Там вообще может не быть ни одного перевода строки (в JSON или XML) или где то его забудут сделать. Плюс делается явно лишняя работа по перекладыванию данных из одного места в другое. Не спортивно это на больших объемах.
Принимай данные в какой нить наследник TStream, парси его, потом в него принимай очередную порцию и опять парси и т.д.


 
_guest_   (2013-09-17 13:03) [41]


> DVM ©   (17.09.13 12:42) [40]

Приходят по одному. Полагаться на строчность не буду. Буду использовать  парсер. Наследник TStream берущий список строк? Если честно, ну не понимаю я зачем. Пришло два-три десятка строк, пусть без #13#10 одной строкой - без разницы, обработал их, поток то зачем? Это у меня результирующие данные большие, а входные маленькие. Моя ошибка, что в топике говоря о том, что данные поступают небольшими фрагментами, я не  сказал "законченными фрагментами". То есть говорить про неспортивность на больших объемах не совсем корректно. Время тратится в основном на выполнение самого запроса и получения ответа зачастую далеко не с первого раза, я уже писал выше - от суток и более. На фоне этого остальное теряется. Конечно незачем еще увеличивать время работы, с другой это совершенно не принципиально. Сейчас идет процесс отладки в широком смысле, не только о коде. Т.е я смотрю сколько вообще пришло данных и какие, и меня запарило ждать, когда они сохранятся из списка. В рабочем режиме - запустят прогу и пару раз в сутки будут проверять все уже или еще не все.


 
stas ©   (2013-09-17 13:11) [42]

_guest_   (17.09.13 12:30) [38]
Я так понимаю Вам из того что пришло нужно вытянуть данные и сохранить их в каком-то читаемом виде. Или нет?
Если да, то как раз СУБД в этом поможет.
А если анализ никакой не нужен, то почему бы сразу по ходу поступления не писать в файл, а ждать когда загрузятся все данные ? ведь могут свет отключить на 90% закачки и что по новой качать?


 
DVM ©   (2013-09-17 13:21) [43]


> _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:29) [44]

idHTTP умеет писать как в поток, так и встринглист, даже процедура называется одинаково, либо Get либо Post, в зависимости от того что вы делаете.


 
_guest_   (2013-09-17 13:34) [45]


> 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(!) , буду работать с потоком.
Раз пошла такая дискуссия предупрежу: я отлучусь часа на три. Мне крайне все это интересно и вообще льстит, что со мной возятся, а не отфутболивают, как тут иногда бывает.


 
_guest_   (2013-09-17 13:37) [46]


> stas ©   (17.09.13 13:29) [44]

Да, только на indy фиг подберешь библиотеки для работы с HTTPS, а в моем случае еще две разных делфи на двух разных компах - вообще вешалка при миграции туда сюда.


 
DVM ©   (2013-09-17 13:41) [47]


> stas ©   (17.09.13 13:29) [44]


> idHTTP умеет писать как в поток, так и встринглист

Но на кой он там мне совсем непонятно, особенно учитывая, что данные могут быть в разных кодировках и не содержать переводов строк вообще. Для частных случаев возможно.


> _guest_   (17.09.13 13:34) [45]


> Ну почему HTML, сразу JSON.

Тогда это никак не "страничка".


> Подскажите компонент возвращающий страничку в поток по HTTPS(!
> ) , буду работать с потоком.

TidHTTP


 
_guest_   (2013-09-17 13:45) [48]


> DVM ©   (17.09.13 13:41) [47]

Блин, не уйти :)
про инди уже написал, в принципе могу и на него перейти.

> Тогда это никак не "страничка".

Я не знаю как это назвать, но в любом из 4-х браузеров я вижу текст json именно как страничку или как назвать то, что на закладке в браузере.


 
stas ©   (2013-09-17 13:47) [49]

_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:49) [50]

Иногда с переводами строк иногда нет, но это же не принципиально, как и в случае xml. А кодировку легко установить встроенными методами самих компонентов, иногда просто указав желаемую кодировку в свойствах.


 
stas ©   (2013-09-17 13:53) [51]

Тут не понял
>я уже говорил: надо собрать плоскую таблицу, а если какого-то атрибута нет, >то это не значит, что это "атр1":"" это значит что его нет совсем и длина >списка будет меньше. И при поступлении данных надо разбираться все ли есть >и если нет то чего именно.
Как это мешает сразу писать в файл?


 
stas ©   (2013-09-17 13:55) [52]

Пришли данные, разобрали что есть, чего нет и записали этот кусок.


 
_guest_   (2013-09-17 13:56) [53]

Ну хорошо-хорошо, но я так и не услышал чем на малом объеме поток лучше списка.

> stas ©   (17.09.13 13:47) [49]

Я понимаю, что лень это плохо, но вот вместо всего, что Вы написали в [49], я пишу просто HttpGetText с похожим результатом и все. Да мне после этого проще .Text в поток загнать. Еще раз: объясните чем список строк/строка хуже потока на 5000 символов.


 
_guest_   (2013-09-17 13:58) [54]


> stas ©   (17.09.13 13:55) [52]

Так я так и делаю. Только в списке. Зачем нужна база или поток?
Я не успеваю уже читать посты и отвечаю невпопад, прервемся, а?


 
Плохиш ©   (2013-09-17 14:00) [55]


> _guest_   (17.09.13 13:45) [48]

Можно увидеть пару примеров входных данных?


 
DVM ©   (2013-09-17 14:03) [56]


> _guest_   (17.09.13 13:56) [53]
> Ну хорошо-хорошо, но я так и не услышал чем на малом объеме
> поток лучше списка.

Какой такой функционал TStringList используется, чтобы непременно использовать именно его? Никакой, если переводы строк могут и отсутствовать.
С тем же успехом можно было взять все что угодно.


 
_guest_   (2013-09-17 16:19) [57]


> 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 и уже можно парсить или не парсить. А в потоке? Уже есть такое или придется все заново писать?


 
Плохиш ©   (2013-09-17 18:04) [58]

Что надо делать с отсутствующими полями?


 
DVM ©   (2013-09-17 22:21) [59]


> _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 парсер вернет тебе набор объектов, которые ты уже можешь обрабатывать как тебе вздумается.


 
_guest_   (2013-09-18 08:44) [60]


> Плохиш ©   (17.09.13 18:04) [58]

Ничего, на месте пустого поля пропуск, разделитель и поехали дальше. Просто у разных объектов могут отсутствовать разные поля. Поэтому общую структуру надо или считывать после загрузки всех данных или создавать в процессе загрузки, правда при этом связанные по смыслу поля могут разъехаться друг от друга, плюс структура в выходных файлах в этом случае будет варьироваться и как то придется их потом склеивать, очевидно за два прохода.

> DVM ©   (17.09.13 22:21) [59]

Вот. Аргументированный ответ. Блестяще и убедительно. И если бы мне удалось подобрать openssl к тому indy что в 2007-й на работе, я прямо сейчас бы стал переделывать. А так придется ждать до вечера.
А насчет парсера, никакой кустарщины не будет. Я прямо сейчас не гоню данные на выход, только оцениваю их количество и качество. Т.е. вполне возможна ситуация, что я выдам не программу, а вывод, что данных на сайте недостаточно и программа не нужна. И только поэтому на этапе оценки использую такую ерунду. И да, лишние или недостающие пробелы, прямые и обратные слеши в данных - все это встречается. Я пока просто отсекаю - полпроцента потерь пока несущественны. Все что не прошло входной контроль - в отдельный файл, и потом буду разбираться с этим.
Спасибо за подсказки, сейчас поищу парсер, работающий с потоком.


 
_guest_   (2013-09-18 08:50) [61]

ЗЗЫ. Вот сейчас, когда Вы меня замотивировали, я обнаружил, что и synapse может вернуть поток, так что все упрощается, дело за парсером.


 
stas ©   (2013-09-18 09:33) [62]

_guest_   (18.09.13 08:50) [61]
А если поток сделаете TFileStream, то будет напрямую писаться на диск, только не понятно как парсер будет работать, забирать все в ОЗУ или частями.

Я так и не понял, Вам надо все выкачать, а потом обработать или получил часть обработал, сохранил ?


 
_guest_   (2013-09-18 09:55) [63]


> stas ©   (18.09.13 09:33) [62]
> Я так и не понял, Вам надо все выкачать, а потом обработать
> или получил часть обработал, сохранил ?

На конечный результат последовательность действий не влияет, можно и так и этак. Как я получаю данные, я писал уже несколько раз, повторюсь: данные получаю в виде небольших законченных json-объектов, пример в [57]. И, имхо, нет особой разницы все ли выкачать и сохранить, а потом обрабатывать и сохранять снова или же получил-обработал-сохранил, за исключением того, что во втором случае исключается промежуточная запись/чтение, но повторюсь: на сам результат это не влияет. Не надо кидать в меня камнями за первый вариант. Объясняю: данные нужны все или не нужны вовсе. Поэтому если я скачал и обработал 98% информации, значит я проделал лишнюю (в основном по времени) работу. А если я скачал, увидел, что 2% не хватает, то я могу и не обрабатывать. По-хорошему, надо реализовывать оба варианта и давать оператору выбор, чтобы он поработав на реальных данных смог определится, каким способом он хочет пользоваться.


 
stas ©   (2013-09-18 10:14) [64]

_guest_   (18.09.13 09:55) [63]

т.е. вопрос о том что не получается сохранить большой кусок текста отпадает, т.к. можно сохранять кусками по ходу? или нет? )


 
stas ©   (2013-09-18 10:18) [65]

по поводу 98%, я к тому что, допустим качали качали, вырубили электричество, но 98% на диске закачаны, и теперь не качаем все заново, а делаем докачку 2%, но тут надо запоминать точку остановки,и докачать.
Правда не знаю все сервера это могут делать или нет.


 
Плохиш ©   (2013-09-18 10:32) [66]


> _guest_   (18.09.13 08:44) [60]
>
> > Плохиш ©   (17.09.13 18:04) [58]
>
> Ничего, на месте пустого поля пропуск, разделитель и поехали
> дальше.

Т.е. структура известна. Тогда совершенно не понятна проблема. Загружаешь данные, парсируешь, сохраняешь. Никаких гигабайтов в памяти. Открою страшную тайну, даже в стандартный Text можно дописывать данные.


 
_guest_   (2013-09-18 10:35) [67]


> stas ©   (18.09.13 10:14) [64]

Он отпал, начиная с [10], но все что было дальше - было крайне полезным для меня.

> stas ©   (18.09.13 10:18) [65]

Речь не идет о выкачанных процентах, я всегда могу продолжить с любого места, так как это происходит в режиме запрос-ответ и запрос посылаю я. Речь о том, что у меня есть некий эталон по количеству данных - общее количество участков. И если на сайте их значительно меньше, то они не могут использоваться при анализе.


 
DVM ©   (2013-09-18 10:36) [68]


> _guest_   (18.09.13 08:44) [60]


> Спасибо за подсказки, сейчас поищу парсер, работающий с
> потоком.

Delphi SuperObject лучший имхо: https://code.google.com/p/superobject/


 
_guest_   (2013-09-18 10:46) [69]


> Плохиш ©   (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 13:30) [70]

Кстати, по поводу SSL/TLS. Недавно обнаружил, что всем давно известная библиотека Delphi Fundamentals весьма сильно преобразилась в лучшую сторону и обрела поддержку SSL/TLS (причем нативную, без сторонних dll!). JSON парсер там тоже имеется. Можно ее попробовать. SSL я проверял - отлично работает: http://sourceforge.net/p/fundementals/code/HEAD/tree/trunk/


 
_guest_   (2013-09-18 15:37) [71]


> DVM ©   (18.09.13 13:30) [70]

Спасибо, возьму на заметку. Но время, как обычно, поджимает, посмотрю позже.


 
_guest_   (2013-09-19 09:25) [72]

Я извиняюсь, и уж последний вопрос, хотя уже и офтоп. А если данные скармливать парсеру в потоке, как он будет разбираться с кодировкой? Или кодировку править при получении из перечислителя? В случае со строкой - подал на вход нужную кодировку - в ней и получил ответ. А подал я поток и получил нечто, для чего не могу подобрать кодировку ни я, ни онлайн перекодировщики.


 
DVM ©   (2013-09-19 10:58) [73]


> _guest_   (19.09.13 09:25) [72]


> строкой - подал на вход нужную кодировку - в ней и получил
> ответ

Как ты определяешь кодировку JSON данных?


 
_guest_   (2013-09-19 11:39) [74]


> DVM ©   (19.09.13 10:58) [73]

Хороший вопрос...  Когда получил первые данные, вставил в мемо, увидел проблемы, в онлайн-декодере посмотрел исходную кодировку и utf8 в cp1251 тем или и иным способом. Хотя понятно, что тот же браузер кодировку уже знает перед отображением данных, так как кириллица сразу читается нормально.
Попутно, еще вопрос: это, конечно, не принципиально, но после парсинга в перечислителе данные идут в совершенно другом порядке, чем в исходнике. На это можно как-то влиять?


 
DVM ©   (2013-09-19 11:47) [75]


> _guest_   (19.09.13 11:39) [74]

По уму надо делать так (вариант для Indy):

Кодировка возможно указана в HTTP заголовках сервера. У TIdHTTP есть событие OnHeadersAvailable кажется, там ты еще до получения данных в свой стрим сможешь получить имя кодировки. Далее возможны 2 варианта:

1) Получаем данные TStringStream, указывая кодировку для него, далее забираем строку из нее в Unicode и отдаем парсеру. Будет копирование данных, что неизбежно при декодировании.

2) Более сложный. Делаем наследника от TMemoryStream, переопределяем в нем метод Write таким образом, чтобы поток при записи данных в него сразу перекодировал их, используя кодировку переданную ему скажем в конструктор, которую в свою очередь мы получили из HTTP заголовков.
Сложность тут в том, чтобы конвертировать данные, нужно получить их некое минимальное количество, определяемое кодировкой (для UTF8 например один символ может занимать различное число байт).

Это первое что пришло в голову, придумаю еще варианты - напишу.


 
DVM ©   (2013-09-19 11:50) [76]


> Попутно, еще вопрос: это, конечно, не принципиально, но
> после парсинга в перечислителе данные идут в совершенно
> другом порядке, чем в исходнике. На это можно как-то влиять?
>

Зависит от парсера, свой парсер если написать если только.


 
_guest_   (2013-09-19 12:01) [77]


> DVM ©   (19.09.13 11:47) [75]

Ну в целом, понял. Но уж для полной ясности: если данные в потоке приходят не в той кодировке, которую хочется получить при выводе данных, то без строчного преобразования не обойтись? Функции перекодировки ведь только со строками работают? Я заглянул в реализацию методов парсера, но никаких перекодировок там не увидел и поэтому нахожусь в сомнениях, а как же он разделители то узнает. И если все-таки ему все равно с какой кодировкой работать, то может тогда пусть он отработает, а уже те строки, что он возвращает перекодировать куда надо, ведь теоретически перекодируемых данных становится меньше.


 
DVM ©   (2013-09-19 12:10) [78]


> _guest_   (19.09.13 12:01) [77]


>  Я заглянул в реализацию методов парсера, но никаких перекодировок
> там не увидел и поэтому нахожусь в сомнениях, а как же он
> разделители то узнает.

Как правило текстовые данные передаваемые по сети имеют либо однобайтную кодировку, например, cp1251, либо UFT-8. По крайней мере остальное встречается крайне редко. В любом случае символы, которые критичны для парсера, все имеют размер по одному байту. Парсер как правило читает по одному байту и переводит свою машину состояний в нужное состояние, попутно аккумулируя необходимые себе данные во внутренних структурах. Непосредственно на парсинг кодировка в этом случае не влияет. Но может получиться, что строки которые он выдаст перекодировать легко не получится. Вот если бы парсер выдавал строки в RawByteString тогда все было бы проще. Но попробуй.


 
_guest_   (2013-09-19 12:14) [79]


> DVM ©   (19.09.13 12:10) [78]

В очередной раз могу, только поблагодарить всех и особенно Вас.



Страницы: 1 2 вся ветка

Форум: "Начинающим";
Текущий архив: 2014.08.03;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.72 MB
Время: 0.005 c
2-1379581711
Вася
2013-09-19 13:08
2014.08.03
получить по имени переменной ее значение


15-1389385804
Юрий
2014-01-11 00:30
2014.08.03
С днем рождения ! 11 января 2014 суббота


15-1389417411
Viktor Makarov
2014-01-11 09:16
2014.08.03
Помогите пожалуйста написать код для этой задачи)


3-1299221012
Junior
2011-03-04 09:43
2014.08.03
Поиск текста в строках SQL сервера


15-1389558602
Юрий
2014-01-13 00:30
2014.08.03
С днем рождения ! 13 января 2014 понедельник





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский