【发布时间】:2012-03-24 18:39:31
【问题描述】:
我知道我可以有效地截断文件并从文件末尾删除字节。
有没有相应的高效截断文件的方法,从文件开头删除内容到文件中间的某个点?
【问题讨论】:
我知道我可以有效地截断文件并从文件末尾删除字节。
有没有相应的高效截断文件的方法,从文件开头删除内容到文件中间的某个点?
【问题讨论】:
当我阅读您要求从文件开头删除内容的问题时。换句话说,您希望删除文件开头的内容并将剩余内容下移。
这是不可能的。您只能从末尾截断文件,而不能从开头截断。您需要将剩余的内容复制到一个新文件中,或者您自己将其复制到同一个文件中。
无论你怎么做,都没有捷径有效的方法可以做到这一点。您必须复制数据,例如@kobik 所描述的。
Raymond Chen 就这个话题写了一篇不错的文章:How do I delete bytes from the beginning of a file?
只是为了好玩,这里有一个基于流的方法的简单实现,用于从文件中的任何位置删除内容。您可以将其与读/写文件流一起使用。我没有测试代码,我会留给你的!
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;
【讨论】:
一个非常简单的解决方案是从“目标位置偏移量”移动(移动)数据块 朝向 BOF,然后修剪(截断)剩菜:
--------------------------
|******|xxxxxx|yyyyyy|zzz|
--------------------------
BOF <-^ (target position offset)
--------------------------
|xxxxxx|yyyyyy|zzz|******|
--------------------------
^ EOF
由于@David 发布了基于TStream 的代码,以下是一些基于“低级”I/O 帕斯卡风格的代码:
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;
【讨论】:
BlockRead/Seek/BlockWrite... 或直接使用TFileStream。