Is it possible to delete bytes from the beginning of a file?

眉间皱痕 提交于 2019-12-03 03:03:39

As I read the question you are asking to remove content from a file starting from the beginning of the file. In other words you wish to delete content at the start of the file and shift the remaining content down.

This is not possible. You can only truncate a file from the end, not from the beginning. You will need to copy the remaining content into a new file, or copy it down yourself within the same file.

However you do it there is no shortcut efficient way to do this. You have to copy the data, for example as @kobik describes.

Raymond Chen wrote a nice article on this topic: How do I delete bytes from the beginning of a file?


Just for fun, here's a simple implementation of a stream based method to delete content from anywhere in the file. You could use this with a read/write file stream. I've not tested the code, I'll leave that to you!

procedure DeleteFromStream(Stream: TStream; Start, Length: Int64);
var
  Buffer: Pointer;
  BufferSize: Integer;
  BytesToRead: Int64;
  BytesRemaining: Int64;
  SourcePos, DestPos: Int64;
begin
  SourcePos := Start+Length;
  DestPos := Start;
  BytesRemaining := Stream.Size-SourcePos;
  BufferSize := Min(BytesRemaining, 1024*1024*16);//no bigger than 16MB
  GetMem(Buffer, BufferSize);
  try
    while BytesRemaining>0 do begin
      BytesToRead := Min(BufferSize, BytesRemaining);
      Stream.Position := SourcePos;
      Stream.ReadBuffer(Buffer^, BytesToRead);
      Stream.Position := DestPos;
      Stream.WriteBuffer(Buffer^, BytesToRead);
      inc(SourcePos, BytesToRead);
      inc(DestPos, BytesToRead);
      dec(BytesRemaining, BytesToRead);
    end;
    Stream.Size := DestPos;
  finally
    FreeMem(Buffer);
  end;
end;

A very simple solution would be to shift (move) blocks of data from the "target position offset" towards BOF, and then trim (truncate) the leftovers:

--------------------------
|******|xxxxxx|yyyyyy|zzz|
--------------------------
BOF  <-^ (target position offset)


--------------------------
|xxxxxx|yyyyyy|zzz|******|
--------------------------
                  ^ EOF

Since @David posted a code based on TStream, here is some code based on "low level" I/O pascal style:

function FileDeleteFromBOF(const FileName: string; const Offset: Cardinal): Boolean;
var
  Buf: Pointer;
  BufSize, FSize,
  NumRead, NumWrite,
  OffsetFrom, OffsetTo: Cardinal;
  F: file;
begin
  {$IOCHECKS OFF}
  Result := False;
  AssignFile(F, FileName);
  try
    FileMode := 2; // Read/Write
    Reset(F, 1); // Record size = 1
    FSize := FileSize(F);
    if (IOResult <> 0) or (Offset >= FSize) then Exit;
    BufSize := Min(Offset, 1024 * 64); // Max 64k - This value could be optimized
    GetMem(Buf, BufSize);
    try
      OffsetFrom := Offset;
      OffsetTo := 0;
      repeat
        Seek(F, OffsetFrom);
        BlockRead(F, Buf^, BufSize, NumRead);
        if NumRead = 0 then Break;
        Seek(F, OffsetTo);
        BlockWrite(F, Buf^, NumRead, NumWrite);
        Inc(OffsetFrom, NumWrite);
        Inc(OffsetTo, NumWrite);
      until (NumRead = 0) or (NumWrite <> NumRead) or (OffsetFrom >= FSize);
      // Truncate and set to EOF
      Seek(F, FSize - Offset);
      Truncate(F);
      Result := IOResult = 0;
    finally
      FreeMem(Buf);
    end;
  finally
    CloseFile(F);
  end;
end;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!