在不创建临时文件的情况下以二进制模式删除记录(C文件I / O)

时间:2014-10-23 13:33:26

标签: c file-handling

到目前为止我引用的所有代码都使用临时文件从文件中删除记录。
例如:

fp=fopen(“foo.db”,”rb”);
ft=fopen(“temp.db”,”wb”);
//check both files opened or created successfully. Terminate program accordingly 
while(fread(&foo,sizeof(Foo),1,fp))
{
    if(record matched)
    {
        //skip this record
    }
    else
    {
        //write a record in temp file
        fwrite(&foo,sizeof(Foo),1,ft);
    }
}

fclose(fp);
fclose(ft);
remove(“foo.db”); //remove original file
rename(“temp.db”,”foo.db”); //rename temp.db to foo.db

这是我们实现删除记录的唯一方法吗? 我可以想到将下一条记录重叠到以前的记录上 但是如何终止最后一条记录并以二进制模式标记文件结尾?
我也看到this post但没有线索

2 个答案:

答案 0 :(得分:2)

它可能是特定于操作系统的。通常,files是一个字节序列,您不能删除中间的一段字节。您应该考虑使用提供GDBM等索引文件的库,或Sqlite之类的数据库(或PostGreSQLMongoDbMariaDb之类的真实DBMS等。 ...)

GDBM和Sqlite(以及通常真正的DBMS)都是在现有文件系统之上构建的,但提供了一些高级抽象。

换句话说,如果您想避免复制它们,则不应在您的情况下使用纯二进制文件。正如user3121023所评论,您可以管理固定长度记录中的链接并管理免费列表等... GDBM和Sqlite等库也可以执行类似的操作。

我知道没有文件系统或操作系统能够删除中间的一段字节,并且没有POSIX API。

答案 1 :(得分:1)

您始终可以在适当位置重写文件 。你最好打开两次文件,首先是" r"模式,第二个" w +"模式,您使用您显示的算法扫描整个文件并在结尾截断它:关闭读取描述符,截断写入描述符,关闭写入描述符。

如果操作系统不允许您打开文件两次,则可以使用ftell仅使用一个文件描述符来执行相同的操作,分别记录上次读取和写入位置,然后来回查看。

但我认为你应该想要这样做。临时文件不仅允许更简单的算法,而且还允许更健壮的算法。如果发生故障(在控制台中断,杀死错误的PID,停电,雷电......),原始文件保持不变,直到完全写入新文件。它很容易恢复。但是,如果您尝试重写到位,如果程序在重写过程中中断,则唯一的文件处于未确定状态,并且所有数据可能都会丢失 - 或者至少需要更难的恢复过程。但它是你的文件而承担风险: - )