I already tried to read the file into a TFileStream but that is where I got stuck the file is inserted into the TFileStream but I am unable to read the bytes of the file, I haven't programmed in a while, please help me.
I also tried to read it into a normal File
var
myFile : File;
byteArray : array of byte;
oneByte : byte;
i, count : Integer;
begin
// Try to open the Test.byt file for writing to
AssignFile(myFile, 'C:\Users\theunie\Desktop\Toets\Test2.txt');
// Reopen the file for reading only
FileMode := fmOpenRead;
Reset(myFile, 1); // Now we define one record as 1 byte
// Display the file contents
// Start with a read of the first 6 bytes. 'count' is set to the
// actual number read
ShowMessage('Reading first set of bytes :');
setlength(ByteArray,sizeof(myfile));
BlockRead(myFile, byteArray, sizeof(myFile), count);
// Display the byte values read
for i := 0 to count do
ShowMessage(IntToStr(byteArray[i]));
// Now read one byte at a time to the end of the file
ShowMessage('Reading remaining bytes :');
while not Eof(myFile) do
begin
BlockRead(myFile, oneByte, 1); // Read and display one byte at a time
ShowMessage(IntToStr(oneByte));
end;
Freeandnil(byteArray);
// Close the file for the last time
CloseFile(myFile);
end;
as well as this
procedure TForm1.Button1Click(Sender: TObject);
var
tf : TFileStream; //My Filestream
ar : array of byte;//The dynamic array I want to read it into
k : integer;//count
s : string;//I want to display this at the end
begin
k := 0;
tf := TFileStream.Create('C:\Users\Theunie\Desktop\Test2.txt',fmOpenReadwrite);
try
inc(k);
SetLength(ar,k);
ar[k-1] := tf.Read(ar[k-1],tf.size);
finally
s := inttostr(ar[0]) +';';
for k := 1 to length(ar) do
begin
s := s + ';' + IntToStr(ar[k]);
end;
FreeAndNil(ar);
end;
RichEdit1.Lines.Add(s);
end;
Is the file large ? Can it fit into RAM all at once ?
You basically have two simple options to create a DynArray out of the file, but they are only recommended for small to middle files.
1: http://www.freepascal.org/docs-html/rtl/classes/tbytesstream.html
2: use IOUtils classes
et cetera
Conversely, to save the array's content into the file you would use something like How to convert TBytes to Binary File? (using MemoryStream)
Regarding your attempts.
http://wiki.freepascal.org/File_Handling_In_Pascal
as it already was noted above,
SizeOf
has no relation to the files, that is the memory size of aFile
variable type. If you want to stick with old TurboPascal API, then you have to useFileSize
function to set the size at once. For small files it would work okay, for large files the very approach "read it all to memory at once, then process" is wrong.inc(k); SetLength(ar,k);
- in a +1 loop - that is a very bad idea, it means a heap fragmentation and copying and re-copying and re-re-copying gorwing data buffer time and again. That isLength*Length/2
scaling, and also might be badly damaging heap memory structure (google aboutheap fragmentation
).When you can - you need to check the
FileSize
in before and set the array toFreeAndNil(byteArray);
- totally wrong. Arrays are not objects. You can not use Destroy/Free/FreeAndNil over them. How to clean a dynarray then ? Well, you may just do nothing, as dynarrays are one of auto-ref-counted types, like strings and interfaces etc. As long as your procedure exits, Delphi would automatically free the memory from the local variables. However if you want to clean a dynarray in the middle of the procedure you can do it viaSetLength( MyDynArray, 0 )
or a shortcutMyDynArray := nil
BlockRead(myFile, byteArray, sizeof(myFile), count)
is wrong on misuse ofSizeOf
. But it has another fault also:ByteArray
variable is basically a pointer, so it is just 4 (four!) bytes ( 8 bytes in Win64 code), so you just overwrite all the call-stack. You really should better use modern type-safe API instead. But if you want to stick with old unsafe low-level API then you have to be very clear upon the low-level implementation of the variables of different types. Basically you want to read the file content not into the pointer to buffer, but into the buffer being pointed at, so it should be likeBlockRead(myFile, byteArray[0], MyFileAndArraySize, count)
. Then if only a part of your file was read -count < MyFileAndArraySize
- you wouldBlockRead(myFile, byteArray[count], MyFileAndArraySize - count, count1)
, thenBlockRead(myFile, byteArray[count+count1], MyFileAndArraySize - count - count1, count2)
and so on. Tedious even when you would understand how bytes are running around in low-level types...ar[k-1] := tf.Read(ar[k-1],tf.size);
- that is just absolutely wretched. Check http://www.freepascal.org/docs-html/rtl/classes/tstream.read.html - the result is how many bytes were actually read. So instead of filling your array with the file content, you feel it with "how many bytes were read in one attempt?" instead. You better utilizetf.ReadBuffer
procedure instead then.Yet if you wanted to go via portions
tf.Read
it should be something likeBut again, you have much easier tools to work with small files in modern Delphi
One more problem in your code is in
It is a so-called "one-off error".
While strings for hystorical reasons are indexed from 1 to
Length(s)
and usually do not have 0th element, dynarrays are not.Dynamic arrays are indexed from
0 = Low(ArrayVarName)
toHigh(ArrayVarName) = Length(ArrayVarName) - 1
. So your loop tries to read the memory past the end of array, outside of array itself.Another error is that you start it with TWO semicolons, like "10;;20;30;40....."
It is typical when you got tired or is not very attentive. So you'd better avoid indexing arrays at all. Below is the working code for turning dynamic array into string from Delphi XE2
A bit more about dynamic arrays: