我希望能够从未分类的源文本文件(每行中的一条记录)中读取,并通过指定应插入的行号将行/记录插入目标文本文件。
将行/记录插入目标文件的位置将通过将传入文件中的传入行与目标文件中已排序的列表进行比较来确定。 (目标文件将作为空文件启动,当程序迭代传入的文件行时,数据将被一次一行地排序并插入其中。)
传入文件示例:
1 10/01/2008 line1data
2 11/01/2008 line2data
3 10/15/2008 line3data
所需的目标文件示例:
2 11/01/2008 line2data
3 10/15/2008 line3data
1 10/01/2008 line1data
我可以通过链接列表或类似的方式在内存中执行排序,但我想允许它扩展为非常大的文件。 (我很乐意尝试解决这个问题,因为我是C ++新手:)。)
其中一种方法可能是使用fstream
打开2个文件流(1个输入和1个输出,或者只输入1个输入/输出流),但是后来我遇到了困难,很难查找并搜索文件位置,因为它似乎取决于文件开头的绝对位置而不是行号:)。
我确信之前已经解决了这样的问题,我很感激如何以一种良好的做法进行处理的建议。
我正在使用Visual Studio 2008 Pro C ++,而我只是在学习C ++。
答案 0 :(得分:1)
如果文件只是一个纯文本文件,那么我担心找到特定编号行的唯一方法就是在你走的时候走文件计数行。
通常的“非内存”方式做你正在尝试做的是将文件从原始文件复制到临时文件,在正确的位置插入数据,然后重命名/替换原始文件。
显然,一旦你完成了插入操作,就可以将文件的其余部分复制到一个大块中,因为你不再关心计算行了。
答案 1 :(得分:1)
[clear-no-c ++]解决方案是使用* nix sort
工具,对第二列数据进行排序。它可能看起来像这样:
cat <file> | sort -k 2,2 > <file2> ; mv <file2> <file>
它不完全就位,它没有使用C ++的请求,但确实有效:)
甚至可能做到:
cat <file> | sort -k 2,2 > <file>
但是,我没有尝试过这条路线
* http://www.ss64.com/bash/sort.html - 排序手册页
答案 2 :(得分:1)
执行此操作的一种方法是不使文件排序,而是使用berkley db(BerkleyDB)使用单独的索引。 db中的每条记录都有排序键和主文件的偏移量。这样做的好处是您可以有多种排序方式,而无需复制文本文件。您还可以通过在末尾附加更改的行来更改行而不重写文件,并更新索引以忽略旧行并指向新行。我们成功地将其用于多GB文本文件,我们必须对其进行许多小的更改。
编辑:我开发的代码是可以下载here的更大包的一部分。具体代码位于source / IO下的btree *文件中。
答案 3 :(得分:1)
基本问题是在常见操作系统下,文件只是字节流。文件系统级别没有行的概念。必须在OS提供的工具之上添加这些语义作为附加层。虽然我从未使用它,但我相信VMS有一个面向记录的文件系统,可以让你想要做的更容易。但是在Linux或Windows下,如果不重写文件的其余部分,则无法插入文件的中间。它类似于内存:在最高级别,它只是一个字节序列,如果你想要一些更复杂的东西,比如一个链表,它必须添加在顶部。
答案 4 :(得分:0)
我认为问题更多的是实现而不是特定的算法,特别是处理非常大的数据集。
假设源文件有2 ^ 32行数据。什么是一种有效的数据排序方式。
我是这样做的:
解析源文件并提取以下信息:排序键,文件中行的偏移量,行长度。此信息将写入另一个文件。这将生成一个易于索引的固定大小元素的数据集,将其称为索引文件。
使用修改后的合并排序。递归划分索引文件,直到要排序的元素数达到某个最小量 - 真正的合并排序递归到1或0个元素,我建议停在1024或者什么,这需要微调。将索引文件中的数据块加载到内存中并对其执行快速排序,然后将数据写回磁盘。
在索引文件上执行合并。这很棘手,但可以这样做:从每个源加载一个数据块(比方说1024个条目)。合并到临时输出文件并写入。清空块时,重新填充。当找不到更多源数据时,从头开始读取临时文件并覆盖要合并的两个部分 - 它们应该是相邻的。显然,最终合并不需要复制数据(甚至创建临时文件)。考虑这一步骤,可能可以为合并的索引文件设置命名约定,以便数据不需要覆盖未合并的数据(如果你看到我的意思)。
读取已排序的索引文件,从源文件中提取数据行并写入结果文件。
对于所有文件读取和写入肯定不会很快,但是应该非常有效 - 真正的杀手是在最后一步中随机搜索源文件。到目前为止,磁盘访问通常是线性的,因此应该合理有效。
答案 5 :(得分:0)
尝试修改Bucket Sort。假设id值很适合它,你将获得一个更有效的排序算法。您可以通过在扫描时实际写出存储桶(使用小存储桶)来提高I / O效率,从而可能减少所需的随机文件/数量。或者不是。
答案 6 :(得分:0)
希望有一些关于如何根据行号将记录插入目标文件的良好代码示例。
您无法将内容插入文件的中间(即,不会覆盖之前的内容);我不知道支持它的生产级文件系统。