2012-07-19 288 views
21

可能重复:
Removing the first line of a text file in C#从文件中删除第一行

什么是从一个巨大删除第一线最快和最聪明的方式(2-3认为GB)文件?

  • 我认为,你可能无法避免重写整块文件,但我可能是错的。

  • 可以使用内存映射文件以某种方式帮助解决此问题吗?

  • 是否有可能通过直接操作文件系统(例如NTFS)来实现这种行为 - 比方说,更新相应的inode数据并更改文件起始扇区,以便忽略第一行?如果是的话,这种方法是否真的很脆弱,或者有很多其他的应用,除了OS本身做类似的事情吗?

+0

通过更改第一行,您将需要重新编写其余内容。考虑对文件进行相反的排序... – Oded 2012-07-19 19:00:01

+2

您应该在操作系统和FS中标记您的问题 - 可能存在文件系统/操作系统组合,它具有编辑磁盘上的文件的能力。 – 2012-07-19 19:02:16

+0

没有特别的窍门。 NTFS不能像那样工作。 – OmnipotentEntity 2012-07-19 19:02:20

回答

13

NTFS默认情况下,大多数卷(但重要的不是全部!)将数据存储在4096字节块中。这些由$MFT记录引用,您不能直接编辑它,因为操作系统不允许它(出于理智的原因)。因此,没有任何技巧可以在文件系统上执行某些操作(即,无法直接反向截断NTFS上的文件,即使文件系统块大小也是如此)。

由于文件存储在文件系统中的方式,唯一的答案就是你必须直接重写整个文件。或者找出一种不同的方式来存储你的数据。一个2-3GB的文件是巨大而疯狂的,特别是考虑到你提到的行意味着这些数据至少部分是文本信息。

你应该考虑将这些数据放入数据库中吗?或者至少可以更有效地组织它。

+1

[您可以使用稀疏文件。 ](http://blogs.msdn.com/b/oldnewthing/archive/2010/12/01/10097859.aspx) – Joey 2012-07-19 21:39:21

6

即使你可以删除一个前导块,它至少会是一个扇区(512字节),可能与你的行的大小不匹配。

考虑一个包装(甚至可能是一个帮助文件),以便从某个偏移量开始读取。

3

想法(没有神奇的灰尘,只有硬以下工作):

使用用户模式文件系统,如http://www.eldos.com/cbfs/http://dokan-dev.net/en/环绕你的真实的文件系统,并创建一个小的簿记系统,以跟踪有多少的文件在前面被“吃掉”了。在某些时候,当文件变得太大时,将文件重新写入另一个文件并重新开始。

那怎么样?

编辑:

如果与虚拟文件系统去,则可以使用可以胶水与期望的偏移一个“虚拟”的文件的情况下(256MB)文件片段。这样你永远不需要重写这个文件。

更多:对“覆盖”的前几行与“无”的想法

反思 - 不这样做,相反,一个64位整数添加到该文件的前面,并使用任何你喜欢跳过那么多字节的方法,例如Stream派生,它将包装原始流并抵消其中的读数。

我想这可能会更好,如果你选择在'客户端'使用包装。

8

您可以用'\x7f'覆盖要擦除的每个字符。然后,在阅读文件时,读者会忽略该字符。这假设你有一个文本文件,当然不会使用DEL字符。

std::istream & 
my_getline (std::istream &in, std::string &s, 
      char del = '\x7f', char delim = '\n') { 
    std::getline(in, s, delim); 
    std::size_t beg = s.find(del); 
    while (beg != s.npos) { 
     std::size_t end = s.find_first_not_of(del, beg+1); 
     s.erase(beg, end-beg); 
     beg = s.find(del, beg+1); 
    } 
    return in; 
} 

随着亨克指出的那样,你可以选择不同的字符作为您DELETE。但是,优点是无论您想要删除哪一行(不限于第一行),该技术都能正常工作,并且不需要使用文件系统。

使用修改后的阅读器,您可以定期对文件进行“碎片整理”。或者,碎片整理可能会自然发生,因为内容将流式传输/合并到不同的文件或归档到不同的计算机。

编辑:你没有明确地说出来,但我猜这是针对某种日志记录应用程序,其目标是在日志文件的大小上设置一个上限。但是,如果这是目标,那么仅使用一组较小的日志文件就容易多了。假设您维护了大约10MB的日志文件,总日志大约为4GB。所以这将是大约400个文件。如果401st文件已启动,那么对于在此处写入的每一行,可以在第一个文件中的连续行上使用DELETE标记。当所有行都被标记为删除时,文件本身可以被删除,再次为您提供大约400个文件。没有隐藏的O(n )行为,只要在删除行时第一个文件未关闭。

但是更容易的是让您的日志记录系统保留第一个和第401个文件,并在移动到第402个文件时删除第1个文件。

+1

是的,聪明的想法。或者用空格,换行符或'\ 0'来覆盖。这一切都取决于读者,但它可以适应多少。 – 2012-07-19 20:00:12

+0

@亨克·霍特曼:你说得对。我更新了帖子,以反映可以选择不同的角色。问候 – jxh 2012-07-19 20:33:17

0

将文件分成两部分,第一部分是较小的块。 删除第一行,然后与另一行相连。