这是我第一次创建一个包含文件读写的程序。实际上我想知道这样做的最佳技巧是什么。因为当我将我的工作与同学比较时,我们的逻辑彼此非常不同。
你看,我们的老师要求我们做一个简单的学生列表系统,用户可以在其中添加,编辑和删除记录。他要求我们创建一个文件来保存所有记录,以便我们在下次使用该程序时可以访问它。
我解决这个问题的方法是在程序打开菜单之前,我读取里面的所有记录并将其保存在数组[]中。这样做,我可以操纵所有记录。然后在用户退出程序之前,我将其保存在同一个文件中并覆盖其上的所有记录。
我同学的解决方案是这样的。当她添加记录时,她访问该文件并附加数据,当她编辑记录时,她访问该文件并编辑特定记录,当她删除记录时,她访问该文件并删除记录。所以她所做的就是她所做的每一项功能,她正在访问该文件。
我们的两项工作当然都可以编码。但我想知道,如果我们处理成千上万的记录,那么使用它会更有效率。还是有其他解决方案比我们做的更好。也许您可以与我们分享您的文件处理经验......谢谢。
答案 0 :(得分:14)
这是一个经典案例,您将在编程中遇到一次又一次:我是否针对速度或内存使用进行了优化?
并且,像所有这些难题一样,没有“正确”的答案或完美的解决方案。换句话说,你和你的同学都正确地解决了这个问题。
通过将所有记录加载到内存中的解决方案,您可以“花费”内存,以便在运行时更快地访问和修改每个记录。将所有记录存储在内存中的数组占用空间,但由于内存访问几乎比磁盘访问速度快得多,因此您的方法将比同学的运行速度快得多。
通过对比,您的同学通过等待从硬盘按需加载数据来节省RAM。但这会花费她的成本:与获取已经存储在内存中的数据相比,击中硬盘是一个非常昂贵的过程,而且每次用户进行更改时,她都会被困在 。想想开始一个程序需要多长时间而不是切换到已经开放的程序。
这就是权衡。在这里问自己的一些重要事情是:
数据集(在您将要处理的常见配置中)是否太大(或会变得太大)以完全适合内存?如果你正在处理通常很小的数据集,那么计算机现在有足够的RAM,这可能是值得的。
您需要多快才能访问数据?实时访问是否重要?它是一个特别大型或复杂数据集,需要花费太长时间才能按需从硬盘加载?您的用户期望达到什么样的性能?
您的应用定位了哪种系统?有时嵌入式系统和其他特殊情况需要他们自己独特的设计方法。您可能拥有大量RAM和非常有限的固定存储空间,或者您可能完全相反。如果您使用的是标准的现代PC硬件,那么您的用户想要/需要/已经拥有什么?如果您的大多数目标用户已经使用相对“强劲”的硬件,那么您可能会做出不同的设计决策,而不是针对更大的潜在受众 - 您肯定会在通过程序表达的系统之前明确表示这些权衡要求。
您是否需要考虑特殊情况?诸如多个用户的并发访问之类的事情使得将所有数据保存在内存中变得更加困难。其他用户如何能够读取仅存储在本地计算机内存中的数据?在这里可能需要共享一个公共文件(甚至可能在共享服务器上)。
您的数据的某些部分是否比其他部分更频繁地被访问?考虑将这些特定部分保留在内存中并延迟加载其余部分(意味着,当用户访问它们时,您只会尝试将它们提取到内存中。)
正如最后一点暗示的那样,平衡或组合方法可能与您达到“理想”解决方案的距离非常接近。您可以将尽可能多的数据存储在RAM中,同时在应用程序的空闲状态期间定期将任何编辑或修改写回磁盘上的文件。平均程序有足够的时间等待用户做某事,而不是相反。您可以利用这些空闲的CPU周期将内存中保留的内容清除回磁盘,而不会导致任何明显的速度损失。这种方法一直在软件开发中使用,有助于避免EClaesson的答案所指出的陷阱。如果您的应用程序崩溃或以其他方式意外退出,则只有很小一部分数据可能会丢失,因为大多数已经在幕后提交到磁盘。
后记:当然,Dark Falcon的答案是正确的,在生产应用程序中,您很可能会使用像数据库这样的东西来处理数据。但由于这似乎是出于教育目的,我认为理解每种方法背后的基本权衡更为重要。
答案 1 :(得分:5)
在任何严肃的应用程序中,优秀的程序员可能会使用现有的库来管理数据。选择此工具取决于具体要求:
存储大量信息的最常见选择是基于SQL的数据库,例如MySQL,Postgres,Microsoft SQL Server,SQLite等。这些数据大多比你同学的解决方案更像你的。
答案 2 :(得分:2)
您的版本(将所有记录保存在内存中)很可能会更快。如果记录数增加,则需要有足够的内存。这样做的坏处是,程序崩溃或不正确的退出会使您丢失所有数据,因为它从未保存到文件中。
你的同学版本不会那么快,因为文件io不是你能做的最快的。但它需要更少的内存,并且在崩溃时更安全,因为大多数数据已经存在于文件中。
答案 3 :(得分:2)
如果不了解运行它的系统的详细信息,数据集的大小以及开发时间与CPU时间的相对成本,这个问题是无法回答的。如果系统有足够的内存,则在ram中处理副本可能更可取。在一个具有极其有限的RAM(当今主要在嵌入式应用程序中找到)的小型系统中,您可能必须更新磁盘文件。其他要考虑的事项是操作系统在实际写入磁盘之前可能执行的任何缓冲,如果程序崩溃,文件中的一致性会发生什么,即使写入磁盘“昂贵”,或者因为它非常慢或者具有有限数量的写周期(一些闪存盘技术)。
如果这是当今桌面计算机上的一个小实际问题,您可能还需要考虑开发各种解决方案所花费的时间,以及它们在小型数据集上运行所花费的相对微不足道的时间。
此外,今天使用擅长处理相关问题的现有数据库解决问题可能更好,而不是在文件系统中创建自己的数据库。
答案 4 :(得分:1)
如果记录不是固定大小,那么编辑记录就很微妙了。只有二进制格式才支持将行标记为未使用(例如,使用外部索引或使用白名单)。文件系统不是原子的,因此您不能确定您所做的事情完全在磁盘上结束。
这使得问题的方式比学生笔记应用程序的其他部分更复杂,并且最好委托给数据库(SQLite和TokyoCabinet是一些更轻量级的)。如果您不能使用数据库,请使用简单的实现。它将有更少的错误,并且当需要用数据库替换它时,您将无法附加。所以,你在内存中读取整个文件的方法听起来是最好的选择。