2012-03-07 11 views

Respuesta

12

Cuando leo la pregunta que está pidiendo que elimine el contenido de un archivo comenzando desde el principio del archivo. En otras palabras, desea eliminar contenido al comienzo del archivo y cambiar el contenido restante.

Esto no es posible. Solo puede truncar un archivo desde el final, no desde el principio. Deberá copiar el contenido restante en un archivo nuevo o copiarlo usted mismo dentro del mismo archivo.

Sin embargo, no hay atajos de manera eficiente para hacer esto. Tienes que copiar los datos, por ejemplo, como describe @kobik.

Raymond Chen escribió un buen artículo sobre este tema: How do I delete bytes from the beginning of a file?


Sólo por diversión, aquí es una implementación simple de un método basado en la corriente para eliminar el contenido de cualquier parte del archivo. Puede usar esto con una secuencia de archivos de lectura/escritura. No he probado el código, ¡te lo dejo!

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; 
+0

En realidad, la referencia al archivo disperso es bastante engañosa. No se trata de ** borrar ** N bytes en el desplazamiento 0, sino ** ajustar ** región de 0..N-1 bytes en ceros (o cualquier valor de byte de relleno preestablecido) – OnTheFly

+2

@user Disculpe, qué es ¿engañoso? –

+1

¡Eres increíble! Gracias David, ¡eso fue todo! – TheDude

7

Una solución muy sencilla sería la de desplazar (mover) los bloques de datos de la "posición de destino compensar" hacia BOF, y luego recorte (truncar) las sobras:

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


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

Desde @ David ha escrito un código basado en TStream, aquí hay un código basado en el "bajo nivel" E/S Pascal estilo I:

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; 
+2

** Muy ** idea inteligente Kobik, pero ¿puedo hacerlo en la práctica? (en Delphi quiero decir) – TheDude

+1

Seguro que puedes: 'BlockRead' /' Seek'/'BlockWrite' ... o usa' TFileStream' directamente. – kobik

+0

@Gdhami Esto es todo lo que puedes hacer. Tienes que copiar el contenido restante del archivo. El punto es que no hay una manera trivial eficiente de truncar al principio del archivo, a diferencia del truncamiento al final del archivo que es efectivamente libre. –

Cuestiones relacionadas