Dość nietypowy problem z odczytem pliku

0

Witam. Pisząc wczoraj pewien program, do odczytu pewnego pliku natrafiłem na dość nietypowy problem. Chcąc dokładnie opisać mój problem , najpierw postaram się po krótce przedstawić specyfikacje pliku. Pierwsze co, nagłówek który liczy 40 bajtów, prócz pewnych danych które zawiera jest czterobajtowa wartość przedstawiająca liczbe poniższych wpisów, czy rekordów jak kto woli. Okay, odczytałem. Czas teraz odczytać zawarte tam rekordy. Każdy rekord składa się, z łańcucha znaków oraz dziesięciu wartościzmienno-przecinkowych. I tutaj zaskoczyło mnie to że długość łańcucha znaków(każdego rekordu), to również 4-bajtowa wartość, a nie 1 bajt jak to jest np przy String. Zatem pomyślałem że dynamiczna tablica char'ów, załatwi sprawę. Po długości łańcucha i samym łańcuchu jest wspomniane wcześniej 10 wartości zmienno przecinkowych które zamykam w 3 rekordach, jak widać poniżej.

Pierw przedstawie deklaracje:

type OPLHeader = packed record
        CRC: LongWord; //Wiadomo...
        Crap: array[5..36] of Byte; //Tej części nagłówka nie znam, więc zamykam w tablicy.
        ItemCount: LongWord; //Tu ilość rekordów...
        end;

 type OPLPosition = packed record
    x : Single;
    y : Single;
    z : Single;
    end;

 type OPLRotation = packed record
     x : Single;
     y : Single;
     z : Single;
     w : Single;
    end;

 type OPLScale = packed record
      x : real;
      y : real;
      z : real;
    end;

Tu mamy zaś strukture wpisów:

 Type OPLRecord = packed record
 PathLength: LongWord;  //długość łańcucha znaków
 ObjectPath: Array of Char; //łańcucha znaków
 Position: OPLPosition;   //
 Rotation: OPLRotation; //  <- wiadomo
 Scale: OPLScale;         //
        end;

Oraz zmienne na których operuje:

        Header: OPLHeader;
        Items: array of OPLRecord;

Tutaj zaprezentuje kod, po napisaniu którego, stanąłem w miejscu.

procedure TOPL.LoadFromFile(Filename: String);
var
     PathChar: Byte;
begin
Assign(F,Filename);
 Reset(F,1);

 //czytam nagłówek//
 BlockRead(F,Header,SizeOf(Header));

 //Rozmiar tablicy Items będzie równa ilości wpisów w pliku (z nagłówka)
 SetLength(Items,Header.ItemCount);

 //Od początku do końca...
 for i:= Low(Items) to High(Items) do
  begin
  //Odczytuje dlugosc lancucha
  BlockRead(F,Items[I].PathLength,4);

  //Ustawiam długość łańcucha
  SetLength(Items[i].ObjectPath,Items[I].PathLength);

  //Czytam łańcuch
   for PathChar:=Low(Items[i].ObjectPath) to High(Items[i].ObjectPath) do
    begin
    BlockRead(F,Items[i]. ObjectPath[PathChar],1);
    end;

  //Czytam pozostały stuff...
  BlockRead(F,Items[i].Position,SizeOf(Items[i].Position));
  BlockRead(F,Items[i].Rotation,SizeOf(Items[i].Rotation));
  BlockRead(F,Items[i].Scale,SizeOf(Items[i].Scale));
  end;
 //Koniec... po imprezie :)
 CloseFile(F);
end;

Okay... Co w taim razie jest tu problemem? Otóż to że po wywołaniu LoadFromFile, moja aplikacja nieodpowiada, a nawet czasem wysypie sie delphi przy okazji... Próbowałem znaleŹć przyczyne, i zauważyłem że jak zakomentuje

  //Ustawiam długość łańcucha
  //SetLength(Items[i].ObjectPath,Items[I].PathLength);

program działa, choć wiadomo, czyta nie tak jak powinien...

Nie raz korzystałem z dynamicznych tablic, a z taką sytuacją stykam się pierwszy raz. Niewiem, może to przez to że to tak naprawde dynamiczna tablica w dynamicznej tablicy? Nie mam pojęcia, i tu licze na pomoc z waszej strony.

Z góry dziękuje.

0

ja bym zrobil tak:

do trzymania rekordow uzylbym obiektow zawirajacych odpowiednie pola
i trzymalbym je w liscie (TList) zamiast w tablicy dynamicznej
np:

 TOPLRecord = class
    path: string;
    position: OPLPosition;
    rotation: OPLRotation;
    scale: OPLScale;
    constructor Create(OPL: TOPL);
end;

constructor TOPLRecord.create(OPL: TOPL);
var len: integer;
begin
  //Odczytuje dlugosc lancucha
  BlockRead(OPL.F,len,4);

  //Czytam łańcuch
  BlockRead(OPL.F,path,len);   

  //Czytam pozostały stuff...
  BlockRead(OPL.F,Position,SizeOf(Position));
  BlockRead(OPL.F,Rotation,SizeOf(Rotation));
  BlockRead(OPL.F,Scale,SizeOf(Scale));
end;


procedure TOPL.wczytaj;
begin
  OPL.WczytajHeader;
  for i := 1 to Header.ItemCount do begin
    TOPL.items.add(TOPLRecord.create(self));
  end;
end;

troche to skrotowo opisalem i duzo brakuje ale w ten sposob unikniesz
problemow z pamiecia i platania z wielowymiarowymi rozmiarami tablic . No i chyba wiekszosc osob sie ze mna zgodzi ze
stosowanie klas znaczni podnosi czytelnosc programu...

0

Hm, ciekawe... spróbuje zastosować twój pomysł.
Oczywiście zgadzam sie z tobą, programy napisane obiektowo, są bardziej czytelne, to raz, zresztą zapomocą klas i obiektów programuje się po prostu wygodniej ;]

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