Odczyt Stringu z pliku przez TFileStream.

0

Witam, dość długo męczyłem temat zapisywania i odczytywania stringu do i z pliku przez TFileStream. Jak na razie poprawnie udało mi się tylko zapisać dane. Odczyt udał się jedynie wtedy gdy plik nie zawierał polskich znaków, zapisać polskie znaki - NIE MA problemu, odczytać to co uprzednio zapisałem - wychodzi coś jak "żółćcl1" + jakieś znaki formatujące tak że nie widać "[" z ShowMessage. Więc zgłaszam się do was z nędznym ochłapem kodu: Jak odczytać poprawnie String z pliku przez TFileStream.

procedure TForm1.FormCreate(Sender: TObject);
var
  S: WideString;
  FS: TFileStream;
begin
  //S := 'żółtażółć';
  FS := TFileStream.Create('test.txt', fmOpenReadWrite);
  ShowMessage(IntToStr(FS.Size));
  //FS.WriteBuffer(Pointer(S)^, Length(S)*2);
  SetLength(S, FS.Size div 2);
  FS.ReadBuffer(Pointer(S)^, FS.Size div 2);
  ShowMessage(']'+S+'[');
  FS.Free;

  Application.Terminate;
end;

Chciałbym dodać tylko, że nigdy nie używałem tego kodu do zapisu i odczytu po kolei przy tej samej kompilacji programu, wiem, że to nie przejdzie przez pozycję kursora w pliku, nie zeruje jej by odczytywać od początku, więc zawszę albo tylko zapisuje, później zapis daję w komentarz i kompiluje program by tylko odczytywał, albo na odwrót.

Jeśli macie jakieś uwagi co do zapisu, walić śmiało, muszę się w końcu nauczyć jak zapisać dane tekstowe z polskimi znakami aby dało się je odczytać i jak je po tym odczytać.

Wszystko to potrzebne mi jest do tworzenia pliku z ustawieniami programu w który będzie zawierał różne dane, nie tylko tekst.

0

Aby zapisać i prawidłowo odczytać jakiś string, należało by również przechować jego długość w pliku. Nie wiem dlaczego dzielisz wielkośc pliku na dwa, ale jak chcesz zmusić kod do działania to przerób sobie poniższy plik na odczyt i zapis do TFileStreama oraz dopasuj do swoich potrzeb, bo to tylko ogólny przykład:

program example2;

{$APPTYPE CONSOLE}

const
  MaxCnt = 6;
  AFileName = 'D:\test_2.bin';
  TxtArr : array[1..MaxCnt] of string = ('ucz', 'sie', 'podstaw', 'i', 'kombinuj', 'sam.');
var
  S : string;
  AFile : File of Byte;
  I, TxtLength, RecCnt : integer;
  DataArr : array[1..MaxCnt] of string;
begin
  for I := Low(DataArr) to High(DataArr) do
    DataArr[I] := TxtArr[I];
  // Zapis
  RecCnt := Length(DataArr);
  Assign(AFile, AFileName);
  Rewrite(AFile);
  BLockWrite(AFile, RecCnt, SizeOf(RecCnt));
  for I := Low(DataArr) to High(DataArr) do
  begin
    TxtLength := Length(DataArr[I]);
    BlockWrite(AFile, TxtLength, SizeOf(TxtLength));
    BlockWrite(AFile, DataArr[I][1], TxtLength);
  end;
  Close(AFile);
  // Odczyt
  Assign(AFile, AFileName);
  Reset(AFile);
  BlockRead(AFile, RecCnt, SizeOf(RecCnt));
  for I := 1 to RecCnt do
  begin
    BlockRead(AFile, TxtLength, SizeOf(TxtLength));
    SetLength(S, TxtLength);
    BlockRead(AFile, S[1], TxtLength);
    Writeln(S);
  end;
  Close(AFile);
  Readln;
end.
0

dziele i mnożę bo tylko wtedy całość się zapisuje, inaczej mam dokładnie połowę zmiennej. Długość łańcucha mógłbym zapisywać do pliku przed ciągiem znaków, wtedy najpierw odczytywał bym ten Integer a później łańcuch. Określenie długości łańcucha w rekordzie mi nie wychodzi, max mogę wpisać tam 255, dla mnie to za mało potrzebuje minimum 512 znaków.
"[DCC Error] Unit1.pas(27): E2056 String literals may have at most 255 elements".

0

O ile się dobrze orientuje to typ string w Delphi 7 mógł pomieścić znaki o wielkości ponad 2 GB, wątpie aby coś na niekorzyść się zmieniło w nowszych wersjach i było tego mniej. Jak widzisz w swoim kodzie zapisuje długośc, a typ string nie jest limitowany przez wielkośc w stylu S : string[69]; oraz to co zapisuje jest krótkie, a to był tylko przykład. Co innego jeżeli string jaki zapisujesz masz podany w kodzie to niestety w jednej linii może być maksimum 255 znaków, ale nic nie stoi na przeszkodzia, a nawet ładniej to będzie wyglądało, jeżeli połaczysz dłuższy ciąg znaków poprzez "+", chociaż chyba aż tak długich danych w kodzie nie musisz wpisywać na ogół, co innego dane pobrane z kontrolek lub innych źródeł, na przykład jakiś plików. A wracając do Twojego dzielenia to bez sensu jest ono, ponieważ własnosc Size przechowuje rozmiar Streamu, jeżeli zawiera on sam tekst w formacie ANSI to jeśli jest to tekst na przykłąd "test", to Size powinno wynosić słownie cztery, o ile w pliku nie ma oprócz tego tesktu żadnych innych znaków oraz danych.

0
procedure StrToStream(const t: string; s: TStream);
var
  Len: Integer;
begin
  Len := Length(t);
  s.Write(Len, SizeOf(Len));
  s.Write(PChar(t)^, Len);
end;

function StreamToStr(s: TStream): string;
var
  Len: Integer;
begin
  s.Read(Len, SizeOf(Len));
  SetLength(Result, Len);
  s.Read(PChar(Result)^, Len);
end;

i musi działać.

0

Przy zapisie 'test123456' w pliku znajduje się:

   t e s t 1 

A przy próbie odczytu wyświetla się:
test1eight więc jakieś naruszenie pamięci czy coś.
Jeśli sam napiszę coś w pliku to odczytuje od 2 znaku.

Jeśli sam wpiszę do pliku polskie znaki to przy próbie odczytu wywala błąd "Integer Overflow".

0

to może najpierw tak - 1. jakie delphi, 2. daj dokładnie taki kod jakim zapisujesz i odczytujesz

0

Ja zapisuje i odczytuje stringi w pliku nietekstowym w następujący sposób:

Najpierw na dwóch bajtach zapisuję długość stringu(dla swoich potrzeb możesz uzyć jednego lub 4 bajtów - więcej nie potrzeba)
Potem zapisuję każdy znak osobno:

for i:=1 to length(str) do fileStream.writeBuffer(str[i], 1);

Jak odczytuję to analogicznie.
Odczytuję długość stringu, potem robię na nim setLength no i:
for i:=1 to dlugosc_stringu do fileStream.readBuffer(str[i], 1);

0

Ja zapisuje i odczytuje stringi w pliku nietekstowym w następujący sposób:

Najpierw na dwóch bajtach zapisuję długość stringu(dla swoich potrzeb możesz uzyć jednego lub 4 bajtów - więcej nie potrzeba)
Potem zapisuję każdy znak osobno:

for i:=1 to length(str) do fileStream.writeBuffer(str[i], 1);

Jak odczytuję to analogicznie.
Odczytuję długość stringu, potem robię na nim setLength no i:
for i:=1 to dlugosc_stringu do fileStream.readBuffer(str[i], 1);

0

Delphi 2010

procedure StrToStream(const t: string; s: TStream);
var
  Len: Integer;
begin
  Len := Length(t);
  s.Write(Len, SizeOf(Len));
  s.Write(PChar(t)^, Len);
end;

function StreamToStr(s: TStream): string;
var
  Len: Integer;
begin
  s.Read(Len, SizeOf(Len));
  SetLength(Result, Len);
  s.Read(PChar(Result)^, Len);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  FS: TFileStream;
begin
  FS := TFileStream.Create('test.txt', fmOpenReadWrite);
  StrToStream('test123456', FS);
  //ShowMessage(StreamToStr(FS));
  Application.Terminate;
end;

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