delphi - 需要一次将任何扩展名为XE5的一个字节的文件读入动态数组

标签 delphi delphi-xe5 dynamic-arrays tfilestream

我已经尝试将文件读取到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;

最佳答案

文件大吗?它可以一次放入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类


http://docwiki.embarcadero.com/Libraries/XE8/en/System.IOUtils.TFile.ReadAllBytes
http://www.malcolmgroves.com/blog/?p=447
http://www.programdevelop.com/4641326/
Why do the System.IOUtils functions and TStreamReader use fmShareCompat?


等等

 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循环中-这是一个非常糟糕的主意,它意味着堆碎片以及复制和重新复制以及重新复制遍历数据缓冲区一次又一次。这是Length*Length/2扩展,也可能会严重破坏堆内存结构(有关heap fragmentation的Google)。
如果可以-您需要先检查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;


这是所谓的“一次性错误”。

尽管出于歇斯底里的原因,字符串的索引从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;


有关动态数组的更多信息:


https://delphihaven.wordpress.com/2009/12/09/dynamic-arrays-as-reference-types/
http://blog.marcocantu.com/blog/2014_september_dynamic_arrays_delphixe7.html

关于delphi - 需要一次将任何扩展名为XE5的一个字节的文件读入动态数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30485418/

相关文章:

Delphi 将 StringGrid 中的数据插入数据库表

delphi - 在xe5上安装ZeosLib

C 数组行为 - 全局/局部/动态

c++ - 从一个动态分配的数组复制到另一个 C++

delphi - 自定义 QuickSort 实现中的 SIGSEGV

delphi - 如何将 AnsiString 转换为 TBytes,反之亦然?

delphi - 如何创建临时文件(0x100)以加速应用程序

multithreading - 如何避免TForm.Caption中的 “(not responding)”?

android - Delphi xe5 Android 应用程序在访问剪贴板时卡住

C访问可变长度数组