如何在Delphi中将文件读入字节数组?

3

我想在Delphi XE2中将文件读入到一个字节数组中。

这是我的当前代码:

function FileToBytes(const AName: string; var Bytes: TBytes): Boolean;
var
  Ms: TMemoryStream;
begin
  Result := False;
  if not FileExists(AName) then
    Exit;
  Ms := TMemoryStream.Create;
  try
    Ms.LoadFromFile(AName);
    if Ms.Size > 0 then
    begin
      Ms.Position := 0;
      MS.ReadBuffer(Bytes[0], Ms.Size);
      Result := True;
    end;
  finally
    Ms.Free;
  end;
end;

procedure runFile();
var
  Bytes: TBytes;
  OpFile: String;
begin
  OpFile := 'C:\Users\Kenny\Documents\calc.exe';
  Bytes := nil;
  if FileToBytes(OpFile, Bytes) then
  begin
    //do someting with Bytes(array of Byte)

  end;
end;

我在这一行遇到了错误:

MS.ReadBuffer(Bytes[0], Ms.Size);

错误信息如下:

访问地址 0x00000008 写入时发生访问冲突,错误地址为 0x00404727。

如有帮助解决此问题的方法,请不吝赐教。

2
Bytes 是一个动态数组。你需要先使用 SetLength 分配足够的空间。此外,如果你的需求非常简单,可以查看 IOUtils.TFile.ReadAllBytes - Andreas Rejbrand
1个回答

4
您没有分配数组,这就解释了出现错误的原因。您可以通过以下方式修复代码:
Ms.LoadFromFile(AName);
SetLength(Bytes, Ms.Size);
Ms.Position := 0;
MS.ReadBuffer(Pointer(Bytes)^, Ms.Size);
Result := True;

请注意,我已经避免了检查零长度文件的需要,并使用Pointer(Bytes),以便在启用范围检查时代码将正常工作。
我还要指出你的代码犯了我所说的 Delphi 内存流反模式。你将文件读入到一个内存流中,这本质上是一个字节数组。然后你从该字节数组复制到另一个字节数组。你将整个文件写入了两个单独的字节数组。比这更好的做法是像这样编写代码:
function FileToBytes(const AName: string; var Bytes: TBytes): Boolean;
var
  Stream: TFileStream;
begin
  if not FileExists(AName) then
  begin
    Result := False;
    Exit;
  end;
  Stream := TFileStream.Create(AName, fmOpenRead);
  try
    SetLength(Bytes, Stream.Size);
    Stream.ReadBuffer(Pointer(Bytes)^, Stream.Size);
  finally
    Stream.Free;
  end;
  Result := True;
end;

你可以直接从文件中读取到目标字节数组。

我不太喜欢将此函数设置为返回布尔值以指示成功。代码可能会出现许多其他问题,而不仅仅是文件不存在。这些问题将导致您的设计引发异常。我更喜欢看到基于纯异常的错误处理,或者纯错误码的错误处理。但不要采用混合方法。

正如Andreas在评论中指出的那样,你也可以使用RTL库函数System.IOUtils.TFile.ReadAllBytes来执行此任务。尽管在最近的版本中解决了其中一些问题,但我个人倾向于避免整个System.IOUtils单元,因为它存在许多设计问题。我认为XE2版本可能存在某些问题。


1
为什么要写 begin Result := False; Exit; end;(四行)当一个简单的 Exit(False)(一行)就足够了? - Andreas Rejbrand
1
使用这个解决方案时,我在“Stream.ReadBuffer(Pointer(Bytes), Stream.Size);”这一行遇到了一个错误:“流读取错误”。 - Kenneth Barker
抱歉,是我的错,我现在会修复它。我忘记解除指针引用。 - David Heffernan
1
如果我们有一个适当的返回语句,那将会更好。“return value”和“Exit(Value)”有什么不同? - Dave Nottage
该值也可以通过将缓冲区的第一个数组字段传输到缓冲区中来写入缓冲区。 Stream.ReadBuffer(Bytes[0], Stream.Size); - USauter
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接