IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

[D7] Meilleure façon d'écrire fichier Excel


Sujet :

Langage Delphi

  1. #1
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut [D7] Meilleure façon d'écrire fichier Excel
    Bonjour à tous,

    Je dois écrire un fichier Excel avec beaucoup de données. Environ 50 colonnes pour 100-200k lignes.
    J'ai écrit ce programme pour tester le fonctionnement.

    Cela fonctionne, mais demande beaucoup trop de temps.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    const
      NB_LINS: Integer = 100000;
      NB_COLS: Integer = 50;
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      LCID: Cardinal;
      myxlApp: TExcelApplication;
      myxlBook: TExcelWorkbook;
     
      xlFile: string;
      i, j: Integer;
    begin
      LCID := GetUserDefaultLCID;
     
      myxlApp := nil;
      myxlApp := TExcelApplication.Create(nil);
      myxlApp.Connect;
      myxlApp.Visible[LCID] := False;
      myxlApp.DisplayAlerts[LCID] := False;
      myxlApp.ScreenUpdating[LCID] := False;
     
      myxlApp.Workbooks.Add(EmptyParam, LCID);
      myxlBook := TExcelWorkbook.Create(myxlApp);
      myxlBook.ConnectTo(myxlApp.ActiveWorkbook);
     
      try
        ProgressBar1.Max := NB_LINS;
        ProgressBar1.Position := 0;
        for i:=1 to NB_LINS do
        begin
          ProgressBar1.Position := i;
          for j:=1 to NB_COLS do
     
            myxlApp.Cells.Item[i, j].Value := Format('Ligne %d - Colonne %d', [i, j]);
        end;
     
        xlFile := Format('%smy_file.xlsx',[getMyDocs]);
        myxlBook.Close(True, xlFile);
      finally             
        myxlBook.Disconnect;
        FreeAndNil(myxlBook);
     
        myxlApp.Disconnect;
        FreeAndNil(myxlApp);
     
        ShowMessage('Terminé !');
      end;
    end;
    Quelle est la meilleure façon pour écrire rapidement autant de données ?
    Il faut que ce soit un fichier Excel *.xlsx et pas un csv.

    Merci de vos conseilles.

  2. #2
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 346
    Points : 3 124
    Points
    3 124
    Par défaut
    Bonjour,

    je ne sais pas si c'est plus rapide, mais il est possible d'utiliser des TStream pour créer des fichiers Excel. Par exemple pour sauver une grille dans un fichier Excel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    procedure XlsWriteCellLabel(XlsStream: TStream; const ACol, ARow: Word;
      const AValue: string);
    var
      L: Word;
    const
      {$J+}
      CXlsLabel: array[0..5] of Word = ($204, 0, 0, 0, 0, 0);
      {$J-} 
    begin
      L := Length(AValue);
      CXlsLabel[1] := 8 + L;
      CXlsLabel[2] := ARow;
      CXlsLabel[3] := ACol;
      CXlsLabel[5] := L;
      XlsStream.WriteBuffer(CXlsLabel, SizeOf(CXlsLabel));
      XlsStream.WriteBuffer(Pointer(AValue)^, L);
    end;
     
     
    function SaveAsExcelFile(AGrid: TStringGrid; AFileName: string): Boolean;
    const
      {$J+} CXlsBof: array[0..5] of Word = ($809, 8, 00, $10, 0, 0); {$J-}
      CXlsEof: array[0..1] of Word = ($0A, 00);
    var
      FStream: TFileStream;
      I, J: Integer;
    begin
      FStream := TFileStream.Create(PChar(AFileName), fmCreate or fmOpenWrite);
      try 
        CXlsBof[4] := 0;
        FStream.WriteBuffer(CXlsBof, SizeOf(CXlsBof));
        for i := 0 to AGrid.ColCount - 1 do
          for j := 0 to AGrid.RowCount - 1 do 
            XlsWriteCellLabel(FStream, I, J, AGrid.cells[i, j]);
        FStream.WriteBuffer(CXlsEof, SizeOf(CXlsEof)); 
        Result := True;
      finally
        FStream.Free;
      end;
    end;
    Utilisation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    SaveAsExcelFile(StringGrid1,'c:\testxls.xls');
    C'est du Xls, mais ça doit marcher pour du Xlsx

    A+
    Charly

  3. #3
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    Merci de ta réponse.

    Je viens de tester, voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    unit Main;
     
    interface
     
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls;
     
    type
      TForm1 = class(TForm)
        Button1: TButton;
        ProgressBar1: TProgressBar;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
        procedure XlsWriteCellLabel(XlsStream: TStream; const ACol, ARow: Word; const AValue: string);
        function SaveAsExcelFile(AFileName: string): Boolean;
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      SaveAsExcelFile('C:\temp\fichier.xlsx');
      ShowMessage('Terminé');
    end;
     
    procedure TForm1.XlsWriteCellLabel(XlsStream: TStream; const ACol, ARow: Word;
      const AValue: string);
    var
      L: Word;
    const
      {$J+}
      CXlsLabel: array[0..5] of Word = ($204, 0, 0, 0, 0, 0);
      {$J-}
    begin
      L := Length(AValue);
      CXlsLabel[1] := 8 + L;
      CXlsLabel[2] := ARow;
      CXlsLabel[3] := ACol;
      CXlsLabel[5] := L;
      XlsStream.WriteBuffer(CXlsLabel, SizeOf(CXlsLabel));
      XlsStream.WriteBuffer(Pointer(AValue)^, L);
    end;
     
    function TForm1.SaveAsExcelFile(AFileName: string): Boolean;
    const
      {$J+} CXlsBof: array[0..5] of Word = ($809, 8, 00, $10, 0, 0); {$J-}
      CXlsEof: array[0..1] of Word = ($0A, 00);
      NB_LINES = 100000;
      NB_COLS = 50;
    var
      FStream: TFileStream;
      i, j: Integer;
    begin
      ProgressBar1.Max := NB_LINES;
      ProgressBar1.Position := 0;
      FStream := TFileStream.Create(PChar(AFileName), fmCreate or fmOpenWrite);
      try
        CXlsBof[4] := 0;
        FStream.WriteBuffer(CXlsBof, SizeOf(CXlsBof));
     
        for i := 0 to NB_LINES do
        begin
          ProgressBar1.Position := ProgressBar1.Position + 1;
          for j := 0 to NB_COLS do
            XlsWriteCellLabel(FStream, j, i, Format('Ligne %d - Colonne %d', [i,j]));
        end;
     
        FStream.WriteBuffer(CXlsEof, SizeOf(CXlsEof));
        Result := True;
      finally
        FStream.Free;
      end;
    end;
     
    end.
    Le traitement est rapide et le fichier est bien créé.
    Par contre, on ne peut pas l'ouvrir.

    Impossible d'ouvrir le fichier "fichier.xlsx" car son format ou son extension n'est pas valide. Vérifiez que le fichier n'est pas endommagé et que son extension correspond bien au format du fichier.

    C'est en fait bien un .xls qui est créé. On est donc limité à 65k lignes à l'ouverture du fichier.

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 469
    Points : 24 905
    Points
    24 905
    Par défaut
    Si il n'y a que de la données, le plus rapide, produire un fichier CSV puis le convertir via Excel en XSLX, c'est beaucoup plus rapide que via l'ajout en OLE

    https://www.developpez.net/forums/d1...i/#post6375536
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    Je dois mettre les données dans un fichier déjà existant en *.xlsx.
    Je ne peux pas utiliser de .csv.

  6. #6
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 064
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 064
    Points : 41 021
    Points
    41 021
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    à essayer les suites SMImport/SMExport de Scalabium avantage pas besoin d'avoir la suite MS Office installée.
    Le principe importer tout dans un clientdatatset (table mémoire ?), ajouter les données (append), exporter le clientdataset

    Perso avec les nouvelles versions je suis passé avec CData Excel (qui lui n'ouvre que les xlsx d'ailleurs) et je traite les tableaux avec des requêtes Firedac
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 469
    Points : 24 905
    Points
    24 905
    Par défaut
    Citation Envoyé par oneDev Voir le message
    Je dois mettre les données dans un fichier déjà existant en *.xlsx.
    Je ne peux pas utiliser de .csv.
    Il n'existerait pas un mécanisme de fusion de données Range.TextToColumns
    de vieux souvenirs de publipostage
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 429
    Points : 5 836
    Points
    5 836
    Par défaut
    un simple copier coller devrais suffire
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  9. #9
    Membre actif Avatar de oneDev
    Homme Profil pro
    dilettant
    Inscrit en
    Mars 2019
    Messages
    213
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : dilettant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2019
    Messages : 213
    Points : 222
    Points
    222
    Par défaut
    Merci de vos réponses.
    Je vais tester tout ça

    Citation Envoyé par SergioMaster Voir le message
    à essayer les suites SMImport/SMExport de Scalabium avantage pas besoin d'avoir la suite MS Office installée.
    Le principe importer tout dans un clientdatatset (table mémoire ?), ajouter les données (append), exporter le clientdataset
    Merci je vais tester

    Citation Envoyé par ShaiLeTroll Voir le message
    Il n'existerait pas un mécanisme de fusion de données Range.TextToColumns
    de vieux souvenirs de publipostage
    Je vais regarder de quoi il s'agit. Je ne connais pas

    Citation Envoyé par anapurna Voir le message
    un simple copier coller devrais suffire
    Dans l'absolu oui, mais nous devons fournir un système complet. le fonctionnement doit être auto du début à la fin.

  10. #10
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 346
    Points : 3 124
    Points
    3 124
    Par défaut
    Bonjour,

    Delphi a accès au presse-papier. Le copier-coller est possible par programme ?
    A+
    Charly

  11. #11
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 429
    Points : 5 836
    Points
    5 836
    Par défaut
    salut

    il est possible de sortir des états (avec un ou plusieurs onglets) formaté avec formule et encadrement sous ecxel
    en utilisant le copier coller pour les datas et ole pour le formatage

    c'est bien plus rapide que de le remplir cellule par cellule
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

  12. #12
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 429
    Points : 5 836
    Points
    5 836
    Par défaut
    Citation Envoyé par Charly910 Voir le message
    Bonjour,

    Delphi a accès au presse-papier. Le copier-coller est possible par programme ?
    A+
    Charly
    oui
    en faisant simplement cela

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     if (Length(Buffer) > 0) then
      begin
        Clipboard.Clear;
        Clipboard.AsText := Buffer;
        Buffer := '';
        BaseCell.Offset[Lig,Col].Select;
        ExcelApp.ActiveSheet.Paste;
      end;
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

Discussions similaires

  1. Réponses: 1
    Dernier message: 18/01/2010, 22h48
  2. Meilleure solution pour écrire dans un fichier Excel
    Par kastillio dans le forum LabVIEW
    Réponses: 10
    Dernier message: 02/11/2009, 09h27
  3. Réponses: 20
    Dernier message: 27/06/2006, 17h42
  4. [Excel] Écrire dans un fichier Excel existant
    Par Invité dans le forum Bibliothèques et frameworks
    Réponses: 5
    Dernier message: 01/05/2006, 16h06
  5. lire / écrire dans un fichier excel au format xml
    Par crisflo dans le forum Format d'échange (XML, JSON...)
    Réponses: 7
    Dernier message: 28/01/2006, 10h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo