gifts2017

1С 8: Работаем с файлами MS Excel, используя OpenOffice/LibreOffice

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

Работа через COM с файлами MS Excel, используя OpenOffice/LibreOffice.

Есть ситуации, когда нет возможности установить Excel на стороне клиента, а нужно загружать в базу данные *.xls файлов. Спасением является бесплатный OpenOffice (либо LibreOffice, т.к. работа через COM с ними абсолютно одинакова).

Ниже привожу процедуры загрузки и выгрузки.

Функция ЗагрузитьТЗизФайла(ПутьКФайлу)

    //OpenOffice Calc//////////////////////////////////////////////////////////////////////////////////////////////
    Попытка
        ServiceManager = Новый COMОбъект("com.sun.star.ServiceManager");
    Исключение
        Предупреждение(ОписаниеОшибки() + Символы.ПС + "программа OpenOffice\LibreOffice не установлена на данном компьютере!");
    Возврат Неопределено;
    КонецПопытки;
    Desktop = ServiceManager.createInstance("com.sun.star.frame.Desktop");
    Свойства = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
    Свойства.Name = "AsTemplate";
    Свойства.Value = Истина;
    Args = Новый COMSafeArray("VT_VARIANT", 2);
    Args.SetValue(0, Свойства);
    Свойства1 = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
    Свойства1.Name = "Hidden";
    Свойства1.Value = Истина;
    Args.SetValue(1,Свойства1);
    Document = Desktop.LoadComponentFromURL(ПривестиФайлКУРЛ(ПутьКФайлу), "_blank", 0, Args);
    Sheets = Document.getSheets();
    Sheet = Sheets.getByIndex(текЛист-1);
    локТабЗнач = Новый ТаблицаЗначений;
    begCol = 0;
    begRow = 0;
    endCol = Sheet.Data.GetLength(6) - 1;
    endRow = Sheet.Data.GetLength() - 1;
    нКол = 0;
    локТабЗнач.Колонки.Очистить();

    КС = Новый КвалификаторыСтроки(50);
    Массив = Новый Массив;
    Массив.Добавить(Тип("Строка"));

    ОписаниеТиповСтрока = Новый ОписаниеТипов(Массив, , КС);

    Пока нКол <= endCol Цикл
        ИмяКол = "К"+Строка(нкол+1);
        локТабЗнач.Колонки.Добавить(ИмяКол,ОписаниеТиповСтрока);
        нКол = нКол + 1;
    КонецЦикла;
    Range = Sheet.getCellRangeByPosition(begCol, begRow, endCol, endRow);
    МассивКом = Новый COMSafeArray("VT_VARIANT", Range.Columns.Count, Range.Rows.Count);
    МассивКом = Range.getDataArray();
    тмпПростойМассив = МассивКом.Выгрузить();
    Для каждого массив из тмпПростойМассив Цикл
        ит = 0;
        НовСтрока = локТабЗНач.Добавить();
        Для каждого ЭлементМассива из массив цикл
            НовСтрока[ит] = ЭлементМассива;
            ит = ит + 1;
        КонецЦикла;
    КонецЦикла;
    Возврат локТабЗнач;

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

Как  видно из функции  ЗагрузитьТЗизФайла - читается сразу вся область данных файла, поэтому с быстродействием все отлично. На выходе имеем готовую таблицу значений. В данном случае каждой колонке определен тип Строка(50), но можно этого и не делать, просто это нужно, если собираетесь, например, помещать ее во временную таблицу. 

Процедура ВыгрузитьТЗвФайл(ТаблицаРезультата)

    //OpenOffice Calc///////////////////////////////////////////////////////////////////////////
    Попытка
        ServiceManager = Новый COMОбъект("com.sun.star.ServiceManager");
    Исключение
        Предупреждение(ОписаниеОшибки() + Символы.ПС + "программа OpenOffice не установлена на данном компьютере!");
        Возврат;
    КонецПопытки;
    Desktop = ServiceManager.createInstance("com.sun.star.frame.Desktop");
    Свойства = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
    Свойства.Name = "AsTemplate";
    Свойства.Value = Истина;
    Args = Новый COMSafeArray("VT_VARIANT", 3);
    Args.SetValue(0, Свойства);
    Свойства1 = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
    Свойства1.Name = "Hidden";
    Свойства1.Value = Истина;
    Args.SetValue(1, Свойства1);
    Document = Desktop.LoadComponentFromURL("private:factory/scalc", "_blank", 0, Args);
    Sheets = Document.getSheets();
    Sheet = Sheets.getByIndex(0);
    мИтКол = 0;
    Для каждого кол из ТаблицаРезультата.Колонки Цикл
        Sheet.getCellByPosition(мИтКол,0).setString(кол.Имя); 
        мИтКол = мИтКол + 1;
    КонецЦикла
   
    ВсегоСтрок = ТаблицаРезультата.Количество();
    ВсегоКолонок = ТаблицаРезультата.Колонки.Количество();
    МассивКОМ = Новый COMSafeArray("VT_VARIANT", ВсегоСтрок,ВсегоКолонок);
    иткол = 0;
    итстр = 0;

    Для каждого стр из ТаблицаРезультата Цикл
        Для каждого кол из ТаблицаРезультата.Колонки Цикл
            стрРез = СокрЛП(стр[кол.Имя]);
            МассивКОМ.SetValue(итстр,иткол,стрРез);
            иткол = иткол+1;
         КонецЦикла;
        иткол = 0;
        итстр = ?(итстр=ВсегоСтрок,0,итстр+1);
    КонецЦикла;
    begCol = 0;
    begRow = 1;
    endCol = ВсегоКолонок-1;
    endRow = ВсегоСтрок;
    Range = Sheet.getCellRangeByPosition(begCol, begRow, endCol, endRow);
    Range.setDataArray(МассивКОМ);
    //Document.storeToURL(ПривестиФайлКУРЛ(ПутьКФайлу),Args);
    Свойства2 = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
    Свойства2.Name = "FilterName";
    Свойства2.Value = "MS Excel 97";
    Args.SetValue(2,Свойства2);
    Document.GetCurrentController().GetFrame().GetContainerWindow().SetVisible(Истина);
    //Document.storeToURL(ПривестиФайлКУРЛ(ФайлКартотеки),Args);

КонецПроцедуры

Процедура  ВыгрузитьТЗвФайл сохраняет любую таблицу значений в файл MS Excel. В текущем примере откроется OpenOffice/LibreOffice Calc  c данными переданной таблицы значений. Если раскомментировать строки:

//Document.storeToURL(ПривестиФайлКУРЛ(ПутьКФайлу),Args);

 ...................................................

//Document.storeToURL(ПривестиФайлКУРЛ(ФайлКартотеки),Args);

и закомментировать

Document.GetCurrentController().GetFrame().GetContainerWindow().SetVisible(Истина);

при этом добавив Параметр ПутьКФайлу, то данные запишутся в файл без открытия Calc`a. Если обратить внимание на сохранение, то сразу бросается двойной вызов  Document.storeToURL - это необходимо для корректного сохранения в формате MS Excel.

Функция ПривестиФайлКУРЛ(ПутьКФайлу)

    ПутьКФайлу = СтрЗаменить(ПутьКФайлу," ","%20");
    ПутьКФайлу = СтрЗаменить(ПутьКФайлу,"\","/");
    Возврат "file:/" + "/localhost/" + ПутьКФайлу;

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

Функция  ПривестиФайлКУРЛ просто приводит путь к виду, необходимому OpenOffice/LibreOffice.

Вот и все. Как вы смогли убедиться -  работа с Calc`ом не сложнее таковой с Microsoft Excel.

См. также

Подписаться Добавить вознаграждение

Комментарии

1. MaxDavid (MaxDavid) 13.07.11 22:11
Плюс даже не пробуя, ибо некогда сталкивался с ООо и представляю, сколько времени может сэкономить статья.
romansun; +1 Ответить
2. Роман Романов (romansun) 13.07.11 23:03
+1 всем - совершенно согласен


добавлю, что ОО не использовал - для тех, у кого не было офиса, использовал ADO. Оч. удобно и, главное, огромные эксели "засасывает" как реактивный пылесос ))
theshadowco; +1 Ответить
3. Igor2010 (IgorXml) 14.07.11 14:52
4. Ийон Тихий (cool.vlad4) 14.07.11 15:51
В общем да...гуд...добавлю в защиту 1С-овцев и плюс к статье, что кое-какие ф-ции по работе с ОО ими написаны в модуле УправлениеПечатьюOOWriterКлиент (БСП)
okulus; Трактор; +2 Ответить
5. Роман Осадченко (cleaner_it) 16.07.11 05:34
Большой жирный плюс. Использую OpenOffice (в последнее время LibreOffice) уже 4 года - мне очень пригодится. Да и другим, думаю, тоже
7. Island-ua (StreamLVM) 18.07.11 11:05


Я умею пользоваться поиском и прежде чем написать статью я искал и находил эти ссылки:
1)http://infostart.ru/public/14718/ Пример работы с OpenOffice.org Writer & MS Word
У меня работа с Сalc

2)http://infostart.ru/public/20710/ Создание PDF из OpenOffice.
хорошая статья, но опять не то

3)http://infostart.ru/public/58070/ Пример выгрузки документа в Excel и отправка по E-mail средствами 1С
здесь 1с 7.7

4)http://infostart.ru/public/59625/ Выгрузка в OpenOffice Calc. Платформа 7.7. Формирование прайса и формы заказа
тоже 1c 7.7

5)http://infostart.ru/public/73507/ Обработка файлов OpenOffice Calc без установленного OpenOffice и ВК
что хоть с этой статьей общего???

6)http://infostart.ru/public/73948/ Пример работы с Open Office Writer. Часть 2. Подмена контекста без OLE. Работает намного быстрее.
и здесь что-то общее, кроме слова OpenOfiice

В каждой из приведенных вами статей есть упоминание слова OpenOffice, хотя общего между ними немного. Они все баяны? Вы хоть просмотрели бы их чтоли...
torg1c; Keu2; rayastar; vis_tmp; Serj1C; +5 Ответить
8. drimer (drimer) 19.07.11 11:31
Отличная статья!
Вкралась небольшая ошибочка в пример
локТабЗнач.Колонки.Добавить(НовИмяКол,ОписаниеТиповСтрока);

а должно быть локТабЗнач.Колонки.Добавить(ИмяКол,ОписаниеТиповСтрока);
9. Island-ua (StreamLVM) 19.07.11 12:18
drimer пишет:

Вкралась небольшая ошибочка в пример
локТабЗнач.Колонки.Добавить(НовИмяКол,ОписаниеТиповСтрока);

а должно быть локТабЗнач.Колонки.Добавить(ИмяКол,ОписаниеТиповСтрока);

Спасибо, поправил. Выдернул с последнего задания и не все привел к нужному виду.
10. Resha D (Resha) 27.07.11 11:50
Методы:
endCol = Sheet.Data.GetLength(6) - 1;
endRow = Sheet.Data.GetLength() - 1;

Не корректно работают для больших файлов.

Для проверки можно ручками создать файл вида:
A_000001	B_000001	C_000001	D_000001	E_000001	F_000001
A_000002	B_000002	C_000002	D_000002	E_000002	F_000002
....
A_046000	B_046000	C_046000	D_046000	E_046000	F_046000


В результате получим:
endCol = -1;
endRow = 0;


Вариант до 001000 - работает отлично.
11. Resha D (Resha) 27.07.11 12:39
Обнаружил, что максимальное число строк, которых понимает OpenOffice, при чтении xls файлов: 2^15 - 1 = 32767. Если хоть на одну больше - алгоритм не работает.
Ekaterina Lebedenko; CaSH_2004; +2 Ответить
12. Александр Шкут (alex_shkut) 30.09.11 13:24
Спасибо огромное, то что надо, кто отходит от пиратки или не имеет официального МСО.
Попробовал использовать в своей конфигурации и не могу понять, откуда возникает переменная в функции загрузки
Sheet = Sheets.getByIndex(текЛист-1);

Могу предположить (так и сделал) что текЛист можно передавать в качестве параметра функции.
13. Виталий Сысоев (Vital451) 21.10.11 07:45
А что за "ФайлКартотеки" нужно подставить ?
14. Александр Шкут (alex_shkut) 21.10.11 19:33
Vital451 пишет:
А что за "ФайлКартотеки" нужно подставить ?

Это пример вызова функции в которой в Переменной "ФайлКартотеки" передается Виндовый путь к файлу полностью, типа: D:\\Мои Документы\файл.xls
15. megatrend - (megatrend) 16.11.11 18:21
Для LibreOffice этот код будет работать? Или его нужно менять в части вызова COM-объекта офиса?
16. Island-ua (StreamLVM) 16.11.11 20:16
(15) megatrend, все будет работать, ничего не нужно менять.
17. г. Казань Рустем Гумеров (Rustig) 05.12.11 13:56
за публикацию плюс,
(0) хотелось бы видеть код с комментариями...
вникать в процедуры и методы объектов ОупенОфиса пришлось отдельно,
спасибо за дельные ссылки Трактору (6) ...
Для начинающих осваивать ОупенОфис в плане программирования продублирую ссылки,
так сказать в качестве основы основ:
- http://articles.org.ru/cn/showdetail.php?cid=6064 - основы работы с объектами ОупенОфиса на форуме для Дельфистов, также эта ссылка есть в публикации http://infostart.ru/public/59625/ , на которую указал Трактор
- http://wiki.services.openoffice.org/wiki/Documentation/BASIC_Guide/Editing_Spreadsheet_Docum­ents - документация по объектам ОупенОфиса на англ. языке
- http://infostart.ru/public/20710/ - статья Трактора с комментариями
CaSH_2004; +1 Ответить
18. Александр Шкут (alex_shkut) 15.01.12 16:17
Для применения с LibreOffice необходимо маленькая поправка. Я долго искал ответ, почему именно так, но не нашел. Методом "тыка" нашел работающее решение.
endCol = Sheet.Data.GetLength(10) - 1;

Значение в скобках (10) - найдено экспериментально. Я так понимаю - это значение массива, где хранится максимальная занятая на данный момент колонка таблицы. С OpenOffice не проверял. Проверено на LibreOffice 3.4
19. Resha D (Resha) 24.01.12 02:08
Так же копался с этой проблемой и нашел несколько другое решение:
Document = Desktop.LoadComponentFromURL("file:///" + ПолноеИмяФайла, "_blank", 0, Параметры);
Листы    = Document.getSheets(); 
Лист     = Листы.getByIndex(НомерЛиста - 1); 
Курсор   = Лист.createCursor();
Курсор.gotoEndOfUsedArea(Истина);
КонечнаяСтрока   = Курсор.Rows.Count - 1;
КонечнаяКолонка  = Курсор.Columns.Count - 1;
...Показать Скрыть

Пока работает на всех файлах, что попадались (больше 65536 строк не попадались).
alex_shkut; +1 1 Ответить 1
20. Александр Шкут (alex_shkut) 10.02.12 14:52
Вполне согласен, решение более корректное, чем мое. Спасибо :) поправлю свой код.
21. Сергей Федоров (Bober777) 18.05.12 12:59
Плюсанул с огромным удовольствием. Статья стоит того. Я бы хотел единственное попросить автора привести пример. Как одновременно прочитать данные с файла ods и тут же отредатировать читаемый файл (например в одной колонке в определенной строке найти Артикул и в той же строке отредактировать ячейку другого столбца претаоложим это будет количество).
Спасибо за внимание.
22. Александр Шкут (alex_shkut) 18.05.12 13:22
(21) Bober777,
прочитать данные с файла ods и тут же отредатировать читаемый файл

Задача не совсем корректна, однако попробую предположить...
1. Если Вы хотите сформировать новый файл, то сформируйте его средствами 1С и сохраните в формате XLS.
2. Вы имеете некий "сводный" файл, куда каждое подразделение вносит свои поправки?
Из данного примера мне пригодилось именно "чтение" файла для импорта в 1С всяких "табличек". Остальные задачи либо "прихоти" неграмотных руководителей, не желающих изучать 1С, либо неправильно поставленный процесс обмена информацией.
LibreOffice прекрасно открывает и читает формат XLS, так почему-же не выгружать из 1С информацию в этом формате?
З.Ы. Даю намек по п.2 - используете из данного примера создание COM-объекта, загружаете информацию из файла в таблицу значений, редактируете ее как Вам угодно и синхронизируете все свои действия средствами COM c открытым файлом. Потом корректно закрываете его, и все. Примеры на сайте OpenOffice имеются. Если это действительно необходимо - изучайте вопрос и плюс Вам в публикацию.
З.Ы. З.Ы. Можно не выгружать в ТЗ, а в фоновом режиме (обработкой) сделать изменения через COM.
23. Сергей Федоров (Bober777) 18.05.12 13:30
Хорошо, если у меня будут еще вопросы технического характера, я могу их задавать?
24. Александр Шкут (alex_shkut) 18.05.12 13:31
(23) Bober777, Я думаю - что да. Только уточните свою задачу.
25. Александр Шкут (alex_shkut) 18.05.12 13:42
Эксель и ОпенОфис хранит дату в виде целого числа. Если загрузить файл в ТЗ - в колонках дат будут целые числа.
Код ниже преобразовывает такие колонки в дату 1С. Устанавливаете курсор в нужную колонку, и запускаете этот код.
Процедура КоманднаяПанель2ВосстановитьДаты(Кнопка)
	Колонка = ЭлементыФормы.ДанныеФайла.ТекущаяКолонка; //ДанныеФайла - табличное поле с загруженными данными
	Для Каждого Строка из ДанныеФайла Цикл
		Если ЗначениеЗаполнено(Строка[Колонка.Имя]) Тогда
			Попытка //Если в колонке неправильная дата или любое нечисловое значение, то пропускаем
				Строка[Колонка.Имя] = Дата("19000101")+((Строка[Колонка.Имя]-2)*24*60*60);
			Исключение
			//Здесь можно сделать вывод списка или подсчет ошибочных ячеек, например
			КонецПопытки;
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры
...Показать Скрыть
26. Сергей Федоров (Bober777) 20.05.12 09:53
(24)
Только уточните свою задачу.

задачу уточнил:
- скопировать файл с расширением "*.ods" обозвать его определенным именем - это не проблема выполняется стандартными процедурами 1С.
- отредактировать скопированный файл в формате *.ods поиском определенных строк по заполненому значению в столбце "номер 1" и отредактировать столбец "номер 2" в найденой строке.
- сохранить отредактированный файл в формате *.ods без участия пользователя автоматически.

Задача вроде как бы простая, знаю как решается, если работать с файлами *.xls.

А в данной задаче сам момент редактирования не знаю как решить (выполнить),
- конечно можно было бы взять сначала данные и загрузить из файла *.ods в таблицу значений;
- затем обработать данные в загруженной таблице значений;
- потом выгрузить данные из таблицы значений в файл;
Но думаю данный метод не подходит.
27. Александр Шкут (alex_shkut) 21.05.12 13:53
(26)
Намек 1: формат .ods - аналог .xlsx, т.е. просто смени расширение и получишь Эксель-файл.
Намек 2: используй всю мощь COM-механизма. Ну тут сложнее, т.к. придется дублировать действия в 1С соответствующими функциями COM-объекта. Я интересовался этой возможностью в свете данной публикации, но писать серьезный модуль нету времени и необходимости. Ссылки на документацию есть выше.

- конечно можно было бы взять сначала данные и загрузить из файла *.ods в таблицу значений;

Да, можно так. Оставляем файл .ods открытым... и подключенным к 1С.
- затем обработать данные в загруженной таблице значений;

А вот здесь нужно каждое изменение дублировать вызовом изменения в исходном файле, т.е. по сути написать свой редактор .ods на основе механизма COM. Подобными извратами я занимался, когда работал с БД Access, но самомго офиса у меня не было. Все писал на Делфи.
- потом выгрузить данные из таблицы значений в файл;

Все это мы делали синхронно в предыдущем пункте, теперь просто сохраним и закроем файл.

Вот такой себе алгоритм...
28. bent 30.05.12 12:48
Большое спасибо за статью. Очень помогла.
Единственное , через раз при загрузке появляется вот такая ошибка:

Ошибка при вызове метода контекста (getCellRangeByPosition)
	Range = Sheet.getCellRangeByPosition(begCol, begRow, endCol, endRow);
по причине:
Произошла исключительная ситуация ([automation bridge] ): com.sun.star.lang.IndexOutOfBoundsException: 
...Показать Скрыть

Подскажите, пожалуйста, с чем это может быть связано..
29. Александр Шкут (alex_shkut) 31.05.12 12:35
(28) Пожалуйста, внимательно потестируйте пример. Возможно, что ошибка возникает в конкретном, определенном случае, на одном и том-же файле. Например: Вы обращаетесь к несуществующему, или возможно, пустому листу.
Я дописал свой вариант функции для обращения к любому листу в файле и к произвольному диапазону на листе.
Все работает без ошибок.
30. bent 31.05.12 15:38
(29) alex_shkut, в том-то и дело, что загружаю один и тот же файл. Как раз пишу обработку по загрузке, поэтому тестирую одну и ту же таблицу. Программа именно через раз загружает. Нажимаю "загрузить" - показывает ошибку, которую описывала выше, тут же пробую еще раз - загружает.
В результате вчера,задала свое значение переменной endCol, зная, что в данной конкретно обработке оно у меня меняться не будет.
31. Александр Шкут (alex_shkut) 31.05.12 16:20
(30)В самом начале, когда я тестировал код на OpenOffice у меня возникали проблемы. Офис "повисал" в памяти и начинались глюки. Позже я добавил в конец функции вот такой код:

...
КонецЦикла;
Document.Close(True);
Document = Неопределено; 

ServiceManager = Неопределено;
Возврат локТабЗнач;
...Показать Скрыть


В общем смысле я закрываю документ и очищаю указатель. Офис перестал зависать в процессах и больше ошибок не появлялось. Может это решение?
32. v i (vis_tmp) 07.11.12 07:53
(31) alex_shkut,

Правильнее, думаю, так делать:

ServiceManager = Неопределено;
Document.close(True);
Desktop.terminate();
33. v i (vis_tmp) 07.11.12 08:07
ОГРОМНОЕ СПАСИБО АВТОРУ!
34. Shade (Shade) 19.03.14 09:13
Спасибо :)
Прикрепленные файлы:
35. Dimass (dmikds) 03.04.14 08:26
Спасибо, за статью, очень помогла!!!
36. Александр Шкут (alex_shkut) 04.04.14 13:26
(25)Увидел в своем же сообщении логическую ошибку.
При преобразовании числа в дату
Строка[Колонка.Имя] = Дата("19000101")+((Строка[Колонка.Имя]-2)*24*60*60);

надо брать не
Дата("19000101")
, а каким-то образом считывать из файла диапазон интерпретации дат.
И использовать начальную, как точку отсчета.
Я не пробовал, но для чего тогда настройка интерпретации дат?
37. Владимир Овсянников (Karlitos) 17.04.14 09:34
Подскажите, пожалуйста, что должно быть в переменной "ТекЛист"?..
38. Vitaliy Litvinenko (StreamLVM) 17.04.14 14:40
(37) Karlitos, номер листа в вашем файле.
39. Владимир Овсянников (Karlitos) 25.04.14 11:39
(38) StreamLVM, ага, я разобрался) Спасибо за статью, помогла!
40. Федор Бурковский (medved_kot) 13.07.14 12:29
Просто хотел откомментировать код
endCol = Sheet.Data.GetLength(6) - 1;
endRow = Sheet.Data.GetLength() - 1;


Это получение последней колонки и строки, которые вообще заполнены в таблице.

тмпПростойМассив = МассивКом.Выгрузить();

в тмпПростойМассив массив Строк и Столбцов, к которому можно обращаться:
Значение = тмпПростойМассив[номерСтроки - 1][номерСтолбца - 1]

И да. Спасибо!
41. Al (al_zzz) 24.02.15 21:53
Подскажите пожалуйста, как мне переделать процедуру сохранения тз, чтоб создавался не файл ексель, а файл в формате "DIF" и в кодировке CP-866?
42. Вася Неизвестный (dismoitout) 28.05.15 12:11
Пытался использовать ваш код для загрузки - если запускаю не с флешки то пишет
Bridge_GetStruct метод обьекта не обнаружен

а если с флешки то


Desktop.LoadComponentFromURL метод объекта не обнаружен
??????????????
43. Вася Неизвестный (dismoitout) 28.05.15 12:12
Вернее есл загржаемый в обработке файл (эксель размещен на флешке или на раб столе или в корне диска цэ)
44. Олег Шалимов (CaSH_2004) 18.06.15 23:57
Мда, метод красивый, быстрый, но глючный.
Во-первых:
(10)(40) Sheet.Data.GetLength некорретно работает не только на больших файлах, но и на маленьких
я для примера создал файл с 3 колонками и 3 строками и прочел его - выдало что колонок > 9 000 000 !!! непонятно что его так глючит
Во-вторых:
это обнаружил после того как на одном из прайсов он не видел последнюю колонку, выдавал на одну меньше и все
В-третьих:
на VBScript его даже не удалось воспроизвести т.к. такого объекта как Data просто не существует!
во всяком случае тут
http://www.openoffice.org/api/docs/common/ref/com/sun/star/sheet/module-ix.html
я этого не нашел

возникает вопрос - что это за зверь такой?
в какой момент он как сработает неизвестно, поэтому его нужно либо перепроверять либо вообще не пользоватся дабы он не подвел в самый неподходящий момент, как получилось у меня после сдачи работы это все всплыло как г-но в проруби

Придется все таки пользоватя медленным, но надежным старым считываением:
CellCursor = Sheet.CreateCursor();
CellCursor.GoToStartOfUsedArea(Ложь);
CellCursor.GoToEndOfUsedArea(Истина);
CellRangeAddress = CellCursor.GetRangeAddress();
ПоследняяКолонка = CellRangeAddress.EndColumn;
ПоследняяСтрока = CellRangeAddress.EndRow;
...Показать Скрыть


PS: тестил на OpenOffice 4.1.1 + 1С:Предприятие 8.2 (8.2.19.90)
45. Vitaliy Litvinenko (StreamLVM) 19.06.15 12:42
(44) CaSH_2004, У меня подобные глюки при работе с сохраненными файлами из древних версий MS Excel. Я рекомендую все же использовать LibreOffice.
46. Олег Шалимов (CaSH_2004) 19.06.15 22:39
(45) А я вот наоборот не рекомендую пока им пользоваться , и вот почему:
в первый и последний раз я увидел LibreOffice пол года назад у одного клиента которому его тоже какой-то сисадмин расхвалил и поставил вместо проверенного OpenOffice.
Потом мне потребовалось сделать выгрузку прайса с картинками, так после долгих извращений и мучений (что-то не корректно шло оформление) LibreOffice перестал открывать и создавать файлы (я его сильно мучил, честно) - после этого я его снес и пользуюсь проверенным OpenOffice.
47. Олег Шалимов (CaSH_2004) 19.06.15 22:56
+(44) Собственно чтобы обойти указанный глюк достаточно заменить получение последней колонки/строки автора на вариант (44), но вот более подробно:
Cursor = Sheet.CreateCursor();
Cursor.GoToStartOfUsedArea(Ложь); // непонятно почему Ложь
Cursor.GoToEndOfUsedArea(Истина); // а тут Истина
КоличествоЗаполненныхКолонок		= Cursor.Columns.Count;
КоличествоЗаполненныхСтрок		= Cursor.Rows.Count;
RangeAddress = Cursor.GetRangeAddress();
ПерваяЗаполненнаяКолонка		= RangeAddress.StartColumn;
ПерваяЗаполненнаяСтрока			= RangeAddress.StartRow;
ПоследняяЗаполненнаяКолонка		= RangeAddress.EndColumn;
ПоследняяЗаполненнаяСтрока		= RangeAddress.EndRow;
...Показать Скрыть

в (19) коллега не учел что работать это будет только если у него заполнение листа идет с самой первой строки и колонки, т.к. это не просто количество строк и колонок всего, а именно ЗАПОЛНЕННЫХ, т.е. по сути:
КоличествоЗаполненныхКолонок = ПоследняяЗаполненнаяКолонка - ПерваяЗаполненнаяКолонка + 1; // т.е. + сама 1-я колонка
КоличествоЗаполненныхСтрок = ПоследняяЗаполненнаяСтрок - ПерваяЗаполненнаяСтрок + 1; // т.е. + сама 1-я строка

Кстати для информации колонок предусмотрено 1024, а строк 1024*1024 = 1 048 576, во всяком случае Cursor.Columns/Rows.Count именно это возвращают пока не выполнишь позиционирование Cursor.GoTo...
(0) в добавок ко всему непонятно зачем тут
МассивКом = Новый COMSafeArray("VT_VARIANT", Range.Columns.Count, Range.Rows.Count);
МассивКом = Range.getDataArray();

автор в переменную МассивКом помещают SafeArray, а потом затирают так и не используя. Я убрал это и все продолжает работать. Может автор или кто-то подскажет для чего это нужно?

PS: в результате разбирания и выкидывания мусора весь пример сократился в 2-3 раза! Там реально много лишнего, коллеги проверяйте выкладываемый код что-ли, а то мусор лопатой выкидываешь
48. Vitaliy Litvinenko (StreamLVM) 23.06.15 18:14
(46) CaSH_2004, Вы не закрывали com объект и он завис. Завершили бы процесс и все работало. А насчет LibreOffice vs OpenOffice, так работа в Libre идет конскими шагами, причем попутно избавляясь от Java в коде, да и по функционалу он впереди, хотя для 90% пользователей это непринципиально.
49. Олег Шалимов (CaSH_2004) 02.07.15 13:20
(48)
Вы не закрывали com объект и он завис. Завершили бы процесс и все работало.

Я его даже не открывал. Я говорил про то что LibreOffice под любым пользователем перестал открываться - просто вылетал с какой то ошибкой системной.
Libre идет конскими шагами

я человек, а не конь, поэтому мне это не нужно :)
по функционалу он впереди, хотя для 90% пользователей это непринципиально.

Вот это верно на 100% - зачем ставить новое если с головой хватает старого? Новый функционал никто не использует т.к. все борются с новыми глюками!

ИМХО:
Как видим даже старый функционал никто толком не знает (судя по этой статье), а это как раз из-за того что постоянно выходит все новое, в надежде избавится от проблем старого, но естественно этого не происходит, зато к старым проблемам прибавляются новые, и из-за того что приходится бросать все силы на исправление ошибок, соответственно не хватает времени не то что на развитие и изучение нового,но даже на себя :(
Это как раз случай "придумываем себе трудности чтобы их потом героически преодолевать".
50. Олег Шалимов (CaSH_2004) 25.08.15 00:14
(48) Вот одна из причин из-за чего нет смысла в LibreOffice несмотря на ее "конский шаг"
Open Calc Report System - смотрим комменты 15-16
Буду благодарен если и вы скините мне что то в защиту своей позиции.
51. Михаил Тебеньков (Miket78) 26.10.15 22:00
Вопрос к знатокам по теме статьи: как из 1с подключиться к открытому в OpenOffice Calc документу.
Для Excel есть код:
Ексель = ПолучитьCOMОбъект(, "Excel.Application");
АктивнаяСтраница = Ексель.ActiveSheet;
ТекстЯчейки=Врег(СокрЛП(АктивнаяСтраница.Cells(НомерСтрокиЕксель,НомерКолонкиЕксель).text));

Отлично работает. А как повторить такое для OO? Нужно именно прочитать активный открытый документ, а не открывать по имени файла новый сеанс.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа