开发者

is possible write/read a file using a string data type structure?

for write something in a file i use for example this code:

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;

And for I/O file i use a array of byte, and so is all ok, but when i use a string, for example declaring:

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

then not work. In sense that file not write nothing. I have understood why, or just think to have understood it. I think that problem maybe is why string contain just a pointer to memory and not static structu开发者_运维知识库re; correct? In this case, there is some solution for solve it? In sense, is possible to do something for i can to write a file using string and not vector? Or i need necessary use a vector? If possible, can i can to do ? Thanks very much.


There are two issues with using strings. First of all you want to use RawByteString so that you ensure the use of byte sized character elements – a Unicode string has elements that are two bytes wide. And secondly you need to dereference the string which is really just a pointer.

But I wonder why you would prefer strings to the stack allocated byte array.

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;

Note: Your previous code declared a buffer of 65536 bytes, but you only ever used 65535 of them. Probably not what you intended.


To use a string as a buffer (which I would not recommend), you'll have to use SetLength to allocate the internal buffer, and you'll have to pass InBuf[1] and OutBuf[1] as the data to read or write.

  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...

You can also use a TBytes, instead of an AnsiString. The usage remains the same.

But I actually see no advantage in dynamically allocating TBytes, AnsiStrings or RawByteStrings here. I'd rather do what you already do: use a stack based buffer. I would perhaps make it a little smaller in a multi-threaded environment.


Yes, you can save / load strings to / from stream, see the following example

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 := '';


On a related note, to copy the contents from one TStream to another TStream, you could just use the TStream.CopyFrom() method instead:

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; 

Which can be simplified by calling CopyFile() instead:

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

Either way, you don't have to worry about read/writing the file data manually at all!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