我已经尝试将文件读入TFileStream,但这就是我卡住的地方,文件被插入TFileStream但是我无法读取文件的字节,我还没有编程,请帮帮我。
我也尝试将其读入普通文件
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;
以及
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;
答案 0 :(得分:2)
文件大吗?它可以一次装入RAM吗?
您基本上有两个简单的选项可以从文件中创建一个DynArray,但它们仅推荐用于中小型文件。
1:http://www.freepascal.org/docs-html/rtl/classes/tbytesstream.html
var BS: TBytesStream; b: byte; L, i: integer;
begin
BS := TBytesStream.Create;
try
BS.LoadFromFile('c:\boot.ini');
L := High(BS.Bytes);
for i := 0 to L do begin
b := BS.Bytes[i];
ShowMessage( IntToStr( b ) );
end;
finally
BS.Destroy;
end;
end;
2:使用IOUtils类
等等
var BS: TBytes; b: byte; L, i: integer;
begin
BS := TFile.ReadAllBytes('c:\boot.ini');
L := High(BS);
for i := 0 to L do begin
b := BS[i];
ShowMessage( IntToStr( b ) );
end;
end;
相反,要将数组的内容保存到文件中,您可以使用How to convert TBytes to Binary File? (using MemoryStream)
之类的内容关于你的尝试。
http://wiki.freepascal.org/File_Handling_In_Pascal
如上所述,SizeOf
与文件无关,即File
变量类型的内存大小。如果您想坚持使用旧的TurboPascal API,则必须使用FileSize
函数立即设置大小。对于小文件,它可以正常工作,对于大文件,“将所有内容一次性读取到内存,然后进程”是错误的。
inc(k); SetLength(ar,k);
- 在+1循环中 - 这是一个非常糟糕的主意,它意味着堆碎片,复制和重新复制以及重新复制gorwing数据缓冲区的时间和次数。这是Length*Length/2
缩放,也可能是严重破坏堆内存结构(谷歌关于heap fragmentation
)。
如果可以 - 您需要检查之前的FileSize
并将阵列设置为
FreeAndNil(byteArray);
- 完全错了。数组不是对象。你不能使用Destroy / Free / FreeAndNil。那么如何清理dynarray呢?
好吧,你可能什么都不做,因为dynarrays是自动引用计数类型之一,比如字符串和接口等。只要你的程序退出,Delphi就会自动从局部变量中释放内存。
但是,如果您想在程序中间清理dynarray,可以通过SetLength( MyDynArray, 0 )
或快捷方式MyDynArray := nil
BlockRead(myFile, byteArray, sizeof(myFile), count)
时, SizeOf
错误。但它还有另一个错误:ByteArray
变量基本上是一个指针,所以它只是4(四个!)字节(Win64代码中的8个字节),所以你只是覆盖所有的调用堆栈。你真的应该更好地使用现代类型安全的API。但是如果你想坚持旧的不安全的低级API,那么你必须非常清楚不同类型的变量的低级实现。基本上你想要读取文件内容而不是指向缓冲区的指针,而是读入指向的缓冲区,所以它应该像BlockRead(myFile, byteArray[0], MyFileAndArraySize, count)
。然后,如果只读取了文件的一部分 - count < MyFileAndArraySize
- 您会BlockRead(myFile, byteArray[count], MyFileAndArraySize - count, count1)
,然后是BlockRead(myFile, byteArray[count+count1], MyFileAndArraySize - count - count1, count2)
,依此类推。
即使你能理解低级类型中字节的运行方式,也很乏味......
ar[k-1] := tf.Read(ar[k-1],tf.size);
- 这真是太可怜了。检查http://www.freepascal.org/docs-html/rtl/classes/tstream.read.html - 结果是实际读取的字节数。因此,您不必使用文件内容填充数组,而是“在一次尝试中读取了多少字节?”代替。您最好使用tf.ReadBuffer
程序。
然而,如果你想通过部分tf.Read
,它应该是
k := 0;
SetLength(ar, tf.Size);
while k < tf.Size do begin
k := k + tf.Read( ar[k], tfSize - k);
end;
但是,在现代Delphi中,您可以使用更简单的工具处理小文件
代码中的另一个问题是
s := inttostr(ar[0]) +';';
for k := 1 to length(ar) do
begin
s := s + ';' + IntToStr(ar[k]);
end;
这是所谓的“一次性错误”。
虽然出于hystorical原因的字符串索引从1到Length(s)
并且通常没有第0个元素,但dynarrays不是。
动态数组的编制范围为0 = Low(ArrayVarName)
到High(ArrayVarName) = Length(ArrayVarName) - 1
。所以你的循环试图在数组本身之外的数组末尾读取内存。
另一个错误是你用两个分号开始,比如“10 ;; 20; 30; 40 .....”
这是典型的,当你累了或不是很专心。所以你最好避免索引数组。 下面是将动态数组从Delphi XE2转换为字符串的工作代码
procedure TForm1.Button1Click(Sender: TObject);
var DynamicArray: TBytes;
SB: TStringBuilder; iSL: IJclStringList;
s1,s2: string; b: byte;
begin
DynamicArray := TBytes.Create( 10, 20, 30, 40, 50 );
SB := TStringBuilder.Create;
try
for b in DynamicArray do begin
if SB.Length > 0 then
SB.Append( ';' );
SB.Append( b );
end;
s1 := SB.ToString;
finally
SB.Destroy; // you must do it in Delphi for Windows
end;
iSL := JclStringList();
for b in DynamicArray do
iSL.Add( IntToStr( b ) );
s2 := iSL.Join( ';' );
iSL := nil; // you may skip it, Delphi would do on exit from procedure
ShowMessage( 'Dynamic array of bytes to string'
+ ^M^J' with Delphi RTL: ' + s1
+ ^M^J' with J.E.D.I. Code Library: ' + s2);
end;
关于动态数组的更多信息: