Удалить первые N символов из TextFile без создания нового файла (Delphi) - PullRequest
6 голосов
/ 19 октября 2010

Я просто хочу удалить из указанного текстового файла первые N символов, но я застрял. Помогите мне, пожалуйста!

procedure HeadCrop(const AFileName: string; const AHowMuch: Integer);
var
  F: TextFile;
begin
  AssignFile(F, AFileName);
  // what me to do next?
  // ...
  // if AHowMuch = 3 and file contains"Hello!" after all statements
  // it must contain "lo!"
  // ...
  CloseFile(F);
end;

Я пытался использовать TStringList, но он дополнительно добавляет символ конца строки!

with TStringList.Create do
try
  LoadFormFile(AFileName); // before - "Hello!"
  // even there are no changes...
  SaveToFile(AFileName); // after - "Hello!#13#10"
finally
  Free;
end;

Спасибо!

Ответы [ 2 ]

9 голосов
/ 19 октября 2010

Нет простого способа удалить что-либо из начала файла в Windows.Вы должны либо скопировать файл в другой файл, либо удалить оригинал и переименовать целевой файл, либо скопировать все данные в файле на несколько байт назад, а затем обрезать файл.Если файл небольшой и может быть загружен в память, последний метод становится довольно простым.

Следующий фрагмент кода реализует последний подход с полноразмерным буфером памяти.

var
  fs: TFileStream;
  ms: TMemoryStream;

begin
  fs := TFileStream.Create('somefile', fmOpenReadWrite); // catch errors here!
  try
    ms := TMemoryStream.Create;
    try
      ms.CopyFrom(fs, 0);
      ms.Position := 42; // head bytes to skip
      fs.Position := 0;
      fs.CopyFrom(ms, ms.Size - ms.Position);
      fs.Size := fs.Position;
    finally FreeAndNil(ms); end;
  finally FreeAndNil(fs); end;
end;
2 голосов
/ 19 октября 2010

Габр победил меня, но я выбрал другой подход:

procedure HeadCrop(const AFileName: string; const AHowMuch: Int64);
var
  lFileStream: TFileStream;
  lPos: Int64;
  lRead: Integer;
  lBuffer: array[0..511] of Byte;
begin
  lFileStream := TFileStream.Create(AFileName, fmOpenReadWrite);
  try
    if lFileStream.Size < AHowMuch then
    begin
      lFileStream.Size := 0;
      Exit;
    end;
    lPos := AHowMuch;
    repeat
      lFileStream.Position := lPos;
      lRead := lFileStream.Read(lBuffer, SizeOf(lBuffer));
      lFileStream.Position := lPos - AHowMuch;
      lFileStream.Write(lBuffer, lRead);
      Inc(lPos, SizeOf(lBuffer));
    until lRead <> SizeOf(lBuffer);
    lFileStream.Size := lFileStream.Size - AHowMuch;
  finally
    lFileStream.Free;
  end;
end;

Этот код читает файл и перемещает блоки размером 512 байт обратно в файл.

PS: эта процедура перемещает только байты, а НЕ символы! Так что это работает только для однобайтовых символов.

...