Avatar billede jaweni Nybegynder
07. april 2008 - 14:42 Der er 12 kommentarer og
1 løsning

BlockRead fra csv/txt-fil (Delphi2)

Hej derude,

mit problem er, at jeg er ude for,
at skulle indlæse txt/cvs-filer
på op imod 400.000 kb ind i en Memo-box.

Dette er en meget laaansommelig affære.

Har hørt om BlockRead; men hvordan
funker det?
Helst ikke gode råd om, at opgradere til
Delphi-X. Det har jeg ikke brug for,
da jeg er minimalist. KISS***
(Jo mindre, jo bedre).
Kan det gøres uden, så gør det.

Med mange gode hilsener
jaweni
Avatar billede kroning Nybegynder
07. april 2008 - 15:25 #1
Jeg har testet på en text fil på 100MB og der var blockread kun ca. 1 sek. hurtigere, her er koden:

var
  x,i : integer;
  fil : file;
  buffer : string; //array of char;
begin
  assignfile(fil,'C:\ditfilnavn');
  reset(fil,4096);
  x:=filesize(fil);

  setlength(buffer,x*4096);
  blockread(fil,buffer[1],x,i);
  closefile(fil);

  memo1.Lines.Text:=buffer;
end;
Avatar billede kroning Nybegynder
07. april 2008 - 15:27 #2
Og et svar hvis du kan bruge det.
Avatar billede kroning Nybegynder
07. april 2008 - 15:28 #3
Ja 1 sek. hurtigere siger jo intet i sig selv :-)

Men uden blockread tog det ca. 10 sek.
Med blockread tog det ca. 9 sek.
Avatar billede jaweni Nybegynder
07. april 2008 - 16:18 #4
Hej,
hvad med linie-længden?
er den uendelig? Eller indenfor
Memo-boxens bredde?

Jeg spørger "dumt".
Avatar billede kroning Nybegynder
07. april 2008 - 17:57 #5
Ved ikke helt hvad du mener? Teksten bliver sat ind i memo´en som den er, der bliver ikke lavet noget om. Du skal self. have begge scroll bar slået til for at undgå ord deling
Avatar billede martinlind Nybegynder
07. april 2008 - 17:57 #6
Dette er KISS, med fuld skue og overliggende knastaksel ;-)

var
  f : TStringList;
begin
  f := TStringList.Create;
  f.LoadFromFile('C:\ditfilnavn');
  Memo1.Lines := F;
end;
Avatar billede kroning Nybegynder
07. april 2008 - 18:15 #7
martinlind > Hvad er forskellen på din kode og:
Memo1.Lines.LoadFromFile('c:\ditfilnavn'); ?
Avatar billede martinlind Nybegynder
07. april 2008 - 20:59 #8
hvis du læser direkte ind i lines skal du 1. stoppe skræmopdatering og så ved jeg ikke hvad der ellers foregår i en memo, men jeg ved at en TStringList er lynene hurtig til at læse en "flad" fil ind, langt hurtigere en gammeldaws file rutiner :-)
Avatar billede kroning Nybegynder
07. april 2008 - 21:24 #9
Det er rigtig at TStringList er meget hurtigere til at læse ind, på min computer 2 sek. i forhold til 10 sek. hvis memoen skal indlæse.
Men det gå galt når jeg kører linien:
Memo1.Lines := F;
så hænger programmet, jeg afbrød efter 3 minutter?

Til jaweni: Det er vigtig at du sætter en horizontal scrollbar på eller sætter WordWrap til false da det ellers kan tage 2-3 gange så lang tid hvis der er mange linier der skal deles.
Avatar billede martinlind Nybegynder
07. april 2008 - 21:58 #10
Skal ikke kunne sige hvad der sker når du sætter lines, det plejer ikke at være et problem.

Men jeg bruger TStringList til ALT, den er en rigtig god og flexibel classe
Avatar billede hrc Mester
07. april 2008 - 23:45 #11
Jeg hader IBMs bærbare! Hvorfor skal de bytte rundt på <ctrl>- og <fn>-tasterne og hvorfor skal de placere <back>- og <forward>-taster klods op ad piletasterne? Sag og bryggede noget klogt sammen og rammer så den forkerte knap. Exit gik det indlæg. Maskinen larmer også. Hvis ikke det var en foræring havde jeg nok en smartere...

