|   |   | 
| 
 | Обработка 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 можно попробовать использовать.     | 
| Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |