20

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

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

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

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

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

4

5 回答 5

14

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

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

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

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

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

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

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

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

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

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

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

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

于 2010-12-04T14:57:14.993 回答
5

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

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

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

于 2010-12-04T14:33:37.247 回答
2

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

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

于 2010-12-04T14:30:30.200 回答
2

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

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

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

于 2010-12-04T14:35:18.570 回答
1

Editing records in place is subtle if they aren't of fixed size. It is only really possible with a binary format and support for marking a row as unused (for example, with an outside index or with whiteouts). Filesystems aren't atomic, so you can't be sure that what you did ends up on disk in its entirety.

This makes the problem way more complex than the rest of your student notes application, and best delegated to a database (SQLite and TokyoCabinet are some of the more lightweight). If you can't use a database, go with a simple implementation. It will have fewer bugs, and you won't get attached when the time comes to replace it with a database. So, your approach of reading the whole file in memory sounds like the best choice.

于 2010-12-04T17:37:54.260 回答