Есть файл CSV. Сделал внешний отчет который формируется по этому файлу. В начале сделал через ТекстовыйДокумент. Но после столкнулся с проблемой производительности. Из за того что размер файла больше 30мб решил доработать чтение csv через ado. Но столкнулся с проблемой. Проблема заключается в том что я не могу получить коллекцию колонок из за специфичного содержания файла. Первые две строки содержат разделитель колонок.
Как можно пропустить в ado эти колонки что бы начать чтение строки с 3-й строки?
Код чтения:
Содержание файл:
"sep" - это символ разделителя
Как можно пропустить в ado эти колонки что бы начать чтение строки с 3-й строки?
Код чтения:
Для Каждого Строкамассива из МассивАдресов Цикл
УдалитьФайлы(ВременныйКаталог, "*");
// Временный файл
id = id+1;
ФайлИмя = "КК" + Строка(id) + ".csv";
Путь = ВременныйКаталог + ФайлИмя;//ПолучитьИмявременногоФайла(".csv");
Файл = ПолучитьИзВременногоХранилища(Строкамассива);
Файл.Записать(Путь);
Сon nectionString = "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq="+ВременныйКаталог+";Extensions=asc,csv,tab,txt;";
Попытка
// Инициализация основного объекта ADODB.Connection. Открытие соединения.
ADODBConnection = Новый COMОбъект("ADODB.Connection");
ADODBConnection.ConnectionString = СonnectionString;
ADODBConnection.Open();
// Импирически определенный параметр для правильного определения количества строк листа.
ADODBConnection.CursorLocation = 3; // По-умолчанию 2.
Исключение
Сообщить(НСтр("ru = '"+ОписаниеОшибки()+"'"), СтатусСообщения.Внимание);
Возврат Новый ТаблицаЗначений; // В случае ошибки возвращаем пустую таблицу значений.
КонецПопытки;
ТекстЗапроса = "SEL ECT * FR OM ["+ФайлИмя+"]";
// Создание Recordset. Дочерний объект ADODBConnection. Набор записей по запросу.
Попытка
ADODBRecordset = Новый COMОбъект("ADODB.Recordset");
ADODBRecordset.Open(ТекстЗапроса, ADODBConnection);
ADODBRecordset.MoveNext();
ADODBRecordset.MoveNext();
// Проверка заполненности листа.
Если (ADODBRecordset.EOF ИЛИ ADODBRecordset.BOF) Тогда
КолвоСтрокExcel = 0;
//Сообщить(НСтр("ru = '" + ИмяЛиста + ": не содержит данных.'"), СтатусСообщения.Внимание);
// Завершение работы.
// Закрытие Объектов.
ADODBRecordset.Close();
ADODBConnection.Close();
ADODBRecordset = Неопределено;
ADODBConnection = Неопределено;
Возврат Новый ТаблицаЗначений; // В случае ошибки возвращаем пустую таблицу значений.
КонецЕсли;
// Импирически определенные параметры для правильного определения количества строк листа.
ADODBRecordset.AbsolutePage = 1;
ADODBRecordset.AbsolutePosition = 1;
Исключение
Сообщить(НСтр("ru = '"+ОписаниеОшибки()+"'"), СтатусСообщения.Внимание);
Возврат Новый ТаблицаЗначений; // В случае ошибки возвращаем пустую таблицу значений.
КонецПопытки;
// Параметр, возвращаемый в вызывающую процедуру.
КолвоСтрокExcel = ADODBRecordset.RecordCount + 1; // (+1) - учет Строки-Заголовока, которая "съедается".
КолвоКолонокExcel = ADODBRecordset.Fields.Count;
КонецЦикла;
ПоказатьСодержание файл:
"sep="
" "" "
Колонка1Колонка2Колонка3Колонка4
" "" "
Колонка1Колонка2Колонка3Колонка4
"sep" - это символ разделителя
По теме из базы знаний
Найденные решения
Ну и все равно переделай чтение через ТекстовыйДокумент на через ЧтениеТекста, как я выше писал.
ТекстовыйДокумент заточен на произвольный доступ в памяти для небольших файликов и нелинейно тормозит на больших объемах.
А ЧтениеТекста - человеческое последовательное чтение из файла, производительность которого зависит от размеров файла исключительно линейно.
ТекстовыйДокумент заточен на произвольный доступ в памяти для небольших файликов и нелинейно тормозит на больших объемах.
А ЧтениеТекста - человеческое последовательное чтение из файла, производительность которого зависит от размеров файла исключительно линейно.
(86) Это на тестовом файле проблема производительности не в этом. Но он же и файлы побольше собирался грузить. Поэтому эта оптимизация в любом случае будет не лишней, о чем я и написал. Это даже не оптимизация. Это просто использование надлежащего инструмента. А для оптимизации производительности на тестовом файле я еще в (38) соглашался, что необходимо оптимизировать преобразование типов.
Остальные ответы
Подписаться на ответы
Инфостарт бот
Сортировка:
Древо развёрнутое
Свернуть все
(16)
Для Каждого Строкамассива из МассивАдресов Цикл
// Временный файл
Путь = ПолучитьИмявременногоФайла(".csv");
Файл = ПолучитьИзВременногоХранилища(Строкамассива);
Файл.Записать(Путь);
Разделитель = Символ("01");//",";
ИмяФайла = Путь;
// чтение файла
ЗагружаемыйФайл = Новый ТекстовыйДокумент;
ЗагружаемыйФайл.Прочитать(ИмяФайла, КодировкаТекста.ANSI);
//шапка по умолчанию 1 строка, из первой строки делаем колонки таблицы
Шапка = ЗагружаемыйФайл.ПолучитьСтроку(3);
//раскладываем строку в массив
МассивКолонок = РазложитьСтрокуВМассивПодстрок(Шапка,Разделитель);
//генерируем колонки
Для Каждого ИмяКолонки Из МассивКолонок Цикл
ИмяБезПробелов = СтрЗаменить(ИмяКолонки," ",""); // убираем из имени колонок пробелы
Str1 = ИмяБезПробелов;
ИмяБезПробелов = RegExp.Replace(Str1, "");
ИмяБезПробелов = ИсправлениеЛатиницыНаКирилицу(ИмяБезПробелов);
Если ТаблицаЗаполнения.Колонки.Найти(ИмяБезПробелов) = Неопределено Тогда
Попытка
Заголовок = ИсправлениеЛатиницыНаКирилицу(ИмяКолонки);
Имя = ИмяБезПробелов;
ТипЗначения = УстановитьТипКолонки(ИмяБезПробелов);
ТаблицаЗаполнения.Колонки.Добавить(Имя, ТипЗначения, Заголовок);
Исключение
сообщить(Имяколонки) ;
сообщить(ИмяБезПробелов) ;
Продолжить
Конецпопытки;
КонецЕсли;
КонецЦикла;
КоличествоСтрок = ЗагружаемыйФайл.КоличествоСтрок();
Для НомерСтроки=4 по КоличествоСтрок Цикл
//Состояние("Чтение файла отчета " + Строка(НомерСтроки) + " из " + Строка(ЗагружаемыйФайл.КоличествоСтрок()));
// получить строку файла с указанным номером и преобразуем её в массив
Строка = ЗагружаемыйФайл.ПолучитьСтроку(НомерСтроки);
МассивКолонок = РазложитьСтрокуВМассивПодстрок(Строка,Разделитель);
НоваяСтрока = ТаблицаЗаполнения.Добавить();
Если МассивКолонок.Количество() <> ТаблицаЗаполнения.Колонки.Количество() Тогда
//Сообщить("Ошибка со строкой " + Строка);
Продолжить; // скорее всего в тексте содержит разделитель
КонецЕсли;
Для НомерКолонки = 1 по МассивКолонок.Количество() Цикл
//заполняем строку значениями
ТекущееЗначение = СокрЛП(МассивКолонок[НомерКолонки-1]);
ИмяКолонки = ТаблицаЗаполнения.Колонки[НомерКолонки-1].Имя;
НоваяСтрока[ИмяКолонки] = ПривестиЗначениекТипу(ТекущееЗначение, ИмяКолонки);
КонецЦикла;
Процент = Цел(НомерСтроки/КоличествоСтрок*100);
КонецЦикла;
КонецЦикла;
Показать
(27)
кастыли
кастыли
Функция ПривестиЗначениекТипу(ТекущееЗначение, ИмяКолонки)
ТипКолонки = УстановитьТипКолонки(ИмяКолонки);
Если ТипКолонки.СодержитТип(Тип("Дата")) Тогда
Возврат ПолучитьДатуИзСтроки(ТекущееЗначение);
ИначеЕсли ТипКолонки.СодержитТип(Тип("Число")) Тогда
Возврат Число(ТекущееЗначение)
Иначе
Возврат ТекущееЗначение
КонецЕсли;
КонецФункции
Показать
(30)
Функция ПривестиЗначениекТипу(ТекущееЗначение, ИмяКолонки)
ТипКолонки = УстановитьТипКолонки(ИмяКолонки);
Если ТипКолонки.СодержитТип(Тип("Дата")) Тогда
Возврат ПолучитьДатуИзСтроки(ТекущееЗначение);
ИначеЕсли ТипКолонки.СодержитТип(Тип("Число")) Тогда
Возврат Число(ТекущееЗначение)
Иначе
Возврат ТекущееЗначение
КонецЕсли;
КонецФункции
&НаСервере
Функция УстановитьТипКолонки(ИмяКолонки)
Если Найти(НРег(ИмяКолонки), "сумма") <> 0
ИЛИ Найти(НРег(ИмяКолонки), "стоимо") <> 0 Тогда
Возврат ПолучитьОписаниеТиповЧисла(18,2);
ИначеЕсли Найти(НРег(ИмяКолонки), "дата") <> 0 Тогда
Возврат ПолучитьОписаниеТиповДаты(ЧастиДаты.Дата);
Иначе
Возврат ПолучитьОписаниеТиповСтроки(300)
Конецесли;
КонецФункции
Показать
(39) Лично я вообще не понимаю, для чего внутри ПривестиЗначениекТипу() опять использовать УстановитьТипКолонки(). Внутренностей УстановитьТипКолонки() мы, похоже так и не увидим и именно в ней каким-то чудесным образом происходит определение типа значения, когда тип этого значения должен быть жестко задан для каждой колонки еще на этапе проектирования/формирования файла *.csv.
(44)
1. Получаем из строки список колонок
2. Раскладываем в массив подстрок
3. Приводим колонку к нужному типу при помощи УстановитьТипКолонки()
4. После сформированной но пустой таблицы заполняем значениями
5. раз у нас уже есть описание типов в колонке приводим значение к нужному типу ПривестиЗначениекТипу()
1. Получаем из строки список колонок
2. Раскладываем в массив подстрок
3. Приводим колонку к нужному типу при помощи УстановитьТипКолонки()
4. После сформированной но пустой таблицы заполняем значениями
5. раз у нас уже есть описание типов в колонке приводим значение к нужному типу ПривестиЗначениекТипу()
(58)
УстановитьТипКолонки
&НаСервере
Функция УстановитьТипКолонки(ИмяКолонки)
Если Найти(НРег(ИмяКолонки), "сумма") <> 0
ИЛИ Найти(НРег(ИмяКолонки), "стоимо") <> 0 Тогда
Возврат ПолучитьОписаниеТиповЧисла(18,2);
ИначеЕсли Найти(НРег(ИмяКолонки), "дата") <> 0 Тогда
Возврат ПолучитьОписаниеТиповДаты(ЧастиДаты.Дата);
Иначе
Возврат ПолучитьОписаниеТиповСтроки(300)
Конецесли;
КонецФункции
Показать
(67)ну хорошо, разное количество колонок в разных файлах.
Уберите вы УстановитьТипКолонки() из ПривестиЗначениекТипу(ТекущееЗначение, ИмяКолонки),
в качестве второго параметра передавайте ТипЗначения к которому нужно приводить, используя тип значения колонки ТЗ.
Приводить строку нужно к дате, число само из строки приведется.
Вот строку из числа необходимо преобразовывать, если разделители разрядов ненужны(а они по-хорошему не нужны).
Уберите вы УстановитьТипКолонки() из ПривестиЗначениекТипу(ТекущееЗначение, ИмяКолонки),
в качестве второго параметра передавайте ТипЗначения к которому нужно приводить, используя тип значения колонки ТЗ.
Приводить строку нужно к дате, число само из строки приведется.
Вот строку из числа необходимо преобразовывать, если разделители разрядов ненужны(а они по-хорошему не нужны).
(78)
С начало сделайте замер и проверьте что в этой функции выполняется долго, поиск через "Найти" или "ПолучитьОписаниеТипов".
Как минимум описание типов можно оптимизировать тем что каждый раз вы не получаете значение, а получаете все три типа до начала обхода столбцов и строк и потом просто подставляете нужный.
Может конечно ошибаюсь, но "ПолучениеОписанияТипов" для каждой строки делать не надо.
ясно, буду оптимизировать это
С начало сделайте замер и проверьте что в этой функции выполняется долго, поиск через "Найти" или "ПолучитьОписаниеТипов".
Как минимум описание типов можно оптимизировать тем что каждый раз вы не получаете значение, а получаете все три типа до начала обхода столбцов и строк и потом просто подставляете нужный.
Может конечно ошибаюсь, но "ПолучениеОписанияТипов" для каждой строки делать не надо.
как-то так
НомерТекущейСтроки = 1;
Пока ADODBRecordset.EOF() = 0 Цикл
НомерТекущейСтроки = НомерТекущейСтроки + 1;
Если НомерТекущейСтроки < 4 Тогда // пропускаем первые 3 строки
ADODBRecordset.MoveNext();
Продолжить;
КонецЕсли;
// продолжаем чтение данных с 4-ой строки
Показать
(3)EOF() - возвращает истину, если текущая позиция записи после последней записи, в противном случае ложь
попробуйте через
Пока НЕ ADODBRecordset.EOF() Цикл
еще можно проверить сколько всего записей в данных и сделать цикл по найденному числу
RecordCount() - возвращает количество записей в объекте Recordset
попробуйте через
Пока НЕ ADODBRecordset.EOF() Цикл
еще можно проверить сколько всего записей в данных и сделать цикл по найденному числу
RecordCount() - возвращает количество записей в объекте Recordset
(37) Не, я просто про соответствие реальности результатам замера. Если так и было, тогда явных узких мест нет. Просто накладные расходы на преобразование типов для большого количества строк и колонок. Но ADO же тоже строки вернет и нужно будет делать те же самые преобразования? Тогда где ожидаемый выигрыш? Тогда оптимизировать надо не метод чтения, а способ преобразования типов.
(38)
надеялся на ускорить заполнение ТЗ ускорить. В теории ADO могло помочь. Но пока застрял.
Не, я просто про соответствие реальности результатам замера. Если так и было, тогда явных узких мест нет. Просто накладные расходы на преобразование типов для большого количества строк и колонок. Но ADO же тоже строки вернет и нужно будет делать те же самые преобразования? Тогда где ожидаемый выигрыш?
надеялся на ускорить заполнение ТЗ ускорить. В теории ADO могло помочь. Но пока застрял.
Если Вам передают даже символ разделителя, значит, содержание и формат файла обмена КАК-ТО, КЕМ-ТО определен? Или нет? Если да, создайте в начале процедуры ТЗ с нужными типами колонок и не тратьте время на типизацию для каждой строки
(60)
Определен налоговой, литература отсутствует. Приходится придумывать велосипед
Если Вам передают даже символ разделителя, значит, содержание и формат файла обмена КАК-ТО, КЕМ-ТО определен? Или нет? Если да, создайте в начале процедуры ТЗ с нужными типами колонок и не тратьте время на типизацию для каждой строки
Определен налоговой, литература отсутствует. Приходится придумывать велосипед
Ну и все равно переделай чтение через ТекстовыйДокумент на через ЧтениеТекста, как я выше писал.
ТекстовыйДокумент заточен на произвольный доступ в памяти для небольших файликов и нелинейно тормозит на больших объемах.
А ЧтениеТекста - человеческое последовательное чтение из файла, производительность которого зависит от размеров файла исключительно линейно.
ТекстовыйДокумент заточен на произвольный доступ в памяти для небольших файликов и нелинейно тормозит на больших объемах.
А ЧтениеТекста - человеческое последовательное чтение из файла, производительность которого зависит от размеров файла исключительно линейно.
(87)
87. nomad_irk 49 28.09.20 14:48 Сейчас в теме
(86)про ЧтениеТекста вместо ТекстовыйДокумент: в текстовый документ ты большой файл можешь и не загрузить, т.к. закончится ОЗУ, а ЧтениеТекста спокойно прочитает весь текст.
Уже переписал. Благо там все просто. Скорости не то что бы много прибавило, но нагрузка с сервера упала значительно.
87. nomad_irk 49 28.09.20 14:48 Сейчас в теме
(86)про ЧтениеТекста вместо ТекстовыйДокумент: в текстовый документ ты большой файл можешь и не загрузить, т.к. закончится ОЗУ, а ЧтениеТекста спокойно прочитает весь текст.
Уже переписал. Благо там все просто. Скорости не то что бы много прибавило, но нагрузка с сервера упала значительно.
(86) Это на тестовом файле проблема производительности не в этом. Но он же и файлы побольше собирался грузить. Поэтому эта оптимизация в любом случае будет не лишней, о чем я и написал. Это даже не оптимизация. Это просто использование надлежащего инструмента. А для оптимизации производительности на тестовом файле я еще в (38) соглашался, что необходимо оптимизировать преобразование типов.
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот