mandag den 10. oktober 2016

Indlæse en fil linje for linje (makro)

I en tidligere artikel beskrev jeg hvordan vi kan importere en CSV-fil igennem LibreOffices importfilter. Artiklen kan du finde her: http://libreofficedk.blogspot.dk/2016/10/mere-regnearks-gymnastik-makro.html

Der er flere fordele ved den metode, men der er også ulemper. F.eks. kan det være besværligt at finde de korrekte parametre til importen, og vi har ikke helt kontrol over hvad der egentlig sker. En konsekvens er blandt andet, at vi ikke kan importere data ind i et eksisterende regneark uden at 'ødelægge' arkets layout. Det viser sig ved at formatering af arket bliver overskrevet.

I denne artikel vil jeg beskrive en anden metode, hvor vi indlæser data linje for linje og behandler indholdet. Hvilken metode du synes er bedst er op til dig, men undervejs lærer vi også lidt mere om programmering i LibreOffice.

Vi indleder makroen på samme måde som vi har set tidligere:
filename= "file:///home/leif/Skrivebord/Calc/Statistik.csv"
my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count
If NOT my_sheets.hasbyName("Statistik") Then
    my_sheets.insertNewByName("Statistik", antal)
End If
the_sheet = my_sheets.getByName("Statistik")


Der burde ikke være ret mange overraskelser i den del. Vi har nu kontrol over dokumentet, og vi har et ark at arbejde med.

Nu skal vi så til at arbejde med filen. Først skal vi have lavet en kanal at indlæse filen igennem. FreeFile er en kommando, som giver os et heltal, som udtrykker første ledige kanal. Så åbner vi filen (variablen filename blev defineret tidligere) og vi vælger metoden 'For Input', hvilket betyder at vi læser, vi skriver ikke (Input = read, Output = write). Til sidst starter vi et loop (fortsæt så længe vi ikke er færdige):
r=0    'Nulstil variabel for rækkenummer
n = FreeFile
Open filename For Input As #n
Do While NOT EOF(n)


Nu starter så logikken
  • r er rækkenummer (0...n)
  • c er kolonnenummer (0-1)
Vi får data ind fra filen celle for celle, så vi må hele tiden kontrollere om vi er i kolonne 0 (datokolonnen) eller 1 (værdikolonnen).
Vi skal også holde øje med om vi er i række 0, fordi så er det kolonneoverskriften vi har med at gøre.

Kolonneoverskriften er tekst, og skal håndteres med .String
Første kolonne er en dato, men udtrykt som tekst. Teksten skal lige konverteres til en brugbar dato og indsættes med .Value.
Anden kolonne er tal, som også indsættes med .Value.

For c = 0 to 1    'Tæl mellem første og anden kolonne
    Input #n, s    'Læs data
    my_cell = the_sheet.getCellByPosition(c,r)    'Peg på den rigtige celle
    If r=0 then    'Hvis rækkenummeret er 0
        my_cell.String=s    'Det er en streng
    Else
        If c=0 Then    'Det er en dato
            s=DateValue(s)          'Tekst til datoformat
            my_cell.NumberFormat=36    'Cellen får datoformat
        End if
        my_cell.Value=s

    End if
Next c        'Næste kolonne
r=r+1        'Læg en til rækkenummeret
Loop        'Afslut loopet


Læs mere om håndtering af datoer i Calc her: http://libreofficedk.blogspot.dk/2016/10/datoer-i-calc-med-makroer.html 
Læs mere om datoformat i i makroer her: http://libreofficedk.blogspot.dk/2016/10/lidt-om-datoer-i-makro.html

Nu mangler vi faktisk kun at lukke for vores datakanal:
Close #n

Hele makroen:
REM  *****  BASIC  *****

Sub Main
filename= "file:///home/leif/Skrivebord/Calc/Statistik.csv"
my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count
the_sheet=checksheet("Statistik", 255, 3, 101)

n = FreeFile
r=0
Open filename For Input As #n
Do While NOT EOF(n)

    For c = 0 to 1
        Input #n, s
        my_cell = the_sheet.getCellByPosition(c,r)
  
        If r=0 then
        my_cell.String=s
        Else
        If c=0 Then
            s=DateValue(s)
            my_cell.NumberFormat=36  
        End if
        my_cell.Value=s

        End if
'       Her lidt ekstra guf for øjet
        If isEven (r) then
        my_cell.CellBackColor=rgb(100,100,100)
        my_cell.CharColor=rgb(255,255,255)
        else
        my_cell.CellBackColor=rgb(250,250,250)
        End if
    Next c
    r=r+1

Loop
Close #n
End Sub


Resultatet:

Efterfølgende har jeg oprettet et diagram, som visualiserer de første 100 rækker fra mit regneark. Diagrammet opdateres automatisk hver gang jeg indlæser nye data fra min CSV-fil: