|
Обработка csv файла около 300 000 строк. | ☑ | ||
---|---|---|---|---|
0
Prilepsky
23.11.11
✎
01:39
|
Подскажите, как быстрей всего обработать такое количество строк?
|
|||
1
Живой Ископаемый
23.11.11
✎
01:45
|
что такое обработать?
|
|||
2
Prilepsky
23.11.11
✎
01:48
|
Записать, допустим, в табличную часть документа или перебрать и по каждой строке сделать запись в регистре сведений.
|
|||
3
Злопчинский
23.11.11
✎
04:16
|
а в чем принципиальная проблема?
|
|||
4
Kassius
23.11.11
✎
04:35
|
Нужно сразу понять, такой массив нужно постоянно обрабатывать или загрузить и забыть?
|
|||
5
Prilepsky
23.11.11
✎
04:55
|
Проблема, что перебором строк - очень долго.
Пробовал через АДО но видимо где-то накосячил и у меня грузилось только первые 4000 строк. (4) Периодически придется загружать подобные массивы. Если это было разовая операция, я бы и часик подождал , пока построчно все переберется =) |
|||
6
big
23.11.11
✎
04:58
|
Файлы 2-4 Гб (большего размера просто не было ещё) прекрасно обрабатываются перебором строк. Причём не важно снеговик это или клюшки.
|
|||
7
МихаилМ
23.11.11
✎
05:05
|
как раз для этого (обработка рекордсетов адо )
первоначально и создавался энтерпрайз интегратор http://main.1c-ei.ru/ |
|||
8
Prilepsky
23.11.11
✎
05:11
|
(6) Не подскажешь как ты это реализовал?
Я перебирал вот так: Текст = Новый ТекстовыйДокумент; Текст.Прочитать(Файл); Для НомерСтроки = 1 По Текст.КоличествоСтрок() Цикл Если НомерСтроки = 1 Тогда Продолжить КонецЕсли;//игнорировать шапку таблицы Стр = Текст.ПолучитьСтроку(НомерСтроки); Стр = СтрЗаменить(Стр, ";", Символы.ПС); |
|||
9
Prilepsky
23.11.11
✎
05:15
|
А вот такой код с АДО:
//ЗаголовкиВСтроке1 = "HDR=YES;" ЗаголовкиВСтроке1 = "HDR=NO;"; СтрокаСоединения ="Provider=Microsoft.Jet.OLEDB.4.0;Data Source= " + СокрЛП(пФайл) +";Extended Properties=""Excel 8.0;" + ЗаголовкиВСтроке1 + "IMEX=1;"""; Connection = Новый COMОбъект("ADODB.Connection"); Connection.ConnectionString = СтрокаСоединения; Попытка Connection.Open(); Исключение Сообщить (ОписаниеОшибки() ); Возврат Неопределено; КонецПопытки; RS = Новый COMОбъект("ADODB.Recordset"); ТекстЗапроса = "SELECT | Лист.* |FROM | [" + пЛист + "$] as Лист"; Попытка RS.Open(ТекстЗапроса, Connection); Исключение Сообщить ("Проблемы с выполнением запроса"); Возврат Неопределено; КонецПопытки; Таблица = Новый ТаблицаЗначений; Если СтруктураКолонок = Неопределено Тогда Для Счетчик = 1 По RS.Fields.Count Цикл Поле = RS.Fields.Item(Счетчик - 1); Колонка = Таблица.Колонки.Добавить("К" + Счетчик, , Поле.Name); КонецЦикла; Иначе Для каждого КлючИЗначение Из СтруктураКолонок Цикл Колонка = Таблица.Колонки.Добавить(КлючИЗначение.Ключ); КонецЦикла; КонецЕсли; НомерСтроки = 0; КолвоСтрок = RS.RecordCount; n=0; Пока RS.EOF() = 0 Цикл n=n+1; НомерСтроки = НомерСтроки + 1; #Если Клиент Тогда Состояние("Чтение файла: " + Формат(НомерСтроки) + " из " + Формат(КолвоСтрок)); ОбработкаПрерыванияПользователя(); #КонецЕсли Если НомерСтроки < НачСтрока Тогда RS.MoveNext(); Продолжить; КонецЕсли; Если КонСтрока > 0 И НомерСтроки > КонСтрока Тогда Прервать; КонецЕсли; НоваяСтрока = Таблица.Добавить(); Если СтруктураКолонок = Неопределено Тогда Для Счетчик = 1 По RS.Fields.Count Цикл Поле = RS.Fields.Item(Счетчик - 1); НоваяСтрока["К" + Счетчик] = Поле.Value; КонецЦикла; Иначе Для каждого КлючИЗначение Из СтруктураКолонок Цикл Поле = RS.Fields.Item(КлючИЗначение.Значение - 1); НоваяСтрока[КлючИЗначение.Ключ] = Поле.Value; КонецЦикла; КонецЕсли; // Обработка других полей RS.MoveNext(); КонецЦикла; // Завершение работы RS.Close(); Connection.Close(); Возврат Таблица; Возвращает таблицу с 3 тысячами строк (И понятие не имею, почему так) |
|||
10
big
23.11.11
✎
05:20
|
(8) Я через FileSystemObject делаю.
(9) Как вариант - м.б. в строке недопустимые для АДО символы есть? Бывает, что в текстовый реквизит скопипастят вместе с текстом ПС+ВК и выборка сбивается |
|||
11
Prilepsky
23.11.11
✎
05:47
|
(10) Файл генерируется автоматически, поэтому навряд ли именно на этой строке какой-то символ вылезает..
|
|||
12
skunk
23.11.11
✎
05:53
|
(10)это какие такие символы
|
|||
13
big
23.11.11
✎
06:00
|
(12) я предположил, что ВК+ПС может мешать.
|
|||
14
Prilepsky
23.11.11
✎
06:01
|
(10) Через FileSystemObject так ?
fso= Новый COMОбъект("Scripting.FileSystemObject"); file=fso.OpenTextFile(файл, 1, 0, 0); //Открываем файл в режиме "только чтение" n=0; Пока file.AtEndOfStream=0 Цикл n=n+1; стр=file.ReadLine(); Состояние("Обработка строки файла : строка " + n); КонецЦикла; file.Close(); Не быстрее первого метода, который я написал. |
|||
15
big
23.11.11
✎
06:10
|
(14) Да ладно - медленнее. :) На старом П-4 файл 4 Гб разбирается в течение 40-50 минут. Причем посимвольно строка перебирается.
|
|||
16
Prilepsky
23.11.11
✎
06:26
|
Точно такой же код у тебя разбирает 4 гб за 40-50 минут?
Ппц, у меня этот код разбирает 33 мб столько же... А комп не из слабых. |
|||
17
big
23.11.11
✎
06:31
|
вместо OpenTextFile используй OpenAsTextStream
|
|||
18
kosts
23.11.11
✎
06:32
|
(8) Думаю этот код изначально неподходящий для больших файлов.
Вот глянь: ЧтениеТекста (TextReader) Методы: Закрыть (Close) Открыть (Open) Прочитать (Read) ПрочитатьСтроку (ReadLine) Конструкторы: По имени файла Формирование неинициализированного объекта Описание: Предназначен для последовательного чтения текстовых файлов (большой длины). Доступность: Тонкий клиент, сервер, толстый клиент, внешнее соединение. Пример: Текст = Новый ЧтениеТекста("d:\win.txt", КодировкаТекста.ANSI); Стр = Текст.ПрочитатьСтроку(); Пока Стр <> Неопределено Цикл // строки читаются до символа перевода строки Сообщить(Стр); Стр = Текст.ПрочитатьСтроку(); КонецЦикла; См. также: ЗаписьТекста ЧтениеТекста, конструктор По имени файла |
|||
19
Prilepsky
23.11.11
✎
06:55
|
(17) Вроде бы быстрей...
Сейчас разбираться будет, минут 20. Можно еще как-нибудь ускорить ? А то все равно в отношение 33мб к 4гб - это не круто |
|||
20
kosts
23.11.11
✎
07:00
|
(19) Предполагаю, что основные тормоза в разборе полученной строки.
|
|||
21
Prilepsky
23.11.11
✎
07:04
|
(20) В том то и дело, я не разбираю строку.
Тупо перебираю и вывожу состояние (номер текущей строки). Мне сейчас нужно найти метод, который быстрей всего будет перебирать все строки, а уже потом буду разбирать. |
|||
22
kosts
23.11.11
✎
07:10
|
(21) Ну будут потом...
|
|||
23
Prilepsky
23.11.11
✎
07:13
|
(22) Что будут потом? :)
|
|||
24
kosts
23.11.11
✎
07:18
|
(23) Ну основные тормоза будут именно при разборе строки, т.к. это выполняется на встроенном языке
|
|||
25
marty0701
23.11.11
✎
07:45
|
(0)Вырежи из кода в (14) вывод в цикле и удивись.
|
|||
26
Serginio1
23.11.11
✎
10:43
|
Достаточно быстро обрабатывает
Функция ИзСтрокиСРазделителями(S,Delimiter=",",QuoteChar="""") Экспорт перем aList; ExtractFields(S,aList,Delimiter,QuoteChar); Возврат aList КонецФункции Функция НайтиВПодстроке(Стр1,Поз1,ИскомыйСимвол) Стр=Сред(Стр1,поз1); поз=Найти(Стр,ИскомыйСимвол); Если поз=0 Тогда возврат СтрДлина(стр1)+1 КонецЕсли; Возврат поз1+поз-1 КонецФункции Процедура ExtractFields(S,aList,Delimiter,QuoteChar) FieldStart=0; ScanField=1; ScanQuoted=2; EndQuoted=3; //{initialize by clearing the string list, and // starting in FieldStart state} // Assert(aList <> nil, 'TDExtractFields: list is nil'); aList= новый Массив; if ( (S=неопределено) или (СтрДлина(S) =0 )) Тогда aList.Add(""); return; КонецЕсли; State = FieldStart; // RStringBuilder SB= new RStringBuilder(); SB=""; StartPos=1; EndPos=СтрДлина(S); Inx=1; // {read through all the characters in the string} while (Inx <=EndPos) Цикл // {get the next character} Ch = Сред(S,Inx,1); // {switch processing on the state} Если State =FieldStart Тогда if ( Ch = QuoteChar) Тогда State = ScanQuoted; StartPos=Inx+1; SB=""; Inx=НайтиВПодстроке(S,StartPos,QuoteChar); продолжить; else if ( Ch = Delimiter) Тогда aList.Add(""); else State = ScanField; StartPos=Inx; Inx=НайтиВПодстроке(S,StartPos,Delimiter); продолжить КонецЕсли; КонецЕсли; ИначеЕсли State =ScanField Тогда if ( Ch = Delimiter ) Тогда CopyCount=Inx-StartPos; aList.Add(Сред(S,StartPos,CopyCount)); State = FieldStart; КонецЕсли ИначеЕсли State = ScanQuoted Тогда if ( Ch = QuoteChar) Тогда State = EndQuoted; CopyCount=Inx-StartPos; // SB.Append(S,StartPos,CopyCount); SB=SB+Сред(S,StartPos,CopyCount); КонецЕсли; ИначеЕсли State = EndQuoted Тогда if (Ch = Delimiter) Тогда aList.Add(SB); State = FieldStart; ИначеЕсли (Ch = QuoteChar) Тогда State = ScanQuoted; SB=SB+QuoteChar; StartPos=Inx+1; Inx=НайтиВПодстроке(S,StartPos,QuoteChar); продолжить else ВызватьИсключение("Нет "+Delimiter+ "в позиции ="+Inx ); КонецЕсли; КонецЕсли; Inx=Inx+1; КонецЦикла; // {if we are in the ScanQUoted or GotError state at the end // of the string, there was a problem with a closing quote} if (State = ScanQuoted) Тогда ВызватьИсключение("Нет закрывающей скобки от поз="+Строка(StartPos-1)+ " до конца строки"); КонецЕсли; // {if the current field is not empty, add it to the list} if (State = EndQuoted) Тогда aList.Add(SB); ИначеЕсли (State = ScanField) Тогда CopyCount=Inx-StartPos; aList.Add(Сред(S,StartPos,CopyCount)); КонецЕсли КонецПроцедуры |
|||
27
Sammo
23.11.11
✎
10:51
|
Из встроенных средств - ЧтениеТекста.
Или fso |
|||
28
rutony
23.11.11
✎
11:20
|
(26)
Я юзаю что то похожее, но без контроля данных... 100 000+ строк, 10+ колонок, обрабатывается за 1-2 минуты... Правда винт SSD... На обычном около 10-15 минут... |
|||
29
Serginio1
23.11.11
✎
11:24
|
(28) Ну засосать то в память 100 000 строк это не проблема. У меня таким макаром и по 300 000. Вместе с записью в базу меньше 10 минут. У тебя скорее всего упирается в запись
|
|||
30
Serginio1
23.11.11
✎
11:32
|
(21) Ты состояние выводи через 10000 (Если НомерСтроки % 10000=0 тогда), а то у тебя все время на вывод состояния уходит.
|
|||
31
Prilepsky
23.11.11
✎
11:32
|
(29) у тебя код из (26) за 10 минут записывает в базу 300 000 строк ?
В функцию ИзСтрокиСРазделителями передается S-строка, Delimiter="," - разделитель, QuoteChar="""" - как цитаты выделены? А какой функцией сами строки читаешь ? |
|||
32
Serginio1
23.11.11
✎
11:37
|
По разному. Но насчет 300 000 эт простой ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок. Чере ТабличныйДокумент или чтениеФайла. Второе предпочтительнее. Ав большинстве случаев если файл нормальный гружу его пярмым булк запросом в SQL. У меня пока 13 версия, а в 14 можно вроде и внешние текстовые источники исользовать.
|
|||
33
Serginio1
23.11.11
✎
11:40
|
QuoteChar="""" это разделитель строк. Если в строке будет кавычка то она экранируется кавычкой нпример ЭтоТекст"СкавычкойИ,запятой будет выглядеть как "ЭтоТекст""СкавычкойИ,запятой"
|
|||
34
VVi3ard
23.11.11
✎
11:40
|
Текст = Новый ЧтениеТекста("d:\win.txt", КодировкаТекста.ANSI);
Стр = Текст.ПрочитатьСтроку(); Пока Стр <> Неопределено Цикл Стр = Текст.ПрочитатьСтроку(); КонецЦикла; Сколько у тебя по времени выполняется данный цикл? Должен не больше 2-3 минут, я выгружал недавно в файлы по 3-4 миллиона строк и затем через SQL BulkInsert вставлял их в таблицу на это уходит примерно 15 минут. И это еще с Форматом полей. |
|||
35
Serginio1
23.11.11
✎
11:41
|
Обчно хватает табуляции и ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок. Но нужно следить что бы в строке не было табуляторов
|
|||
36
steep1
23.11.11
✎
11:43
|
||||
37
Serginio1
23.11.11
✎
11:46
|
(34) Все зависит от количества идексов и железа. У меня запись с объединением в темп таблицу миллионную таблицу уходит около минуты. Точно не замерял так как у меня еще присутствует Merge
|
|||
38
Prilepsky
23.11.11
✎
11:48
|
В общем, все читает быстро, если не писать "Состояние("Текущая строка "+n);" =)
Буду копать дальше. Всем спасибо! |
|||
39
VVi3ard
23.11.11
✎
11:48
|
(37) Согласен.
|
|||
40
VVi3ard
23.11.11
✎
11:49
|
(38) :) Что и требовалось доказать.
Чтобы все было корректно вычисляй шаг равный 1% и каждый процент выводи состояние и все будет отлично. |
|||
41
marty0701
23.11.11
✎
13:49
|
(38) Из (25) этого было не понять?
|
|||
42
Snorkler
23.11.11
✎
15:16
|
(0) Может полезно будет:
v8: Чтение больших текстовых файлов (CSV) |
|||
43
Prilepsky
25.11.11
✎
09:05
|
(41) Как только вырезал - понял.
|
|||
44
rs_trade
25.11.11
✎
09:17
|
(0) а там какие значения в полях. ссылочные есть?
|
|||
45
Prilepsky
25.11.11
✎
09:42
|
(44) нету
|
|||
46
rs_trade
25.11.11
✎
11:06
|
(45) bulk insert можно попробовать использовать.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |