gifts2017

Чтение больших текстовых файлов (CSV)

Опубликовал v_id (v_id) в раздел Программирование - Практика программирования

Две функции чтения CSV файла и возврата Таблицы Значений с данными файла с использованием COM объекта ADODB.Recordset и внешней компоненты GameWithFire.

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

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

Файлы с кавычкими и вложенными запятым обрабатываются верно. Например файл с содержанием:
клиент;адрес
ИП Иванов А.А.;"Москва;ул.Ленина;53"

вернет ТЗ в 2 колонки

клиент адрес
ИП Иванов А.А. Москва;ул.Ленина;53

 

Спасибо автору данного решения The gray Cardinal.

Публикуется с согласия автора.

Первоисточник и сами функции



Функция ПрочитатьCSV(Папка, ИмяФайла, КолПолей)

   
// Параметры:

    // "Папка" - путь к файлу без имени файла с завершающим слешем,

    // "ИмяФайла" - имя файла,

    // "КолПолей" - количество колонок (число).

    // Функция возвращает ТаблицуЗначений с данными файла.



   
Текст = "[" + ИмяФайла + "]

    |ColNameHeader=False

    |Format=Delimited(;)

    |TextDelimiter=none

    |CharacterSet=ANSI

    |"
;

    Для
ы = 1 По КолПолей Цикл

       
Текст = Текст + "Col" + ы + "=Field" + ы + " Text" + Символы.ПС;

    КонецЦикла;

   
ТекстДок = Новый ТекстовыйДокумент;

   
ТекстДок.УстановитьТекст(Текст);

   
ТекстДок.Записать(Папка + "Schema.ini");



   
objRec = Новый COMОбъект("ADODB.Recordset");

   
strQuery = "SELECT * FROM [" + ИмяФайла + "]";

   
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Папка + ";Extended Properties=""text;""";

   
adOpenStatic = 3;

   
adLockOptimistic = 3;

   
adCmdText = 1;

   
ТаблЗнач = Новый ТаблицаЗначений;

    Для
ы = 1 По КолПолей Цикл

       
ТаблЗнач.Колонки.Добавить();

    КонецЦикла;



   
objRec.Open(strQuery, strConn, adOpenStatic, adLockOptimistic, adCmdText);

   
КолСтрок = objRec.RecordCount;

   
Ном = 1;

    Пока Не
objRec.EOF Цикл

        Если
Ном % 500 = 0 Тогда

           
Состояние(ИмяФайла + " " + Ном + " из " + КолСтрок);

        КонецЕсли;

       
НовСтр = ТаблЗнач.Добавить();

        Для
i=0 По objRec.Fields.Count-1 Цикл

           
НовСтр[i] = Строка(objRec.Fields(i).Value);

        КонецЦикла;

       
objRec.MoveNext();

       
Ном = Ном + 1;

    КонецЦикла;

   
objRec.Close();

    Возврат
ТаблЗнач;

КонецФункции



Функция ПрочитатьCSV_2(Папка, ИмяФайла, КолПолей)

   
// Параметры:

    // "Папка" - путь к файлу без имени файла с завершающим слешем,

    // "ИмяФайла" - имя файла,

    // "КолПолей" - количество колонок (число).

    // Функция возвращает ТаблицуЗначений с данными файла.



   
Текст = "[" + ИмяФайла + "]

    |ColNameHeader=False

    |Format=Delimited(;)

    |TextDelimiter=none

    |CharacterSet=ANSI

    |"
;

    Для
ы = 1 По КолПолей Цикл

       
Текст = Текст + "Col" + ы + "=Field" + ы + " Text" + Символы.ПС;

    КонецЦикла;

   
ТекстДок = Новый ТекстовыйДокумент;

   
ТекстДок.УстановитьТекст(Текст);

   
ТекстДок.Записать(Папка + "Schema.ini");



   
objRec = Новый COMОбъект("ADODB.Recordset");

   
strQuery = "SELECT * FROM [" + ИмяФайла + "]";

   
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Папка + ";Extended Properties=""text;""";

   
adOpenStatic = 3;

   
adLockOptimistic = 3;

   
adCmdText = 1;

   
objRec.Open(strQuery, strConn, adOpenStatic, adLockOptimistic, adCmdText);



   
ПодключитьВнешнююКомпоненту("GameWithFire.ADOUtils");

   
ADOUtils = Новый("AddIn.ADOUtils");

    Возврат
ADOUtils.ADORecordsetToValueTable(objRec);

КонецФункции

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Артур Аюханов (artbear) 18.11.11 11:14
А если внутри поля есть текст с точкой-запятой в кавычках, нормально прочитает?
Например, файл
клиент;адрес
ИП Иванов А.А.;"Москва;ул.Ленина;53"
прочитается верно, как 2 поля?
2. Ийон Тихий (cool.vlad4) 18.11.11 11:36
а как серый кардинал к этому относится, что вы скоммуниздили его функции? ...я помнится еще весной видел эти ф-ции...
3. v_id (v_id) 18.11.11 13:41
(2) cool.vlad4, чукча не читатель...
описание прочти и/или опубликуй что-ть, что пройдет модерацию, потом поговорим.
4. v_id (v_id) 18.11.11 13:43
(1) artbear, на днях специально проверю, в моем случае такого набора данных быть не может
5. Ийон Тихий (cool.vlad4) 18.11.11 13:49
(3) Реагируй адекватно. Написано же
Делюсь результатом моих поисков (абсолютный копи-паст),
вот я и спросил, а The Gray Cardinal дал добро или нет. ...на этом сайте он помоему зарегистрирован.
ЗЫ
описание прочти и/или опубликуй что-ть, что пройдет модерацию, потом поговорим.
и? где в описании есть его разрешение? ф-ции один в один скопированы, есть чем гордится...
6. v_id (v_id) 18.11.11 13:53
(5) cool.vlad4, Публикуется с согласия автора.

Перед тем как пост будет опубликован он проходит модерацию, где админ задает такой же вопрос и получает ответ.

cool.vlad4 пишет:
Реагируй адекватно

Не считай других хуже себя, эталона нравственности.
7. Ийон Тихий (cool.vlad4) 18.11.11 13:58
(6) Я и не считаю, я просто задал вопрос, поскольку есть такая возможность и поскольку бываю на форуме скрипт-кодинга. Ты слишком нервно все воспринимаешь
Зы и почему-то у меня в браузере не было надписи, что публикуется с согласия. Приношу свои извинения.
8. v_id (v_id) 18.11.11 14:04
9. Ийон Тихий (cool.vlad4) 18.11.11 14:05
(1) Обе ф-ции грузят как положено. Проверил,
ЗЫ Только клиент и адрес_ уйдут под название колонок
artbear; v_id; +2 Ответить 1
10. v_id (v_id) 18.11.11 14:13
cool.vlad4 пишет:
ЗЫ Только клиент и адрес_ уйдут под название колонок

ИМХО, так и задумано, для универсальности.

Спасибо, что проверил!
11. Артур Аюханов (artbear) 18.11.11 14:36
(9) Спасибо.
(10) да, это верное поведение.
Рекомендую добавить в описание небольшой коммент насчет кавычек и вложенных точек с запятой, т.к. такие тексты не такая уж редкость :(
12. Ийон Тихий (cool.vlad4) 18.11.11 16:10
А я себе в консоль добавил и немножко видоизменил 1-ую ф-цию:
Если МенеджерВременныхТаблиц = Неопределено Тогда
		Сообщить("Включите использование временных таблиц");
	 Возврат;
    КонецЕсли;
	
	ДиалогВыбора = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    
	ДиалогВыбора.Фильтр     = "Файл csv данных (*.csv)|*.csv";
	ДиалогВыбора.Расширение = "csv";
	
	ДиалогВыбора.Заголовок ="Выберите файлы для загрузки";

	ДиалогВыбора.ПредварительныйПросмотр     = Ложь;
	ДиалогВыбора.ИндексФильтра               = 0;
	ДиалогВыбора.ПроверятьСуществованиеФайла = Ложь;
	ДиалогВыбора.МножественныйВыбор          = Ложь;
	Если ДиалогВыбора.Выбрать() Тогда 
		Файл = Новый Файл(ДиалогВыбора.ПолноеИмяФайла);
		ВремЗапрос = Новый Запрос;
		ВремЗапрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
		ВремЗапрос.Текст =  "ВЫБРАТЬ * ПОМЕСТИТЬ " +  ИмяВремТаблицы + "	
							|ИЗ
							|	&ТЗ как тбл";
		ВремЗапрос.УстановитьПараметр("ТЗ",ЗагрузитьИзCSVвТЗ_1(Файл.Путь, Файл.Имя));
		ВремЗапрос.Выполнить();  		
	КонецЕсли;
	
...Показать Скрыть

// Параметры:
// "Папка" - путь к файлу без имени файла с завершающим слешем,
// "ИмяФайла" - имя файла,
// "КолПолей" - количество колонок (число).
// Функция возвращает ТаблицуЗначений с данными файла         
Функция ЗагрузитьИзCSVвТЗ_1(Папка, ИмяФайла, КолПолей=Неопределено, ИспользоватьСхему=Ложь) Экспорт	//добавить преобразование первой строки - и её загрузку	 
	
Если  ИспользоватьСхему И ЗначениеЗаполнено(КолПолей) Тогда
    Текст = "[" + ИмяФайла + "]

    |ColNameHeader=False

    |Format=Delimited(;)

    |TextDelimiter=none

    |CharacterSet=ANSI

    |";

    Для ы = 1 По КолПолей Цикл

        Текст = Текст + "Col" + ы + "=Field" + ы + " Text" + Символы.ПС;

    КонецЦикла;

    ТекстДок = Новый ТекстовыйДокумент;

    ТекстДок.УстановитьТекст(Текст);

    ТекстДок.Записать(Папка + "Schema.ini");


КонецЕсли;

    objRec = Новый COMОбъект("ADODB.Recordset");

    strQuery = "SELECT * FROM [" + ИмяФайла + "]";

    strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Папка + ";Extended Properties=""text;""";

    adOpenStatic = 3;

    adLockOptimistic = 3;

    adCmdText = 1;

    ТаблЗнач = Новый ТаблицаЗначений;
 	

    objRec.Open(strQuery, strConn, adOpenStatic, adLockOptimistic, adCmdText);

	Для iCount = 0 По objRec.Fields.Count-1 Цикл
	     ТаблЗнач.Колонки.Добавить(objRec.Fields.Item(iCount).Name,АДОвТип(objRec.Fields.Item(iCount).Type)); //по Type можно смотреть тип
    КонецЦикла;

    КолСтрок = objRec.RecordCount;

    Ном = 1;
    Пока Не objRec.EOF Цикл

        Если Ном % 500 = 0 Тогда

            Состояние(ИмяФайла + " " + Ном + " из " + КолСтрок);

        КонецЕсли;

        НовСтр = ТаблЗнач.Добавить();

        Для i=0 По ТаблЗнач.Колонки.Количество()-1 Цикл

            НовСтр[i] = Строка(objRec.Fields(i).Value);

        КонецЦикла;

        objRec.MoveNext();

        Ном = Ном + 1;

    КонецЦикла;

    objRec.Close();

   Возврат ТаблЗнач;
   
КонецФункции
...Показать Скрыть

///На самом деле типов дофига и больше
Функция АДОвТип(type)  Экспорт
	Если type=3 Тогда 
		Возврат Новый ОписаниеТипов("Число",,Новый КвалификаторыЧисла(10)); 
	ИначеЕсли type=5 Тогда
	    Возврат Новый ОписаниеТипов("Число",,Новый КвалификаторыЧисла(15,2)); 
	Иначе
		Возврат Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(256));
	КонецЕсли;
КонецФункции
...Показать Скрыть
13. Артур Аюханов (artbear) 18.11.11 16:46
14. svetlanapk 12.01.12 21:43
Плагиат и есть плагиат, куда смотрят модераторы!!!
15. Доржи Цыденов (support) 12.01.12 21:45
16. Administrator 12.01.12 22:03
17. Доржи Цыденов (support) 12.01.12 22:24
(16) Administrator, так вроде получено разрешение. Хотелось бы конечно, чтобы сам http://infostart.ru/profile/1115/ подтвердил.
18. v_id (v_id) 13.01.12 16:00
(15) support,
(all) думаю, ники svetlanapk, Administrator это клоны пользователя infoooo, который очень любит использовать чужие (и мою, в том числе) обработки в своих сборках, что было неоднократно доказано (ссылку не даю, она забанена).

Думаю администрации нужно повнимательнее отнестись к клонам и накруткам на этом сайте.
19. v_id (v_id) 13.01.12 19:52
(16) Administrator, а ты чтобы не палисться перелогиниться не забывай.
20. Сергей (serggo) 16.04.12 17:18
Народ, а у меня несмотря на файл schema.ini всё равно читает, как будто разделитель - запятые (((( Помогите!!! Что делать?

[Cписок2.txt]
ColNameHeader=True
Format=Delimited(;)
TextDelimiter=none
CharacterSet=ANSI
Col1=Field1 Text
Col2=Field2 Text
Col3=Field3 Text
Col4=Field4 Text
Col5=Field5 Text
Col6=Field6 Text


PS: если кто скажет переименуй в csv - неповерю, проверял. Также смотрел остальные параметры schema.ini -- не помогло (((
21. Александр Лапшин (zfilin) 18.07.12 22:27
(20) В коде есть небольшая неточность. Из-за того, что по-умолчанию метод "Записать" объекта "ТекстовыйДокумент" сохраняет в кодировке UTF8 (см. синтакс-помощник), в файле Schema.ini в начале появляются лишние символы, которые обычно не видны в просмотрщике. И кажется, что с файлом все в порядке.

На самом деле строчка

ТекстДок.Записать(Папка + "Schema.ini");

должна выглядеть так:

ТекстДок.Записать(Папка + "Schema.ini", КодировкаТекста.ANSI);

Так все работает.
ZOMI; Myskyl; +2 Ответить 1
22. Юрий Осипов (yuraos) 11.02.13 09:51
Для работы с ADO использую эту подсистему
Прочитал про GameWithFire.dll и обрадовался, щас ускорю выгрузку ADORecordset в ТЗ.
Но обнаружилось, что на сервере (где мне это особенно интересно сделать)
подключить ВК невозможно (ограничение платформы как под 8.1, так и под 8.2, у меня - 8.1).

Не знаете, как можно обойти это ограничение ???
23. Александр Лобачёв (SANILLA) 29.09.13 22:24
оооо спасибо, искал, кажется то что надо
24. S.A.N.I.L.L.A (Myskyl) 04.10.13 20:32
(21) zfilin, Благодарю за подсказку
ТекстДок.Записать(Папка + "Schema.ini", КодировкаТекста.ANSI);
так действительно лучше выглядит.
25. Xer shi (Xershi) 20.10.15 16:35
Что-то у меня не читает файл. Коллекция с пустыми ячейками.
Но у меня разделитель ",".
//|Format=Delimited(;)
	|Format=Delimited(,)

Не помогло.
26. Xer shi (Xershi) 21.10.15 12:52
Похоже проблема в том что файл содержит для каждой колонки обертку "". Так еще в самих ячейках есть разделитель. Придется писать свой парсер.
27. Yuri_V _____ (yur4ik9408) 30.06.16 11:34
а как на счет больших файлов, у которых больше 255 колонок?
кто-то сталкивался с данной проблемой?
28. Xer shi (Xershi) 30.06.16 13:04
(27) yur4ik9408, у моего парсера количество колонок роли не играет, вопрос только в стандарте и размере самого файла.
29. Yuri_V _____ (yur4ik9408) 30.06.16 18:38
(28) Xershi, А где можно посмотреть на ваш парсер?
30. Xer shi (Xershi) 30.06.16 19:34
31. Николай ~ ~ (kuzyara) 22.08.16 15:48
Для небольших файлов можно использовать такой код.