【问题标题】:C Programming File Reading/Writing TechniqueC 编程文件读/写技术
【发布时间】:2011-05-20 05:33:14
【问题描述】:

这是我第一次创建一个涉及文件读写的程序。实际上,我想知道这样做的最佳技术是什么。因为当我和我的同学比较我的工作时,我们的逻辑是非常不同的。

你看,我们的老师要求我们做一个简单的学生列表系统,用户可以在其中添加、编辑和删除记录。他要求我们制作一个文件来保存所有记录,以便我们下次使用该程序时可以访问它。

我对这个问题的解决方案是在程序打开它的菜单之前,我读取里面的所有记录并将其保存在一个数组[]中。这样做,我可以操纵所有的记录。然后在用户退出程序之前,我将它保存在同一个文件中并覆盖上面的所有记录。

我同学的解决方法是这样的。当她添加记录时,她访问文件并附加数据,当她编辑记录时,她访问文件并编辑特定记录,当她删除记录时,她访问文件并删除记录。所以她所做的就是对她创建的每一个函数,她都在访问该文件。

我们的两个工作当然都是可以编码的。但我想知道,如果我们要处理数千或数百万条记录,哪种方式更有效。或者有没有比我们做的更好的解决方案。也许您可以与我们分享您的文件处理经验...谢谢。

