0

为了在我使用的文件中写一些东西,例如这段代码:

procedure MyProc (... );
const
  BufSize = 65535;
var
  FileSrc, FileDst: TFileStream;
  StreamRead: Cardinal;
  InBuf, OutBuf: Array [0..bufsize] of byte;
begin
  .....
  FileSrc := TFileStream.Create (uFileSrc, fmOpenRead Or fmShareDenyWrite);
  try
    FileDst := TFileStream.Create (uFileTmp, fmCreate);
    try
      StreamRead := 0;
      while ((iCounter < iFileSize) or (StreamRead = Cardinal(BufSize))) 
      begin
        StreamRead := FileSrc.Read (InBuf, BufSize);
        Inc (iCounter, StreamRead);
      end;
    finally
      FileDst.Free;
    end;
  finally
    FileSrc.Free;
  end;
end;

对于 I/O 文件,我使用一个字节数组,所以一切正常,但是当我使用字符串时,例如声明:

InBuf, OutBuf: string  // in delphi xe2 = unicode string

然后不工作。从某种意义上说,该文件什么也不写。我已经明白为什么,或者只是想明白了。我认为这个问题可能是为什么字符串只包含一个指向内存而不是静态结构的指针;正确的?在这种情况下,有一些解决方案可以解决吗?从某种意义上说,是否可以为我使用字符串而不是向量编写文件做点什么?或者我需要使用矢量?如果可能的话,我能做到吗?非常感谢。

4

4 回答 4

3

使用字符串有两个问题。首先,您要RawByteString确保使用字节大小的字符元素——Unicode 字符串具有两个字节宽的元素。其次,您需要取消引用实际上只是一个指针的字符串。

但我想知道为什么您更喜欢字符串而不是堆栈分配的字节数组。

procedure MyProc (... );
const
  BufSize = 65536;
var
  FileSrc, FileDst: TFileStream;
  StreamRead: Cardinal;
  InBuf: RawByteString;
begin
  .....
  FileSrc := TFileStream.Create (uFileSrc, fmOpenRead Or fmShareDenyWrite);
  try
    FileDst := TFileStream.Create (uFileTmp, fmCreate);
    try
      SetLength(InBuf, BufSize);
      StreamRead := 0;
      while ((iCounter < iFileSize) or (StreamRead = Cardinal(BufSize))) 
      begin
        StreamRead := FileSrc.Read (InBuf[1], BufSize);
        Inc (iCounter, StreamRead);
      end;
    finally
      FileDst.Free;
    end;
  finally
    FileSrc.Free;
  end;
end;

注意:您之前的代码声明了一个 65536 字节的缓冲区,但您只使用了其中的 65535 个。可能不是你想要的。

于 2011-09-28T08:05:00.383 回答
3

要将字符串用作缓冲区(我不推荐),您必须使用 SetLength 来分配内部缓冲区,并且您必须将 InBuf[1] 和 OutBuf[1] 作为要读取的数据传递或写。

  var
    InBuf, OutBuf: AnsiString; // or TBytes
  begin
    SetLength(InBuf, BufSize);
    SetLength(OutBuf, BufSize);

    ...

    StreamRead := FileSrc.Read(InBuf[1], BufSize); // if TBytes, use InBuf[0]

    // etc...

您还可以使用 TBytes,而不是 AnsiString。用法保持不变。

但实际上我认为在这里动态分配 TBytes、AnsiStrings 或 RawByteStrings 没有任何优势。我宁愿做你已经做过的事情:使用基于堆栈的缓冲区。在多线程环境中,我可能会使其更小一些。

于 2011-09-28T08:06:31.063 回答
0

是的,您可以将字符串保存/加载到/从流中,请参见以下示例

var Len: Integer;
    buf: string;
    FData: TStream;

// save string to stream
// save the length of the string
Len := Length(buf);
FData.Write(Len, SizeOf(Len));
// save string itself
if(Len > 0)then FData.Write(buf[1], Len * sizeof(buf[1]));

// read string from stream
// read the length of the string
FData.Read(Len, SizeOf(Len));
if(Len > 0)then begin
   // get memory for the string
   SetLength(buf, Len);
   // read string content
   FData.Read(buf[1], Len * sizeof(buf[1]));
end else buf := '';
于 2011-09-28T08:02:26.673 回答
0

在相关说明中,要将内容从一个复制TStream到另一个TStream,您可以只使用该TStream.CopyFrom()方法:

procedure MyProc (... );
var
  FileSrc, FileDst: TFileStream;
begin
  ...
  FileSrc := TFileStream.Create (uFileSrc, fmOpenRead Or fmShareDenyWrite);
  try
    FileDst := TFileStream.Create (uFileTmp, fmCreate);
    try
      FileDst.CopyFrom(FileSrc, 0); // or FileDst.CopyFrom(FileSrc, iFileSize)
    finally
      FileDst.Free;
    end;
  finally
    FileSrc.Free;
  end;
  ...
end; 

这可以通过调用 CopyFile() 来简化:

procedure MyProc (... );
begin
  ...
  CopyFile(PChar(uFileSrc), PChar(uFileTmp), False);
  ...
end; 

无论哪种方式,您都不必担心手动读取/写入文件数据!

于 2011-09-28T18:31:48.217 回答