dbf-Datei schnell in Excel-Blatt kopieren

Nutzung, Komponenten, .NET

Moderator: Moderatoren

Antworten
Benutzeravatar
Christof
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 265
Registriert: Mo, 01. Okt 2007 17:14
Wohnort: Bedburg
Hat sich bedankt: 1 Mal
Danksagung erhalten: 1 Mal

dbf-Datei schnell in Excel-Blatt kopieren

Beitrag von Christof »

Hallo Leute,

ich probiere im Moment etwas mit ActiveX rum. Geärgert hat mich immer, dass ein Übertrag einer relativ kleinen DBF-Datei in ein bestehendes Excel-Sheet so lange dauert. Ich wollte aber auch nicht aus der Excel-Anwendung auf die DBF zugreifen.

Mit dem kleinen Trick über die Zwischenablage geht das richtig fix. Naja, vielleicht nix Neues für die meisten Profis hier. Ich war jedenfalls froh, das ich es herausgefunden habe.
Wer's also brauchen kann oder wissen will...

Code: Alles auswählen

*****************************************************************************
*
* Ausgabe der Ergebnis.dbf in eine Excel-Tabelle
*
*****************************************************************************
#include "Appevent.ch"
#include "Gra.ch"
#include "Xbp.ch"
#include "std.ch"
#include "common.ch"
#include "topdown.ch"
#include "Xbpdev.ch"
#include "dmlb.ch"
#include "activex.ch"
#include "excel.ch"


//////////////////////////////////////////////////////////////////////
// Main entry point of the application
//////////////////////////////////////////////////////////////////////
Function  ProFi
LOCAL oExcel, oBook, oSheet
LOCAL cUebergabe:="", oClipboard


oDlg2 := tdModal(7,34,,,20,,,.T.)
oDlg2:title := "ProFi-Bericht erstellen..."
oDlg2:create()
oDlg2:setModalState(XBP_DISP_APPMODAL)
oDa2 := oDlg2:drawingarea

tdSay(1.5,2,'Ergebnisdaten nach ProFiErg.xls exportieren ...',oDa2,35,'c',,'10.Arial')
oProgBar1:=tdProgBar(2.5,2,oDa2,32,,tdRED)

use ergebnis new exclusive

  // Create the "Excel.Application" object
  oExcel := CreateObject("Excel.Application")
  IF Empty( oExcel )
    tdMsg("Excel ist nicht installiert!" )
    RETURN NIL
  ENDIF

  // Avoid message boxes such as "File already exists". Also,
  // ensure the Excel application is visible.
  oExcel:DisplayAlerts := .F.
*  oExcel:visible       := .T.  // soll im Hintergrund erfolgen

  // Add a workbook to the Excel application. Query for
  // the active sheet (sheet-1) and set up page/paper
  // orientation.
  oBook  := oExcel:workbooks:Open(cDataPath+"\ProFiErg.xls")
  oSheet := oBook:Worksheets(3)
  oSheet:Activate

  // Feed in the data from the table to the Cells
  // of the sheet.

  do while nr<1000 .and. !eof()
    cUebergabe+=' '+ergebnis->bezei+chr(9)
    cUebergabe+=tdFixUp(ergebnis->gesamt,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->summe,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t1 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t2 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t3 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t4 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t5 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t6 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t7 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t8 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t9 ,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t10,15,"",",",2)+chr(9)
    cUebergabe+=tdFixUp(ergebnis->t11,15,"",",",2)+chr(9)

    cUebergabe+=chr(13)+chr(10)
    DbSkip(1)
  ENDDO

  close Ergebnis

  oClipboard:=xbpClipboard():new():create()
  oClipboard:Open()
  oClipboard:Clear()
  oClipboard:SetBuffer(cUebergabe)
  oClipboard:Close()
  oClipboard:destroy()

  oSheet:Cells(2,1):select()
  oSheet:Paste()

  Sleep(10)

  oSheet := oBook:Worksheets(1)
  oSheet:Activate

  // Save workbook as ordinary excel file.
  oBook:Save()

  // Quit Excel
  oExcel:Quit()
  oExcel:Destroy()

RETURN NIL
Oh ähem, die Funktion 'tdFixUp' formatiert eine Zahl als Text und tauscht den Dezimalpunkt gegen ein Komma aus. Ist aus der TopDown-Lib entnommen und von mir modifiziert. Kann man aber sicher locker mit PADL() und StrTran() nachbilden.

