Liczba linijek w pliku tekstowym

0

Witam
Mam plik tekstowy, w którym zapisane może być od tysiąca do nawet około miliona linijek następnie tworze tablice, która musi mieć długość taką jak ilość linijek w pliku tekstowym i musze w jakiś bardzo szybki sposób uzyskać liczbę linijek w pliku, aby skonfigurować długość tablicy. Więc macie może jakiś szybki sposób na uzyskanie tej liczby linijek w pliku?

0

Nie ma trzeba przebiec po pliku i policzyc CRLF. Co zresztą nie raz było na forum.

<font color="green">//edit Ups to co poniżej jest bez sensu bo ty zdaje sie nie ładujesz tego tekstu do tej tablicy..</span>

Albo możesz lecieć w pętli repeat..until, zwiekszać wielkość tablicy powiedzmy o 1000, ładowac 1000 linijek i tak w kółko. A jak gdzieś w ostatnim obrocie plik sie skończy, to przykrawasz wielkość tablicy do ostatecznego rozmiaru. Tak zadziała szybciej niz powiększanie tablicy co 1, i być może szybciej niż najpierw policzenie CR/LF a potem tworzenie tablicy.

A dlaczego w ogóle ładujesz do tablicy a nie do TStringList?

0

W sumie może umieszczę kod i opisze dokładnie, o co mi chodzi mianowicie w pliku testowym mam dane zapisane w trzech kolumnach i musze je przepisać do tablicy trzy rekordowej, po czym będą zaraz po odczycie wykonywane różne operacje matematyczne na tejże tablicy. Z tym, że odczyt trwa właśnie bardzo długo a dokładniej trochę dziwnie się program zachowuje, bo za pierwszym razem, gdy chce odczytać to ten czas jest jeszcze do przyjęcia, ale za drugim, gdy wcześniej tablica była już wypełniona odczyt trwa nawet do 20s a czemu tak się dzieje nie wiem. Może ktoś będzie miał jakąś ciekawą poradę jak ten proces przyśpieszyć

type

  Timpuls=packed record
  im :single;
  re :single;
  t  :single;
  end;
  arrimpuls=array of timpuls;

  TxtImpuls=packed record           //tego rekordu używam do przepisywania 
  im :string;                                 //bo wtedy jest szybciej
  re :string;
  t  :String;
  end;

Procedure import(var tablica:arrimpuls; Opendialog:Topendialog);
var
f:textfile;
linijka:string;                  //jedna cała linijka w pliku
pierwszalinijka:string;      //pierwsza linia pliku ktura zawiera inne informacje
i:integer;
cc:txtimpuls;                    //zmienna do przepisywania z pliku txt
BEGIN
  if OpenDialog.Execute then
    begin
      AssignFile(f,OpenDialog.FileName);
      Reset(f);
      readln(f,pierwszalinijka);    //czyta pierwsza linie ktora nie zawiera danych
      i:=0;
      DecimalSeparator:='.';
      while not Eof(f) do
      begin
        setlength(tablica,i+1);
        readln(f,linijka);                  //odczyt calej linijki

        cc.t:='';
        cc.t:=Copy(linijka,1,16);       //odczyt z pierwszej kolumny
        tablica[i].t:=strtofloat(cc.t);

        cc.re:='';
        cc.re:=Copy(linijka,17,16);     //odczyt z drogiej kolumny
        tablica[i].re:=strtofloat(cc.re);

        cc.im:='';
        cc.im:=Copy(linijka,33,length(linijka)-32);//odczyt z trzeciej kolumny
        tablica[i].im:=strtofloat(cc.im);

        inc(i);
      end;
      DecimalSeparator:=',';
      closefile(f);
    end;
END;

Aha no i dodam jeszcze ze właśnie za ten długi czas odczytu jest odpowiedzialna właśnie deklaracja długości tablicy, która znajduje się w pętli.

0

Tak jak pisałem: nie powiekszaj długości tablicy o 1, tylko w duzych paczkach. Częste powiększanie o jeden stwarza duże problemy menedżerowi pamięci, zwłaszcza, jesli tablica jest duża.

Problemy za drugim razem mogą wynikać z poszatkowania pamieci po pierwszym razie.

Ja bym probował mniej więcej tak jak poniżej (kodu nie testowałem)

Zwróc uwage, że oprócz zmiany powiekszania tablicy usunąłem zmienną cctxtimpuls, która nie jest potrzebna. Rozwaz też zmianę Timpuls z packed record na record - packed record zajmuja mniej miejsca, ale są wolniejsze.

procedure import(var tablica:arrimpuls; Opendialog:Topendialog);
var
  f:textfile;
  linijka:string;                            //jedna cala linijka w pliku
  pierwszalinijka:string;              //pierwsza linia pliku która zawiera inne informacje
  i:integer;
const
  StepSize=1000;       //o tyle bedziemy zwiekszac tablice zamiast o 1, spróbuj rózne wartości

begin
  if OpenDialog.Execute then
    begin
      AssignFile(f,OpenDialog.FileName);
      Reset(f);
      readln(f,pierwszalinijka);             //czyta pierwsza linie ktora nie zawiera danych
      DecimalSeparator:='.';

      SetLenght(tablica,0)   //wyczyszczenie tablicy z poprzedniego razu
      repeat
        SetLength(tablica,Length(Tablica)+StepSize);

        for i:=High(Tablica)-Pred(StepSize) to High(Tablica) do     //tu moglem sie kopnac o 1, sprawdz bo mi się nie chciało
           if not Eof(f) then
           begin
             readln(f,linijka);                             //odczyt calej linijki

             Tablica[i].t:=StrToFloat(Copy(linijka,1,16));
             Tablica[i].re:=StrToFloat(Copy(linijka,17,16);
             Tablica[i].im:=StrToFloat(Copy(linijka,33,length(linijka)-32));
             //widze ze zakladasz rowna szerokosc kolumn, wtedy copy jest ok
             //jesli plik bedzie mial rozne szerokosci kolumn i bedzie trzeba
             // szukac po separatorach, uzyj funkcji ExtractStrings
           end
           else
           begin
              SetLength(Tablica,i);  //wyrównanie nadmiarowego rozmiaru tablcy przy wychodzeniu, tu tez sprawdz blad o 1
              DecimalSeparator:=',';
              CloseFile(f);
              Exit;  //tylko tędy wychodzimy z procedury!
           end;
    until False;
end;
0

Dzięki wielkie pomogło tylko ze musze dalej używać rekordu tekstowego do przepisywania, bo jak przepisuje bezpośrednio to się kaszanka robi tak jak wcześniej, za pierwszym razem jest szybciutko a za następnymi trzeba długo czekać, lub czasami nawet nie przepisze, a czemu tak się dzieje nie wiem i przyznam ze dziwi mnie to. Ale ogólnie efekt, który chciałem nawet z tym rekordem tekstowym uzyskałem, klikom na przycisk i przepisanie teraz nie trwa nawet sekundy. Jeszcze raz dziękuje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1