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ę.
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.
Przepraszam było późno plik zajmuje 8 bajtów. ReadBufferData to był strzał w dziesiątkę, dziękuję.
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ł?
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ć. ;)
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.
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.
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.