Fórum pro uživatele kancelářského balíku OpenOffice | LibreOffice
 

#1 8. 2. 2017 08:49:59

ludviktrnka
Člen
Registrace: 9. 7. 2009
Příspěvků: 697

Aktualizace dat z CSV souboru - VYŘEŠENO

Dobrý den, vím že se to téma už několikrát řešilo, ale stejně to stále nám uspokojivě hotové. Rád bych aktualizoval ve stávajícím dokumentu a ve stávajícím listu data z nového csv. V podstatě princip je ten, že stará data se vymažou a na jejich místo se nakopírují nová (Ne tedy nějaké hledání rozdílů).
Doteď to dělám tak, že CSV otevřu, označím oblast, pak CTR+C a ve stávajícím dokumentu CRL+V. Napadlo mě, že bych to trochu automatizoval a udělal jsem makro. V něm mám jeden zásadní problém - nevím jak vybrat právě všechna data (ani míň ani víc). Metoda kopírování, kterou používám, je docela pomalá, takže příliš velká oblast třeba "A1:ZZ5000" už počítač na chvilku zastaví než se to provede. Oblast "A1:ZZ60000" způsobí kolaps. Data v CSV mají různý rozsah jak co týká sloupců tak řádků. Rád bych si vytvořil obecné řešení. Jiná možnost by byla nakopírovat celý obsah listu, ale takovou metodu jsem ani nenašel, možná neexistuje.

Sub vloz_csv

dim doc as object, tempdoc as object, list as object, csvlist as object
dim adresa as string
dim arg1(2) as new com.sun.star.beans.PropertyValue

doc = thisComponent

list = doc.getCurrentController.getActiveSheet()

adresa = convertToURL(PickFile())

with com.sun.star.sheet.CellFlags
	list.ClearContents(.VALUE or .STRING or .DATETIME)
end with

arg1(0).Name = "FilterName"
arg1(0).Value = "Text – txt – csv (StarCalc)" 'název filtru
arg1(1).Name = "FilterOptions"
arg1(1).Value = "44,34,76,1" '59=středník, nic pro oddelovac textu, 76=UTF-8,1=první řádek
arg1(2).Name = "Hidden"
arg1(2).Value = True
tempDoc = starDeskTop.LoadComponentFromURL(adresa," ",0,arg1())

csvlist = tempDoc.Sheets.GetByIndex(0)

zdroj = csvlist.getCellRangeByName("A1:ZZ5000").getDataArray

tempDoc.close(True)

list.getCellRangeByName("A1:ZZ5000").setDataArray(zdroj)

msgbox ("Fajn",0,"Info")

End Sub

Editoval ludviktrnka (8. 2. 2017 20:07:39)


LibreOffice 5.4.

Offline

#2 8. 2. 2017 10:21:47

neutr
Člen
Registrace: 8. 3. 2007
Příspěvků: 3,435

Re: Aktualizace dat z CSV souboru - VYŘEŠENO

Metoda na okopnutí celého obsahu CSV existuje. Stačí přidat makro které otestuje konec souboru. To získáte úpravou makra od Dana Sedláčka tuším že se jmenuje kopíruj ze skrytého, ale dalo by se upravit i to Vaše.
     Dan tam má jenom kopírování jednotlivých buněk ale funguje. Samozřejmě musíte jej načíst jako sešit Calcu, vložit vyhledání konce a kopírovat jako array - jen text. Problém ale vidím ve velikosti možného rozsahu. Kopírování array jen text. To je trošku nešikovné a zbytečné řešení. Existuje jiný typ makra. Otestujete tohle :

Sub NactiTxtDoCalcu 'Výsledek hodí do jediné buňky
oCell = thisComponent.Sheets.getByIndex(0).getCellByPosition(0,0)
iNumber = freefile()
open "/tmp/dummy.txt" for input as iNumber
While not eof(iNumber)
Line Input #iNumber, sLine
If sLine <>"" then
   sMsg = sMsg & sLine & chr(10)
end if
wend
Close #iNumber
oCell.setString(sMsg) 'sMsg rozeberte cyklem do buněk pomocí textových funkcí, nebo udělejte array.
End Sub

Editoval neutr (8. 2. 2017 10:22:17)


Moje e-mailová adresa
Pokud je Váš problém vyřešen, označte prosím svůj příspěvek za "VYŘEŠENÝ"
Zlepšíte orientaci při vyhledávání řešení JAK OZNAČIT TÉMA ZA VYŘEŠENÉ

Offline

#3 8. 2. 2017 10:42:03

neutr
Člen
Registrace: 8. 3. 2007
Příspěvků: 3,435

Re: Aktualizace dat z CSV souboru - VYŘEŠENO

Ještě mne napadlo jiné řešení. Spusťte to mnou uvedené makro před kopírováním jen s tím rozdílem, že do sMsg nebudete dávat sMsg = sMsg & sLine & chr(10) ale budete inkremenovat číslo - například takto funkcí.

Function NactiKonecTextu 
dim iVar as long 'proměnná která není přímo nutná stačí proiterovat a vrátit jen sLine.
iNumber = freefile()
open "/tmp/dummy.txt" for input as iNumber
While not eof(iNumber)
Line Input #iNumber, sLine
If sLine <>"" then
   iVar = iVar + 1
end if
wend
NactiKonecTextu = iVar
End Function

Ve Vašem makru pak přidáte promměnou "X" pro konec pole > X = NactiKonecTextu(). Pak samozřejmě nebudete znát počet sloupců a musíte to odhadnout. Dá se to i rozdělit na jednotlivé následné sekvence například po 1000 řádcích a přiměřeném množství sloupců - třeba i 1024 a podobně.
      To by bylo trošku obtížnější ale dosáhnete toho pomocí podmínky s INT a MOD v Cyklu. Těmito čísly samozřejmě nakrmíte rozsahy array které se budou kopírovat postupně.

Editoval neutr (8. 2. 2017 10:47:31)


Moje e-mailová adresa
Pokud je Váš problém vyřešen, označte prosím svůj příspěvek za "VYŘEŠENÝ"
Zlepšíte orientaci při vyhledávání řešení JAK OZNAČIT TÉMA ZA VYŘEŠENÉ

Offline

#4 8. 2. 2017 11:49:39

lp.
Člen
Registrace: 24. 9. 2009
Příspěvků: 842

Re: Aktualizace dat z CSV souboru - VYŘEŠENO

Pokud se jedná o aktualizaci, pak proč nevyužít vlastnosti Calcu (poměrně dovedně skryté, dříve to bylo v normální nabídce.):

a) Vložit csv do listu (pravý klik na záložku listu, vložit list, vybrat ze souboru, zaškrtnout "Odkaz",  vyplnit dialog s výběrem,


b) Aktualizovat. (Úpravy, odkazy, vybrat a aktualizovat.)

Offline

#5 8. 2. 2017 12:16:35

ludviktrnka
Člen
Registrace: 9. 7. 2009
Příspěvků: 697

Re: Aktualizace dat z CSV souboru - VYŘEŠENO

Děkuji za reakce.
To neutr: to čtení textu není na csv soubor moc pohodlné, přeci jen vestavěný csv filtr je sofistikovanější. Nalezení konce podle funkce NactiKonecTextu v dalším přípsěvku je fajn. Tu určitě použiji. Díky


To lp.: toto je hodně dobré. Toho jsem si nikdy nevšim. Myslím že mi to bude v 90% případů stačit. Je tady ale jedna velká nevýhoda a to nebezpečí ukliknutí při otvírání dokumnetu a tím "nechtěná" aktualizace třeba již mírně přizpůsobených dat.

Editoval ludviktrnka (8. 2. 2017 12:52:42)


LibreOffice 5.4.

Offline

#6 8. 2. 2017 13:21:11

neutr
Člen
Registrace: 8. 3. 2007
Příspěvků: 3,435

Re: Aktualizace dat z CSV souboru - VYŘEŠENO

Mne sice aktualizace standardní nabídkou napadla ale myslel jsem že pan Trnka také ví - a předem to zvarhl kvůli automatizaci.
      Hned jsem si představil co s tím asi bude dělat - procházet adresáře třeba s výstupy eshopů, nebo z pokladních systémů. U jiného uživatele bych asi neváhal navrhnout zabudovaným postupem.
      Calc má výborné převody nejen CSV ale i XML a podobně. Jen je omezen počtem řádků ale formátování je dík filtrům dobré. Drtivou většina potřeb pokrývá. Já používám načítání tím makrem pro dlouhé XML kde musím nasekat řádky tak aby se mi vešly do Calcu. Tak mne napadlo že pan Trnka dělá něco podobného.


Moje e-mailová adresa
Pokud je Váš problém vyřešen, označte prosím svůj příspěvek za "VYŘEŠENÝ"
Zlepšíte orientaci při vyhledávání řešení JAK OZNAČIT TÉMA ZA VYŘEŠENÉ

Offline

#7 8. 2. 2017 19:58:59

ludviktrnka
Člen
Registrace: 9. 7. 2009
Příspěvků: 697

Re: Aktualizace dat z CSV souboru - VYŘEŠENO

Tak jsem se už zorietoval. Makro doplněné zjištěním délky je perfektní, funguje rychle a spolehlivě. Vestavěný nástroj na odkaz má výraznou nevýhodu že se ptá na aktualizaci při otevření sešitu. Lehko se člověk uklikne a může přijít o data, je to použitelné jen někde - kde se data upravují pouze externě. Já to potřebuji v účetních souborech, kam načtu z on-line databéze generované CSV a lehce je upravuji dle aktuálních potřeb. Ale obecně to použití je širší, těch případů mám hodně, někam se hodí i ten vestavěný nástroj, ale spíše v opačném poměru než jsem psal (tedy 1:9)
Výsledné makro:

Sub vloz_csv

dim doc as object, tempdoc as object, list as object, csvlist as object
dim adresa as string
dim arg1(2) as new com.sun.star.beans.PropertyValue

doc = thisComponent
list = doc.getCurrentController.getActiveSheet()

adresa = convertToURL(PickFile())

delka = PocetRadkuTextu (adresa)

with com.sun.star.sheet.CellFlags
	list.ClearContents(.VALUE or .STRING or .DATETIME)
end with

arg1(0).Name = "FilterName"
arg1(0).Value = "Text – txt – csv (StarCalc)" 'název filtru
arg1(1).Name = "FilterOptions"
arg1(1).Value = "44,34,76,1" '44=čárka 59=středník, 34 = uvozovky, 76=UTF-8, 1=první řádek
arg1(2).Name = "Hidden" 
arg1(2).Value = True

tempDoc = starDeskTop.LoadComponentFromURL(adresa," ",0,arg1())
csvlist = tempDoc.Sheets.GetByIndex(0)

zdroj = csvlist.getCellRangeByPosition(0, 0, 500, delka).getDataArray

tempDoc.close(True)

list.getCellRangeByPosition(0, 0, 500, delka).setDataArray(zdroj)

msgbox ("Fajn",0,"Info")

End Sub

Function PocetRadkuTextu (sURL as string)
dim iVar as long 'proměnná která není přímo nutná stačí proiterovat a vrátit jen sLine.
iNumber = freefile()
open sURL for input as iNumber
While not eof(iNumber)
Line Input #iNumber, sLine
If sLine <>"" then
   iVar = iVar + 1
end if
wend
PocetRadkuTextu = iVar
End Function

Function PickFile() as string
Dim FilePicker As Object
Dim FilePath() As String
FilePicker=createUnoService("com.sun.star.ui.dialogs.FilePicker")
FilePicker.execute
FilePath()=FilePicker.GetFiles
PickFile = FilePath(0)
End Function

Editoval ludviktrnka (8. 2. 2017 20:13:40)


LibreOffice 5.4.

Offline

#8 8. 2. 2017 22:23:29

ludviktrnka
Člen
Registrace: 9. 7. 2009
Příspěvků: 697

Re: Aktualizace dat z CSV souboru - VYŘEŠENO

a nakonec zlepšovák se zjištěním obou rozměrů kopírované tabulky trochu jinou metodou:

Sub vloz_csv

dim doc as object, tempdoc as object, list as object, csvlist as object
dim adresa as string
dim arg1(2) as new com.sun.star.beans.PropertyValue
dim pole(1) as integer

doc = thisComponent
list = doc.getCurrentController.getActiveSheet()

adresa = convertToURL(PickFile())

with com.sun.star.sheet.CellFlags
	list.ClearContents(.VALUE or .STRING or .DATETIME)
end with

arg1(0).Name = "FilterName"
arg1(0).Value = "Text – txt – csv (StarCalc)" 'název filtru
arg1(1).Name = "FilterOptions"
arg1(1).Value = "44,34,76,1" '44=čárka 59=středník, 34=uvozovky, 76=UTF-8,1=první řádek
arg1(2).Name = "Hidden"
arg1(2).Value = True

tempDoc = starDeskTop.LoadComponentFromURL(adresa," ",0,arg1())
csvlist = tempDoc.Sheets.GetByIndex(0)

pole() = split(getArea(csvlist))

zdroj = csvlist.getCellRangeByPosition(0, 0, pole(1), pole(0)).getDataArray

tempDoc.close(True)

list.getCellRangeByPosition(0, 0, pole(1), pole(0)).setDataArray(zdroj)

msgbox ("Fajn",0,"Info")

End Sub

Function getArea(oSheet as Object) as String
Dim oCell As Object
Dim oCursor As Object
Dim aAddress As Variant
oCell = oSheet.GetCellbyPosition( 0, 0 )
oCursor = oSheet.createCursorByRange(oCell)
oCursor.GotoEndOfUsedArea(True)
aAddress = oCursor.RangeAddress
getArea = aAddress.EndRow & " " & aAddress.EndColumn
End Function

Editoval ludviktrnka (8. 2. 2017 22:34:19)


LibreOffice 5.4.

Offline

Zápatí