Ach ja, mit der Steuerung einer Powerpoint-Show kämpfe ich noch. Aufrufen etc. funktioniert. Probleme machen noch die Verknüpfungen. Die sollen automatisch - ohne das der Anwender das merkt - aktualisiert werden. Aber das kriege ich auch noch raus. :blob5:

Gruß

Christof
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Beitrag von brandelh »

Hi Christof,

deine Inspiration ist wirklich Gold wert (leider habe ich keines, sonst würde ich es dir geben ;-) ) ...

Ich habe hier mal mit meiner großen Datei auf diese Art und Weise eine Excel Datei erzeugt ...

DBF Lastrec() : 298.551
Size etwa: 480 MB

Index mit scope -> export von etwa 180.000 Datensätzen nach Excel.
50.000 je Sheet, alles in eine XLS (max. 65000 Zeilen je Sheet).

In knapp 3 Minuten war die XLS mit 192 MB fertig.

Das ist Rekord :!: und somit meine neue Exportmethode von DBF nach Excel.

Die Datumsfelder habe ich übrigens als Zahl übergeben und die Spalte als Datum formatiert ...
Gruß
Hubert
Benutzeravatar
Christof
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 265
Registriert: Mo, 01. Okt 2007 17:14
Wohnort: Bedburg
Hat sich bedankt: 1 Mal
Danksagung erhalten: 1 Mal

Beitrag von Christof »

Hallo Hubert,

na super :!: Danke für die Blumen! Ein paar "Streicheleinheiten" sind manchmal viel mehr wert als Gold :wink:

:D Freut mich wirklich, dass es so prima funktioniert. Ich hatte schon etwas Bedenken wg. der großen Menge an Daten.

Ich bekomme hier immer so viele Hilfen, Hinweise und Tipps. Schön, dass ich mal was zurückgeben konnte.


Gruß

Christof
Gerd König
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 193
Registriert: Fr, 09. Jun 2006 7:52
Wohnort: Nähe Sömmerda

Re: dbf-Datei schnell in Excel-Blatt kopieren

Beitrag von Gerd König »

Hallo Christof,

gestern bin ich auf Deinen Thread gestoßen.

Bisher habe ich Excelsheets immer Zelle für Zelle generiert, was ewig gedauert hat. Um das bei Sheet mit sehr vielen Zeilen zu beschleunigen, bin ich alternativ den Umweg über eine csv-Datei gegangen.


Aber Dein Vorschlag ist wirklich effektiv!

Allerdings exportiere ich i.d.R. nicht aus einer DBF sondern aus einem Datenarray. Ich übergebe meiner Funktion zusätzlich ein Headerarray (Aufbau entsprechend DbStruct()).

Bevor ich die Daten schreibe, formatiere ich die Tabelle (das dauert ca. 2-3 Sekunden) und schreibe den Tabellenkopf

Code: Alles auswählen

   cSheetData:=""                              //Zeichenkette für Zwischenablage
   nMaxCol :=Len(aHeader)
   FOR i=1 TO nMaxCol
      IF aHeader[i,2+nOffset]=="N"
         IF aHeader[i,4+nOffset]=0
            cX:="0"
         ELSE
            cX:="0,"+Replicate("0",aHeader[i,4])
         ENDIF
      ELSE
         cX:="@"
      ENDIF
      oSheet:columns(i):numberFormat:=cX
      oSheet:cells(1,i):font:Bold:=.T.
      cSheetData+=aHeader[i,1]+Chr(9)
   NEXT
   cSheetData+=CRLF
Anschließend schreibe ich die Zeilen:

Code: Alles auswählen

   FOR i:=1 TO Len(aData)
      FOR j:=1 TO nMaxCol
         IF ValType(aData[i,j])=="C"
            cX:=aData[i,j]
         ELSEIF ValType(aData[i,j])=="N"
            cX:=StrTran(AllTrim(Str(aData[i,j])),".",",")
         ELSEIF ValType(aData[i,j])=="L"
            cX:=IIf(aData[i,j],"Ja","Nein")
         ELSEIF ValType(aData[i,j])=="D"
            cX:=DToC(aData[i,j])
         ELSE
            cX:=""
         ENDIF
         cSheetData+=cX+Chr(9)
      NEXT
      cSheetData+=CRLF
   NEXT
Dann folgt das Kopieren ab Zelle {1,1}

Code: Alles auswählen

   oClipboard:=xbpClipboard():new():create()
   oClipboard:open()
   oClipboard:clear()
   oClipboard:setBuffer(cSheetData)
   oClipboard:close()
   oClipboard:destroy()
   oSheet:cells(1,1):select()
   oSheet:paste()
Zum Schluß führe ich noch eine Spaltenanpassung durch und setze die Markierung auf die erste Zelle in der nächsten freien Zeile:

Code: Alles auswählen

   FOR i:=1 TO nMaxCol
      oSheet:columns(i):autoFit()
   NEXT
   oSheet:cells(2+Len(aData),1):select()
Herzlichst
Gerd
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Re: dbf-Datei schnell in Excel-Blatt kopieren

Beitrag von AUGE_OHR »

Gerd König hat geschrieben: Bisher habe ich Excelsheets immer Zelle für Zelle generiert, was ewig gedauert hat.
...
Allerdings exportiere ich i.d.R. nicht aus einer DBF sondern aus einem Datenarray.
Ich übergebe meiner Funktion zusätzlich ein Headerarray (Aufbau entsprechend DbStruct()).

Bevor ich die Daten schreibe, formatiere ich die Tabelle (das dauert ca. 2-3 Sekunden) und schreibe den Tabellenkopf

Code: Alles auswählen

   cSheetData:=""                              //Zeichenkette für Zwischenablage
   nMaxCol :=Len(aHeader)
   FOR i=1 TO nMaxCol
   NEXT
   cSheetData+=CRLF
du hast doch (schon) alles im Array. Das mit dem Header ist ja noch ok so, aber warum
übergibst du den "Rest" nicht gleich als Array ?

Code: Alles auswählen

oSheet:range( "A6:F" + LTRIM( STR( 6 + nTreff ) ) ) :value := aData
in diesem Fall wäre
der "Datenbereich" von A6:Fxxx.

probieren es mal aus :)
gruss by OHR
Jimmy
Gerd König
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 193
Registriert: Fr, 09. Jun 2006 7:52
Wohnort: Nähe Sömmerda

Re: dbf-Datei schnell in Excel-Blatt kopieren

Beitrag von Gerd König »

Hallo Jimmy,

Du hast recht. =D>

Die ganze Aufbereitung der Daten kann ich mir sparen.

Ich mache das jetzt so, daß ich nur den Tabellenkopf per Clipboard einfüge.

Die Daten schreibe ich dann mit

Code: Alles auswählen

oSheet:range( "A2:"+Chr(nMaxCol+64)+AllTrim(Str(1+Len(aData)))):value:=aData
unmittelbar vor der Spaltenanpassung.
Ich habe echt nicht gwußt, daß Datenbereiche per Array an Excel übergeben werden können.

Gruß
Gerd
stevie
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 417
Registriert: Mo, 17. Sep 2007 18:20
Wohnort: Senftenberg
Kontaktdaten:

Re: dbf-Datei schnell in Excel-Blatt kopieren

Beitrag von stevie »

Tipp: der Thread wäre reif für die Wissensdatenbank
Viele Grüße
Stevie
Benutzeravatar
brandelh
Foren-Moderator
Foren-Moderator
Beiträge: 15695
Registriert: Mo, 23. Jan 2006 20:54
Wohnort: Germersheim
Hat sich bedankt: 65 Mal
Danksagung erhalten: 33 Mal
Kontaktdaten:

Re: dbf-Datei schnell in Excel-Blatt kopieren

Beitrag von brandelh »

Gerd König hat geschrieben: Ich habe echt nicht gwußt, daß Datenbereiche per Array an Excel übergeben werden können.
Gruß
Gerd
so ging es mir auch, bis TOM vor einiger Zeit mal ein solches Beispiel gebracht hat.
Gruß
Hubert
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12906
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 45 Mal

Re: dbf-Datei schnell in Excel-Blatt kopieren

Beitrag von AUGE_OHR »

Gerd König hat geschrieben: Ich habe echt nicht gwußt, daß Datenbereiche per Array an Excel übergeben werden können.
public.xbase++.activex
17. März 2006
Re: Writing to Excel is too slow - Sample.xls (0/1)
jörg bertram
gruss by OHR
Jimmy
Antworten