【问题讨论】:

    标签: c file input large-data


    【解决方案1】:

    如果记录不是固定大小,就地编辑记录是很微妙的。只有使用二进制格式并支持将行标记为未使用(例如,使用外部索引或白色标记)才能真正实现。文件系统不是原子的,所以你不能确定你所做的事情最终会完整地保存在磁盘上。

    这使得问题比您的学生笔记应用程序的其余部分更复杂,并且最好委托给数据库(SQLite 和 TokyoCabinet 是一些更轻量级的)。如果您不能使用数据库,请使用简单的实现。它将有更少的错误,并且当需要用数据库替换它时您不会被附加。因此,您在内存中读取整个文件的方法听起来是最佳选择。

    【讨论】:

      【解决方案2】:

      这是您在编程中会一次又一次遇到的经典案例:我是针对速度还是内存使用进行优化?

      而且,就像所有这些难题一样,没有“正确”的答案或完美的解决方案。换句话说,你和你的同学在你解决问题的方法上都是对的。

      通过将所有记录加载到内存中的解决方案,您“消耗”内存以便在运行时更快地访问和修改每条记录。将所有记录存储在内存中的数组中会占用空间,但由于内存访问几乎比磁盘访问快无限,因此您的方法运行速度会比您同学的快很多。

      相比之下,您的同学通过等待从硬盘按需加载数据来节省 RAM。但这会让她付出代价:与获取已经在内存中的数据相比,访问硬盘是一个非常昂贵的过程,而且每次用户进行更改时,她都会被困在这样做。想想启动一个程序与切换到一个已经打开的程序需要多长时间。

      这就是权衡。这里要问自己的一些重要问题是:

      1. 数据集(在您将要处理的常见配置中)是否太大(或将变得太大)而无法完全放入内存?如果您正在处理通常是小型数据集,那么计算机现在有足够的 RAM,这可能是值得的。

      2. 您需要多快才能访问数据?实时访问重要吗?它是一个特别复杂的数据集,需要很长时间才能按需从硬盘加载?您的用户期望什么样的性能?

      3. 您的应用程序面向什么样的系统?有时嵌入式系统和其他特殊情况需要他们自己独特的设计方法。您可能拥有大量的 RAM 和非常有限的固定存储空间,或者您可能拥有完全相反的情况。如果您使用标准的现代 PC 硬件,您的用户想要/需要/已经拥有什么?如果您的大多数目标用户已经在使用相对“强大”的硬件,那么您可能会做出不同的设计决策,而不是针对更大的潜在受众——您肯定已经通过程序的表达系统明确地看到了这些权衡要求。

      4. 您需要考虑特殊情况吗?诸如多个用户并发访问之类的事情使将所有数据保存在内存中变得更加困难。其他用户如何能够读取仅存储在本地计算机内存中的数据?这里可能需要共享一个公共文件(甚至可能在共享服务器上)。

      5. 您的数据的某些部分是否比其他部分更频繁地访问?考虑将这些特定部分始终保留在内存中并延迟加载其余部分(这意味着,您仅在/如果用户访问它们时尝试将它们提取到内存中)。

      正如最后一点所暗示的那样,平衡或组合的方法可能与您接近“理想”解决方案一样接近。您可以将尽可能多的数据存储在 RAM 中,同时在应用程序空闲状态期间定期将任何编辑或修改写回磁盘上的文件。一般程序花费大量时间等待用户做某事,而不是相反。您可以利用这些空闲的 CPU 周期将内存中的内容刷新回磁盘,而不会导致任何明显的速度损失。这种方法一直用于软件开发,有助于避免 EClaesson 的回答指出的陷阱。如果您的应用程序崩溃或以其他方式意外退出,则只有很小一部分数据可能会丢失,因为大部分数据已经在后台提交到磁盘。

      后记:当然,Dark Falcon 的回答是正确的,在生产应用程序中,您很可能会使用数据库之类的东西来处理数据。但由于这似乎是出于教育目的,我认为了解每种方法背后的基本权衡更为重要。

      【讨论】:

      • Nioe 回答!我一直想知道为什么老师坚持让学生为这些任务编写自己的机制。我知道有人必须编写数据库库,但实际上似乎很少有现实世界的编程类似于这些作业。有时我想知道 thedailywtf.com 上的某些文章是否来自人们将他们在作业中学到的东西应用到现实世界的应用程序中。
      • 我不会称之为经典,但人们常常忽视内存优化的需要。
      • @Dark Falcon:我同意。我想这是出于同样的原因,而不是教孩子们如何实际使用计算器,它仍然坚持让他们在高中代数中手工进行长除法。以及为什么在现代教育环境中没有学习如何有效访问和使用参考资料,而是将大量精力花在记忆上。
      • @darkfalcon 我认为你是对的。我们的老师正在教我们最原始的编程方式。我认为学习将sql应用于c比教我们这个要好..呵呵
      • 但我认为我们需要学习一切的基础.. 否则我们将不会学到任何东西
      【解决方案3】:

      如果不了解要运行的系统的详细信息、数据集的大小以及开发时间与 cpu 时间的相对成本,就无法回答这个问题。如果系统有足够的内存,在 ram 中处理副本可能更可取。在内存极其有限的小型系统中(今天主要用于嵌入式应用程序),您可能必须更新磁盘文件。其他需要考虑的事情是操作系统在实际写入磁盘之前可能会做的任何缓冲,如果程序崩溃,文件的一致性会发生什么,即使写入磁盘是“昂贵的”,因为它真的很慢或者具有有限数量的写入周期(某些闪存盘技术)。

      如果这是当今台式计算机上的一个小实际问题,您可能还需要考虑开发各种解决方案所花费的时间,而在小型数据集上运行它们可能花费的时间相对微不足道。

      另外,今天最好使用擅长处理相关问题的现有数据库来解决问题,而不是在文件系统中创建自己的数据库。

      【讨论】:

      • 正确,这是正确的技术观点。但鉴于这是一项 C++ 家庭作业,如果期望它处理数百个数据库文件或在某种陈旧的机器上运行,那就太荒谬了。
      【解决方案4】:

      在任何严肃的应用程序中,优秀的程序员可能会使用现有的库来管理数据。选择此工具取决于具体要求:

      1. 是否需要多个用户同时访问?
      2. 是否需要多台机器访问?

      存储大量信息的最常见选择是基于 SQL 的数据库,例如 MySQL、Postgres、Microsoft SQL Server、SQLite 等。这些大多类似于你同学的解决方案,而不是你的。

      【讨论】:

      • 我同意。我将建议使用 SQL 数据库,并且已经有很多库可以帮助初学者使用 SQL。
      【解决方案5】:

      您的版本(将所有记录保存在内存中)很可能会更快。如果记录数增加,它要求您有足够的内存。这样做的坏处是程序崩溃或不正确的退出会使您丢失所有数据,因为它从未保存到文件中。

      你的同学版本不会那么快,因为文件 io 不是你能做到的最快的。但它需要更少的内存,并且在崩溃时更安全,因为大部分数据已经在文件中。

      【讨论】:

      • 还有内存/速度的权衡。
      • 我建议他定期保存文件。设置一个计时器,一旦达到 10 分钟,在继续之前将内存写入文件。
      • @newbie:最好的做法是介于两者之间。特别是,将文件的一部分保存在内存中(例如,上次使用的记录,或者您希望很快使用的记录)并将其余部分保存在文件中,并在最佳时间定期同步到磁盘;维护文件索引也是一个好主意,这样您就可以将文件“查找”到正确的位置。但是,如果你真的需要这种优化,你最好使用成熟的数据库方式,他们已经解决了这个问题,所以你不必这样做。这种“最佳”解决方案是一种折衷,这次是针对代码复杂性。
      猜你喜欢
      • 2010-09-22
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 2011-06-10
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多