Nok om HAL og dens uheldige design.

Hvis din Ur-delphi har en TListView (findes i Win32-fanebladet (unit ComCtrls)) kan du lave et virtuelt listview. Teknikken er at man har en bagvedliggende liste som TListViewet plukker fra når de skal bruges. Hvis listviewet viser 10 linjer tegner den kun de 10. Det er lynende hurtigt og det bruger ikke meget ram. Jeg indlæste 200000 linjer på 156ms, dvs. 1/6 sekund. Hvis data skal vises på skærmen (og ikke editeres) er det den hurtigste måde:

DFM-Filen:
----------
object frmMain: TfrmMain
  Left = 0
  Top = 0
  Caption = 'Virtuel listview'
  ClientHeight = 301
  ClientWidth = 467
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object lvData: TListView
    Left = 0
    Top = 41
    Width = 467
    Height = 260
    Align = alClient
    Columns = <
      item
        Caption = 'Data'
        Width = 300
      end>
    OwnerData = True
    RowSelect = True
    TabOrder = 0
    ViewStyle = vsReport
    OnData = lvDataData
    OnDataHint = lvDataDataHint
    ExplicitLeft = 96
    ExplicitTop = 64
    ExplicitWidth = 250
    ExplicitHeight = 150
  end
  object pHeader: TPanel
    Left = 0
    Top = 0
    Width = 467
    Height = 41
    Align = alTop
    BevelOuter = bvNone
    TabOrder = 1
    ExplicitLeft = 160
    ExplicitTop = 24
    ExplicitWidth = 185
    object btnTest: TButton
      Left = 8
      Top = 8
      Width = 75
      Height = 25
      Caption = 'Test'
      TabOrder = 0
      OnClick = btnTestClick
    end
  end
end

PAS-Filen:
----------
unit FMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, ComCtrls, StdCtrls;

type
  TfrmMain = class(TForm)
    lvData: TListView;
    pHeader: TPanel;
    btnTest: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnTestClick(Sender: TObject);
    procedure lvDataData(Sender: TObject; Item: TListItem);
    procedure lvDataDataHint(Sender: TObject; StartIndex, EndIndex: Integer);
  private
    fList: TStringList;
  public
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.btnTestClick(Sender: TObject);
var
  TickStart: cardinal;
begin
  TickStart := GetTickCount;
  try
    fList.LoadFromFile('c:\test.txt');
    lvData.Items.Count := fList.Count; // Initiér listview.
  finally
    MessageDlg(format('Indlæst %d linjer på %d ms',[fList.Count,GetTickCount - TickStart]), mtInformation, [mbOK], 0);
  end;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  fList := TStringList.Create;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  lvData.Items.Clear; // Skal også nulstilles igen
  fList.Free;
end;

procedure TfrmMain.lvDataData(Sender: TObject; Item: TListItem);
begin
  Item.Caption := fList[Item.Index];
end;

procedure TfrmMain.lvDataDataHint(Sender: TObject; StartIndex, EndIndex: Integer);
begin
  // Angiver det næste interval der skal vises. Hvis data er cached til disk er det
  // en god idé at hente det ind i hukommelsen her.
  // Min TStringList er allerede der så der er ingen grund til at lave noget her.
end;

end.

--------------- o ---------------

I DFM-filen er der sikkert mange properties din delphi ikke kan håndtere. Det letteste er nok at lave formen, med dens komponenter og derefter kopiere pas-koden ind.
Avatar billede hrc Mester
07. april 2008 - 23:53 #12
Indlæste 1.500.000 linjer på 8 sekunder; det er tiden det tog TStringList at indlæse. Listviewet foretog sig intet.

I ovenstående destructor bruger jeg

  lvData.Items.Clear;

til at rydde listviewet, så der ikke kommer events til en liste der er blevet frigivet. Det viser sig at det er meget hurtigere at sætte count = 0;

  lvData.Items.Count := 0;
Avatar billede jaweni Nybegynder
22. april 2008 - 13:47 #13
Performance blev betydeligt bedre; men ved store filer
var der lidt ventetid, inden linierne vistes i memoen.

Det skyldes muligvis min maskines ydeevne.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester