Wczytanie pliku binarnego do strumienia i konwersja jego zawartości na liczbę całkowitą

0

Witajcie, posiadam plik 8-bitowy i chciałbym skonwertować jego zawartość na zapis w liczbie całkowitej (DEC).
O ile ładowanie pliku i skakanie po nim nie robi mi większego problemu, to nie mam pojęcia jak zrobić konwersję.

2
staryjamnik napisał(a):

Witajcie, posiadam plik 8-bitowy […]

Co to znaczy, że plik jest 8-bitowy? Zajmuje jeden bajt czy co?

O ile ładowanie pliku i skakanie po nim nie robi mi większego problemu, to nie mam pojęcia jak zrobić konwersję.

Do wczytywania liczb, klasa strumienia posiada odpowiednie metody, np. ReadBufferData.

0

Przepraszam było późno plik zajmuje 8 bajtów. ReadBufferData to był strzał w dziesiątkę, dziękuję.

0

Program już sobie napisałem i przy małych plikach ok 5-10MB jest elegancko, ale przy ładowaniu większego do strumienia ok.1GB robi się kaszana i pokazuje "Out of memory". Po zmianie na TFileStream pokazuje inny błąd "Stream read error". Jakiś pomysł?

0

Nie ładuj takich ilości danych do pamięci, bo nie potrzebujesz wszystkiego ”na już”. Poza tym to i tak za dużo – część na pewno trafi do pliku stronicowania i Twój program złapie solidną zamułę (o ile w ogóle sterta będzie na tyle duża…). Użyj strumienia klasy TFileStream i ładuj do pamięci tylko te fragmenty pliku, których potrzebujesz.

staryjamnik napisał(a):

Po zmianie na TFileStream pokazuje inny błąd "Stream read error". Jakiś pomysł?

Ja mam – pokaż kod, bo bez niego można jedynie napisać, że wystąpił błąd odczytu i musisz coś z tym zrobić. ;)

0

No więc tak napisałem sobie coś takiego

const
offset = 1321;
size = 2812584;
var
  FileIN, FileOUT : Integer;
  Buffer: array[0..1] of byte;
  {I,}P,ile, wykonania: Integer;
begin
{ i:= offset+size;}
 P:= offset; //wskaźnik
 ile:=0;
 wykonania:=size div 1; //ilość wykonań rozmiar pliku podzielić przez rozmiar bufora

 try
  FileIN := FileOpen('c:\plik', fmOpenRead);
  FileOUT := FileCreate('c:\plikwynikowy', fmCreate or fmOpenWrite);
  FileSeek(FileIN,P-1,0);  // jednorazowe ustawienie wskaźnika
repeat


FileRead(FileIN, Buffer, 1);
FileWrite(FileOUT, Buffer, 1);
FileSeek(FileIN,P,0);
P:=P+1; //aktualna pozycja + rozmiar buffor
ile:=ile+1; //ilość wykonań
until wykonania=ile;

finally
    FileClose(FileOUT);
    FileClose(FileIN);
  end;

end;

I jak kopiuję bajt po bajcie to jest elegancko, ale strasznie wolno. Próbowałem z większym buforem np.4096, później sprawdzać ile zostało i już po 1 bajcie kończyć, ale cały czas gdzieś jest kaszana.

2

Zasadniczo powinno wystarczyć tyle:

procedure CopyFileFromOffset(const ASourceFileName, ADestFileName: String; AOffset: Int64);
var
  Input, Output: TFileStream;
begin
  Input := TFileStream.Create(ASourceFileName, fmOpenRead);
  Output := TFileStream.Create(ADestFileName, fmCreate or fmOpenWrite);
  try
    Input.Seek(AOffset);
    Output.CopyFrom(Input, Int64.MaxValue);
  finally
    Input.Free();
    Output.Free();
  end;
end;

Wywołanie:

CopyFileFromOffset('C:\Input.dat', 'C:\Output.dat', 1321);

Wszystko dlatego, że metoda CopyFrom posiada w sobie dokładnie taką pętlę, jakiej próbujesz użyć, więc nie ma sensu wymyślać koła na nowo. Podany w drugim parametrze rozmiar kopiowanego bloku i tak jest przycinany do rzeczywistego rozmiaru strumienia, dlatego w przykładzie wyżej podałem po prostu maksymalny możliwy rozmiar.

Powyższe napisałem na podstawie widzy na temat Lazarusa, jednak ten przykład powinien tak samo działać w Delphi.

1

Dziękuję bardzo wszystko działa, ale było moje zdziwienie jak popatrzyłem na wcześniejszy kod który robiłem na strumieniach praktycznie to samo co u Ciebie tylko ja używałem MemoryStream i Position zamiast Seek. W linijce zamiast Input.Seek(AOffset); trzeba dodać zero jako drugi parametr (Input.Seek(AOffse,0); i kompiluje się w Delphi. Temat do zamknięcia, wielkie uszanowanie dla kolegi.

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