Как считать содержимое файла в переменную?

Автор Strannik61, 8 ноября 2016, 09:52

0 Пользователи и 1 гость просматривают эту тему.

Strannik61

Для организации поиска по базе нужно занести ТЕКСТОВОЕ содержимое файла в базу.
Файлы могут быть СТРОГО нескольких типов - odt, doc, xls или ods
Сейчас делаю так:
Открываю файл - сохраняю как текстовый (temp.txt) - Считываю из него построчно в переменную - Заношу в базу - Удаляю текстовый файл (temp.txt).
Может быть есть более лёгкий и правильный путь? Считать сразу в переменную, но только текстовое содержимое файла?
Без форматирования, таблиц и прочего?

rami

Получить текстовое содержимое из текстового документа (odt, doc) просто (объём строки ограничен 64КБ):
s=ThisComponent.Text.String

Для табличных документов (xls или ods) чуть сложнее, нужно выбрать лист, диапазон и перебрать строки диапазона, например, так:
Sub Main   Dim d(), s$
d=ThisComponent.Sheets(0).Data
For i=0 To UBound(d)
s=s & join(d(i),";") & chr(10)
Next
End Sub

JohnSUN

Ну да... Только, наверное, не ThisComponent, а какой-нибудь oDoc.getText().getString() - у Strannik61 этим ThisComponent скорее всего будет сама база, куда контент вставляется.
А по таблицам, наверное, чистая Data как-то не очень... Тексты-то потеряются, а по ним поиск вести собираются. Возможно, для каждого листа (в смысле для UsedArea, конечно - не для всего листа) придется слизывать .getDataArray(), пихать его обратно как setFormulaArray, опять считывать и тогда уж join'ить... И, само собой, книгу закрыть без сохранения изменений  ;D
Или смотреть в сторону текстовых фильтров - типа, имитировать сохранение в CSV...
А вообще-то постановка задачи какая-то странная  ;)
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

Strannik61

#3
rami - очередное огромное спасибо!

JohnSUN - постановка задачи не странная. Проблема в том, что ОЧЕНЬ давно, лет так 15 назад, ещё на IE и MS Office была сделана собственная простенькая система делопроизводства.
За годы она разрослась. Потом перешли на OpenOffice. При этом вызов всех документов по-прежнему производился из IE через ActiveX, что само по себе неправильно.
Вот я потихоньку и переделываю систему, чтобы всё работало только в ОО без IE, но к несчастью с сохранением всей структуры базы и вызывалось из самого ОО.
При этом поиск документов должен быть в базе, т.к. ей пользуются удалённо. Поэтому и есть необходимость заносить в неё текстовое содержимое.
UPDATE
У нас все новые документы создаются на основе образцов документов. В частности все табличные образцы содержат только 1 лист, поэтому задача у меня упрощается.

rami

Постановка задачи слишком общая, я дал общие идеи с чего начать, но дальше нужно учитывать подробности. Обратите внимание на уточнения JohnSUN на счёт Data, DataArray и FormulaArray — они по разному работают с данными.

P.S. К сведению, если данные в табличных документах имеют ту же структуру как и в базе, можно добавлять данные из электронных таблиц в базу простым перетаскиванием. Если этот способ подойдёт, то будет просто и удобно.

Strannik61

Под базой я имел в виду базу в mysql
Туда так просто не перетащишь. :)
И способ с перебором диапазона таблицы не получился. В текст вставляется много непонятных числе из пустых ячеек.
Мне кажется будет проще выделить всё содержимое листа, скопировать и вставить в текстовый лист по принципу "без форматирования". А там уже как вы и советовали.

rami

Цитата: Strannik61 от  8 ноября 2016, 10:11И способ с перебором диапазона таблицы не получился. В текст вставляется много непонятных числе из пустых ячеек.
"Непонятные числа" — 2.2250738585072014e-308 — это не числовые значения (пустые ячейки или текст).

Для чисел и текста:
Sub Main   Dim d(), da(), s$
oSheet=ThisComponent.Sheets(0)
d=oSheet.Data
da=oSheet.getCellRangeByPosition(0,0,UBound(d(0)),UBound(d)).DataArray
For i=0 To UBound(d)
s=s & join(da(i),";") & chr(10)
Next
End Sub

economist

Сталкивались с подобной задачей - база договоров в Excel.
Тексты договора - длинные строки (а кто сказал что нельзя?)

После 120 тыс. строк стало тормозить. Залили всё в SQLite, морду написали в BASE, да и в Calc есть старое "междумордие".  Когда стали заливать и приложения - стал тормозить поиск и возникла задача максимально быстрого полнотекстового поиска, с поддержкой языка запросов, позволяющих исключать словоформы.

Тут как раз пришел незамутненный практикант и прикрутил FTS (Full Text Search) к SQLite, и стало совсем хорошо. Время любого поискового запроса (включает как правило несколько И и НЕ - 0,5 сек. 
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

JohnSUN

Цитата: Strannik61 от  8 ноября 2016, 11:32
JohnSUN - постановка задачи не странная.
Да ладно тебе, я же там смайлик прилепил - просто каламбурил на тему ника...

@rami Ты постоянно вставляешь chr(10) - это из-за этой фразы?
Цитата: Strannik61 от  8 ноября 2016, 09:52
(temp.txt) - Считываю из него построчно в переменную
Насколько я себе представляю полнотекстовый поиск - эти переводы строк (да и точку с запятой, пожалуй) можно и просто на пробелы заменить. Впрочем, могу и ошибаться.
А по поводу "соскрести контент с листа" - у меня почему-то получилось длиннее:
Function getContent(Optional sheetIndex As Integer) As String
Dim oSheet As Variant
Dim oCursor As Variant
Dim oSDescriptor As Variant
Dim i As Long, j As Long, k As Long
Dim oFound As Variant
Dim oArea As Variant
Dim res As String
If IsMissing(sheetIndex) Then sheetIndex = 0
oSheet = ThisComponent.getSheets().getByIndex(sheetIndex)
oCursor = oSheet.createCursor()
oCursor.gotoEndOfUsedArea(True)
oSDescriptor = oCursor.createSearchDescriptor()
oSDescriptor.setSearchString(".+")
oSDescriptor.SearchRegularExpression = True
oFound = oCursor.findAll(oSDescriptor)
getContent = ""
If IsNull(oFound) or IsEmpty(oFound) Then Exit Function
res = ""
For i = 0 To oFound.getCount()-1
oArea = oFound.getByIndex(i)
For j = 0 To oArea.getRows().getCount() - 1
For k = 0 To oArea.getColumns().getCount() - 1
res = res & oArea.getCellByPosition(k, j).getString() & " "
Next k
Next j
Next i
getContent = res
End Function
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

rami

Цитата: JohnSUN от  8 ноября 2016, 12:30Насколько я себе представляю полнотекстовый поиск - эти переводы строк (да и точку с запятой, пожалуй) можно и просто на пробелы заменить.
Это для сохранения структуры таблицы, от пробелов отказался, так как они могут быть внутри ячейки между слов. Если структура таблицы не нужна, можно свалить всё в кучу или вытаскивать только нужное. Вообще, я показал некий пример, ты показал другой вариант, а Strannik61 будет думать что больше подходит.

Strannik61

#10
Ну у меня на Базу данных натравлен sphinx.  :)
Поэтому поиск моментальный.
Сейчас благодаря советам rami и Питоньяку получилось вот так.
Сильно не ругайте, но советы приветствуются Dim s

Sub CleanText()
Dim document as object, document2 as object,
Dim dispatcher as object, oLocDocument as Object
Dim LocUrl as String, NoArgs()

document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dispatcher.executeDispatch(document, ".uno:SelectAll", "", 0, Array())
dispatcher.executeDispatch(document, ".uno:Copy", "", 0, Array())
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
LocUrl = "private:factory/swriter"
oLocDocument = StarDesktop.LoadComponentFromURL(LocUrl,"_default",0,NoArgs)
document2   = oLocDocument.CurrentController.Frame
args1(0).Name = "SelectedFormat"
args1(0).Value = 1
dispatcher.executeDispatch(document2, ".uno:ClipboardFormatItems", "", 0, args1())
s=ThisComponent.Text.String
oLocDocument.close(true)
msgbox s
End sub

msgbox в конце для тестирования. Потом уберу

rami

Цитата: Strannik61 от  9 ноября 2016, 16:52Сейчас благодаря советам rami и Питоньяку получилось вот так.
Питоньяк, да, он может такие советы давать ;D ;D ;D , а я нет. Это бы меня с кем-то O0 путаете ;D ;D ;D

Ваш макрос выделяет и копирует текст в текущем документе, создаёт новый документ и вставляет скопированное, затем закрывает новый документ и ... показывает текст из текущего документа. Спрашивается: зачем ??? все эти танцы с профсоюзом диспетчеров ;D , если новый документ создаётся (если это нужно) одной строкой кода, а другой строкой в него вставляется текст?

economist

"Профсоюз Диспетчеров" - О..о.о! Надо запомнить!
Теперь я понял почему от него так сложно избавиться в офисе - у них, оказуецо, профсоюз :-))
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

bigor

А если vbs макросом перегнать все  .odt .doc .xls .ods в txt и потом уже грузить в базу
Пример для xls в csv, но меняя параметры фильтров можно все нужные файлв конвертировать в txt

Set ServiceManager = CreateObject("com.sun.star.ServiceManager")
Set Desktop = ServiceManager.createInstance("com.sun.star.frame.Desktop")
Dim Param(1)
Set Param(0) = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue")
Set Param(1) = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue")

Dim oFile
Dim fso, oFiles, oFolder           
Set fso = CreateObject("Scripting.FileSystemObject")

Const path_ = "c:\workfolder"   'каталог где ищем xls
Const file_ = "xls" ' какое расширение ищем

path_u = dos2unix(path_ ,"\\" ,"/" )&"/" ' конвертируем путь в формат ООО


Set oFolder = fso.GetFolder(path_) 
Set oFiles = oFolder.Files         
For Each oFile In oFiles         
     
if Right(oFile.name, 3) = file_ then    ' сравниваем расширение если xls, то в обработку
outFileName = Left(oFile.Name,len(oFile.Name)-3) ' получаем имя файла без расширения

Param(0).Name = "FilterName" ' фильтр для входных
Param(0).Value = "MS Excel 97"

Param(1).Name = "Hidden"
Param(1).Value = true

Set Document = Desktop.LoadComponentFromURL("file:///"&path_u&oFile.Name, "_blank", 0, Param)

Param(0).Name = "FilterOptions" ' фильтр для выходных
Param(0).Value ="44,34,34,1," ' тут параметры для csv

Param(1).Name = "FilterName"
Param(1).Value = "Text - txt - csv (StarCalc)"
           

Document.storeToURL "file:///"&path_u&outFileName&"csv", Param
Document.close True ' закрываем документ


      end if 
Next

Function dos2unix(txt, expr1, expr2) ' функция конвертирования путей
   
    Dim oReg
    Set oReg = New RegExp       
    oReg.Global = True   
    oReg.IgnoreCase = True   
    oReg.Pattern = expr1
    dos2unix = oReg.Replace(txt, expr2)
End Function

Поддержать разработчиков LibreOffice можно можно тут, а наш форум вот тут

Strannik61

to rami. Проблема в том, что копироваться может не только текст, но и таблицы. И открытым документом может быть ods.
А в odt таблицы прекрасно вставляются как чистый текст. Хотя я не все нюансы знаю, поэтому нашёл такой способ. :)
to Bigor. Из ods файла категорически не хочет сохраняться в txt формате. Если знаете способ буду рад поучиться.