Возможно ли записать / прочитать файл, используя строковую структуру данных? - PullRequest
0 голосов
/ 28 сентября 2011

для записи чего-либо в файл, который я использую, например, этот код:

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;

А для файла ввода / вывода я использую массив байтов, и так все в порядке, но когда я использую строку, например, объявляя:

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

тогда не работает. В смысле этот файл не пишите ничего. Я понял почему, или просто думаю, что понял это. Я думаю, что проблема может быть в том, что строка содержит только указатель на память, а не статическую структуру; правильный? В этом случае есть какое-то решение для его решения? В смысле, можно ли что-то сделать, потому что я могу написать файл, используя строку, а не вектор? Или мне нужно использовать вектор? Если возможно, я могу сделать? Большое спасибо.

Ответы [ 4 ]

3 голосов
/ 28 сентября 2011

Есть две проблемы с использованием строк.Прежде всего вы хотите использовать 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 из них.Вероятно, не то, что вы хотели.

3 голосов
/ 28 сентября 2011

Чтобы использовать строку в качестве буфера (что я бы не рекомендовал), вам придется использовать 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 здесь . Я бы предпочел сделать то, что вы уже делаете: использовать буфер на основе стека. Я бы, возможно, сделал его немного меньше в многопоточной среде.

0 голосов
/ 28 сентября 2011

В связанной заметке, чтобы скопировать содержимое из одного 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; 

В любом случае вам не нужно беспокоиться о ручном чтении / записи данных файла!

0 голосов
/ 28 сентября 2011

Да, вы можете сохранять / загружать строки в / из потока, см. Следующий пример

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