CynicRus
2014-04-04 12:04:44
Hey. As I noticem a many peoples doesn't know, how to use TFileStream class in Simba. Well, I have a bit of free time, and I hope - this article may be helpful for your scripting.
TFileStream
A file is the basic way to reference drive storage, that enables a computer to distinguish one set of information from another on a drive. TFileStream enables programs to read from and write to a file on a drive. It can be used whenever you need to access the bytes of a File. Using the TFileStream will require you to know some about the things (byte Data) that you will want to write to file, such as the number of bytes in that Data and the arrangement of those bytes, in Records and structures. File access is based on exact "File" byte position reference number, TFileStream will do much of the file positioning automatically for writting and reading.
Put the name of the file and the way the file should be opened as it's parameters. The FileName parameter has to be a valid file path for the system it's running on, if it is not a valid path then an exception is thrown. The Mode parameter sets how the file is to be opened and consists of an open mode and a share mode. These modes can be set to determine "How" the file is opened, you can open a file to write to it (fmOpenWrite), or to read from it ($0000), or to do both ($0001). You can also have the function create the file with mode $FF00, which will create the file is it does not exist or erase the file if it already exists.
Once you have a TFileStream created you can write bytes of data to this file with the WriteBuffer( ) method.
Or you can Read bytes from this FileStream with it's ReadBuffer( ) method
The first parameter of both of these fuctions (Buffer) is an UnTyped variable, which means that you can put almost any variable in this parameter and the Delphi complier will accept it without type checking (no warings). This is both good and bad, This was nessarary because there are many different data types that can be written to a file, so this variable needs to be very flexible and accept any Type of variable, the bad part is that there is no Type Checking by the compiler, so you can make anykind of misteak using the Buffer parameter and it will compile without warning. So you need to know how to use this UnTyped Variable. If you use a variable of Fixed memory size for it's "Data" Value like Integer, Byte, Char, TPoint, TRect and others. You can just use that variable as the Buffer and put a SizeOf( ) in the Count parameter. The compiler will get the "Value" data bytes of this Buffer variable and write or read it for the file. For variables with changable memory size for it's "Data" value, like String, Pchar (or any Pointer variable), TObject, this method will NOT work. The "Value" data for these changeable memory allocation variables is a 4 Byte (numeric) Pointer address, and has nothing to do with the "Data" (like text in String and PChar) for these variables.
Using the TFileStream Write and Read Methods
The following code is an example for writing four integers to a file, in a procedure. This will create a file named "D:\Test1.file'" and overwrite that file if it already exists without warning. When naming this file, I have used a File extention of ".file" which is an uncommon file extention (compared to- .txt .doc .bmp .wav .pas) but you can name your files anyway that is useful for you, with any file extention or no file extention. Be careful if you use a commom file extention!
The FileStream1 is created with the fmCreate or fmOpenWrite open Mode and the fmShareDenyWrite share Mode. This means that a New File is created with write access, and no other program can write to this file while it is open. All of our integer variables are given values in the begining of the procedure, an after we create the FileStream1 we can write to this file. The first FileStream1 write buffer is for the variable Int1, an Integer, notice that we use the SizeOf( ) function in the Count parameter. (Do you know the number of bytes this SizeOf function will return for an Integer?) This will write 4 bytes to the file with the bits set in these 4 bytes for the integer value of 100. But these 4 bytes are all that is saved to the file, there is NO information saved to the file about what this data was (an Integer in this case). Next the second Integer Int2 is written to the file. But where are the 4 bytes for this integer written, at the beginning of the File, over top of the Int1 bytes? No, after each write the FileStream position is Advanced to where the last write ended, so the Int2 is added on the end of the file, which would be byte number 5, Also, when you use the FileStream write the file size is automatically increased to the size needed for that write. So we can just use the WriteBuffer method and put as many fixed size variables in the file as we want to. Two more Integers Int3 and Int4 are added to the file, the values for these integers (1702521171, 1918986307) will be explained later.
the TFileStream.Position - Is a zero based integer value that has the current offset of bytes from the begining of the FileStream. Any operation for reading and writing the FileStream will use the file byte begining at the current FileStream Position. The TFileStream access methods, (Write, WriteBuffer, Read, ReadBuffer, LoadFromStream, SaveToStream, CopyFrom) all start their file operation at the Current FileStream Position and automatically advance the FileStream Position to where that method ends it's operation. You can set the FileStream Position to any location of the file, you can also set the position Past (greater than) the current end of the file, if the FileStream is created with the fmOpenWrite Mode, then the file's Size will be increased to the new FileStream Position past the end of the file. If the FileStream is created with the fmOpenRead mode, then the Position can NOT go higher than the Size of the FileStream.
IMPORTANT - You must FREE the FileStream to release the file from the system's file handleing. To use operating system resources efficiently, a program should Free a TFileStream as soon as you are finished with it, I usually use a try and finally block to make sure the FileStream is Free.
So now we have made a Muti Data file with 4 integers in it at file path 'D:\Test1.file' . . . Now we need to Read these 4 integers out of the file. Remember, that since we wrote the file, we know what the data Types are, and where the data segments are located (their file Byte position). Here is some code to read the four integers out of the file!
This time the FileStream1 is Created with the fmOpenRead mode so we can read from the file. Remember, that there is NO information in this file about what the bytes in this file are for, or the order or type of Data in this file, so you will need to know what Data is in the file to get data out of this file. Since we wrote this file we know the data in it and it's arrangement, so we just read the Data out of the file in the exact same sequence that we put the data into it. After the file is opened, we just read the file one Integer at a time like we did when we wrote the file. Remember, the ReadBuffer procedure will automatically advance the FileStream Position to the end of the read operation or the end of the file, whichever comes first. It can NOT advance the Position past the end of the file. So after the second integer (Int2) is read, the FileStream Position is 8, after the third integer is read the file Position is 12. I have added a String, Str1, which is used to put the Integer values into text, so you can display this string in a TLabel.Caption or ShowMessage( ) to confirm that it has gotten the correct integer values.
the Bytes in a File do NOT have a Type - As I have said, there is no information about the bytes (data) in the file unless you put this information in the file, and know how to get this information out of the file and use it. I did not put any information into the file about the data of this file, I will deal with that later. The next code examples are meant to show you that the bytes of a file can be read out of the file and used in ANY WAY, without any reguard to what the bytes were used as (their data Type) when the bytes were written to file. The file Size of the "D:\Test1.file" will be 16 bytes (4 bytes for each integer). An Integer is a common variable in Delphi, a TPoint has two integers in it's Record type. So 4 Integers would be the amount of Integers in 2 TPoints. So we can read these 16 file bytes into 2 TPoints, as in the following example:
Again we get the same integer values from the file in the Rect1 variable. I am showing you these last two examples, not for a way to read files, but so you will see that the bytes in your file are not restricted in how they are read or used. You should notice that there is NO TYPE-CHECKING by the compiler for the bytes read into the TPoints or the TRect. This is not posible, the program has no information about what is in this file. The ONLY thing that sets how and what is read form this file is YOU, in your code.
to be continued…
TFileStream
A file is the basic way to reference drive storage, that enables a computer to distinguish one set of information from another on a drive. TFileStream enables programs to read from and write to a file on a drive. It can be used whenever you need to access the bytes of a File. Using the TFileStream will require you to know some about the things (byte Data) that you will want to write to file, such as the number of bytes in that Data and the arrangement of those bytes, in Records and structures. File access is based on exact "File" byte position reference number, TFileStream will do much of the file positioning automatically for writting and reading.
TFileStream.Init(const FileName: string; Mode: Word);
Put the name of the file and the way the file should be opened as it's parameters. The FileName parameter has to be a valid file path for the system it's running on, if it is not a valid path then an exception is thrown. The Mode parameter sets how the file is to be opened and consists of an open mode and a share mode. These modes can be set to determine "How" the file is opened, you can open a file to write to it (fmOpenWrite), or to read from it ($0000), or to do both ($0001). You can also have the function create the file with mode $FF00, which will create the file is it does not exist or erase the file if it already exists.
Once you have a TFileStream created you can write bytes of data to this file with the WriteBuffer( ) method.
procedure TFileStream.WriteBuffer(const Buffer; Count: Integer);
Or you can Read bytes from this FileStream with it's ReadBuffer( ) method
procedure TFileStream.ReadBuffer(var Buffer; Count: Integer);
The first parameter of both of these fuctions (Buffer) is an UnTyped variable, which means that you can put almost any variable in this parameter and the Delphi complier will accept it without type checking (no warings). This is both good and bad, This was nessarary because there are many different data types that can be written to a file, so this variable needs to be very flexible and accept any Type of variable, the bad part is that there is no Type Checking by the compiler, so you can make anykind of misteak using the Buffer parameter and it will compile without warning. So you need to know how to use this UnTyped Variable. If you use a variable of Fixed memory size for it's "Data" Value like Integer, Byte, Char, TPoint, TRect and others. You can just use that variable as the Buffer and put a SizeOf( ) in the Count parameter. The compiler will get the "Value" data bytes of this Buffer variable and write or read it for the file. For variables with changable memory size for it's "Data" value, like String, Pchar (or any Pointer variable), TObject, this method will NOT work. The "Value" data for these changeable memory allocation variables is a 4 Byte (numeric) Pointer address, and has nothing to do with the "Data" (like text in String and PChar) for these variables.
Using the TFileStream Write and Read Methods
The following code is an example for writing four integers to a file, in a procedure. This will create a file named "D:\Test1.file'" and overwrite that file if it already exists without warning. When naming this file, I have used a File extention of ".file" which is an uncommon file extention (compared to- .txt .doc .bmp .wav .pas) but you can name your files anyway that is useful for you, with any file extention or no file extention. Be careful if you use a commom file extention!
procedure WriteToFile;
var
FileStream1: TFileStream;
Int1, Int2, Int3, Int4: Integer;
begin
Int1 := 100;
Int2 := 200;
Int3 := 1918986307;
Int4 := 1702521171;
FileStream1.init('D:\Test1.file',
$FF00 or $0001 or $0020);
try
FileStream1.WriteBuffer(Int1, SizeOf(Int1));
FileStream1.WriteBuffer(Int2, SizeOf(Int2));
FileStream1.WriteBuffer(Int3, SizeOf(Int3));
FileStream1.WriteBuffer(Int4, SizeOf(Int4));
finally
FileStream1.Free;
end;
end;
The FileStream1 is created with the fmCreate or fmOpenWrite open Mode and the fmShareDenyWrite share Mode. This means that a New File is created with write access, and no other program can write to this file while it is open. All of our integer variables are given values in the begining of the procedure, an after we create the FileStream1 we can write to this file. The first FileStream1 write buffer is for the variable Int1, an Integer, notice that we use the SizeOf( ) function in the Count parameter. (Do you know the number of bytes this SizeOf function will return for an Integer?) This will write 4 bytes to the file with the bits set in these 4 bytes for the integer value of 100. But these 4 bytes are all that is saved to the file, there is NO information saved to the file about what this data was (an Integer in this case). Next the second Integer Int2 is written to the file. But where are the 4 bytes for this integer written, at the beginning of the File, over top of the Int1 bytes? No, after each write the FileStream position is Advanced to where the last write ended, so the Int2 is added on the end of the file, which would be byte number 5, Also, when you use the FileStream write the file size is automatically increased to the size needed for that write. So we can just use the WriteBuffer method and put as many fixed size variables in the file as we want to. Two more Integers Int3 and Int4 are added to the file, the values for these integers (1702521171, 1918986307) will be explained later.
the TFileStream.Position - Is a zero based integer value that has the current offset of bytes from the begining of the FileStream. Any operation for reading and writing the FileStream will use the file byte begining at the current FileStream Position. The TFileStream access methods, (Write, WriteBuffer, Read, ReadBuffer, LoadFromStream, SaveToStream, CopyFrom) all start their file operation at the Current FileStream Position and automatically advance the FileStream Position to where that method ends it's operation. You can set the FileStream Position to any location of the file, you can also set the position Past (greater than) the current end of the file, if the FileStream is created with the fmOpenWrite Mode, then the file's Size will be increased to the new FileStream Position past the end of the file. If the FileStream is created with the fmOpenRead mode, then the Position can NOT go higher than the Size of the FileStream.
IMPORTANT - You must FREE the FileStream to release the file from the system's file handleing. To use operating system resources efficiently, a program should Free a TFileStream as soon as you are finished with it, I usually use a try and finally block to make sure the FileStream is Free.
So now we have made a Muti Data file with 4 integers in it at file path 'D:\Test1.file' . . . Now we need to Read these 4 integers out of the file. Remember, that since we wrote the file, we know what the data Types are, and where the data segments are located (their file Byte position). Here is some code to read the four integers out of the file!
procedure ReadFromFile;
var
FileStream1: TFileStream;
Int1, Int2, Int3, Int4: Integer;
Str1: String;
begin
FileStream1.init('D:\Test1.file',
$0000 or $0020);
try
FileStream1.ReadBuffer(Int1, SizeOf(Int1));
FileStream1.ReadBuffer(Int2, SizeOf(Int2));
FileStream1.ReadBuffer(Int3, SizeOf(Int3));
FileStream1.ReadBuffer(Int4, SizeOf(Int4));
finally
FileStream1.Free;
end;
Str1 := 'Int1-'+IntToStr(Int1)+' Int2-'+IntToStr(Int2)+' Int3='
+IntToStr(Int3)+' Int4'+IntToStr(Int4);
WriteLn(str1);
end;
This time the FileStream1 is Created with the fmOpenRead mode so we can read from the file. Remember, that there is NO information in this file about what the bytes in this file are for, or the order or type of Data in this file, so you will need to know what Data is in the file to get data out of this file. Since we wrote this file we know the data in it and it's arrangement, so we just read the Data out of the file in the exact same sequence that we put the data into it. After the file is opened, we just read the file one Integer at a time like we did when we wrote the file. Remember, the ReadBuffer procedure will automatically advance the FileStream Position to the end of the read operation or the end of the file, whichever comes first. It can NOT advance the Position past the end of the file. So after the second integer (Int2) is read, the FileStream Position is 8, after the third integer is read the file Position is 12. I have added a String, Str1, which is used to put the Integer values into text, so you can display this string in a TLabel.Caption or ShowMessage( ) to confirm that it has gotten the correct integer values.
the Bytes in a File do NOT have a Type - As I have said, there is no information about the bytes (data) in the file unless you put this information in the file, and know how to get this information out of the file and use it. I did not put any information into the file about the data of this file, I will deal with that later. The next code examples are meant to show you that the bytes of a file can be read out of the file and used in ANY WAY, without any reguard to what the bytes were used as (their data Type) when the bytes were written to file. The file Size of the "D:\Test1.file" will be 16 bytes (4 bytes for each integer). An Integer is a common variable in Delphi, a TPoint has two integers in it's Record type. So 4 Integers would be the amount of Integers in 2 TPoints. So we can read these 16 file bytes into 2 TPoints, as in the following example:
procedure ReadFromFile;
var
FileStream1: TFileStream;
Pnt1, Pnt2: TPoint;
Str1: String;
begin
FileStream1.Init('D:\Test1.file',
$0000 or $0020);
try
FileStream1.ReadBuffer(Pnt1, SizeOf(Pnt1));
FileStream1.ReadBuffer(Pnt2, SizeOf(Pnt2));
finally
FileStream1.Free;;
end;
Str1 := 'Pnt1.x-'+IntToStr(Pnt1.x)+' Pnt1.y-'+IntToStr(Pnt1.y)+
' Pnt2.x='+IntToStr(Pnt2.x)+' Pnt2.y'+IntToStr(Pnt2.y);
WriteLn(str1);
end;
This works because the TPoint has 2 integers in it. The integer Values for the Pnt1, Pnt2, x and y values will be the same as the Integer values we got before in the Int1, Int2, Int3, Int4 integers. What about a TRect. . . it has 4 integers in it. . . you could read a TRect from this FileStream1 with:
procedure ReadFromFile;
var
FileStream1: TFileStream;
Rect1: TRect;
Str1: String;
begin
FileStream1.Init('D:\Test1.file',
$0000 or $0020);
try
FileStream1.ReadBuffer(Rect1, SizeOf(Rect1));
finally
FileStream1.Free;
end;
Str1 := 'Rect1.Left-'+IntToStr(Rect1.Left)+
' Rect1.Top-'+IntToStr(Rect1.Top)+
' Rect1.Right='+IntToStr(Rect1.Right)+
' Rect1.Bottom'+IntToStr(Rect1.Bottom);
WriteLn(str1);
end;
Again we get the same integer values from the file in the Rect1 variable. I am showing you these last two examples, not for a way to read files, but so you will see that the bytes in your file are not restricted in how they are read or used. You should notice that there is NO TYPE-CHECKING by the compiler for the bytes read into the TPoints or the TRect. This is not posible, the program has no information about what is in this file. The ONLY thing that sets how and what is read form this file is YOU, in your code.
to be continued…