Имя: Пароль:
1C
1С v8
Обработка 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
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 можно попробовать использовать.
AdBlock убивает бесплатный контент. 1Сергей