关于字符串:C 在文件中的特定点插入一行 | 珊瑚贝

C++ Inserting a line at specific point in file


我有一个包含游戏高分的文本文件,格式如下:

1
2
3
Name Score
Name Score
Name Score

文件按分数降序排列。

我想在文件的正确位置插入一个新名称及其对应的分数,以便它保持正确排序。任何建议如何做到这一点将不胜感激!

例如,给定以下文件:

1
2
3
4
Edward 100
David 90
Sarah 80
Alice 60

我想补充一下。

1
2
Name = Jodi
Score = 70

到文件,所以新文件的内容是:

1
2
3
4
5
Edward 100
David 90
Sarah 80
Jodi 70
Alice 60

谢谢

目前我有以下代码:

1
2
3
4
5
6
7
string playerName = pPlayer>GetName();
int playerScore = pPlayer>GetScore();

std::ofstream score(“scores.txt”, std::ios_base::app | std::ios_base::out);

score <<\
<< playerName <<“” << playerScore;

这只是将名称添加到文件的末尾。我考虑阅读整个文件,然后对旧文件进行排序。但我不想这样做,因为如果文件变大可能需要很长时间。

  • 那么,到目前为止你做了什么?
  • 目前我有以下代码:
  • 您可能需要加载和重写文件才能执行此操作。否则,您必须使用文件随机访问来做一些肮脏的技巧。
  • @尼克L。随机访问无济于事,您需要重写文件的整个结尾。写一个新文件是唯一的方法。
  • 好的,谢谢,很有用
  • 那个评论不是讽刺的!
  • @MarkRansom我同意,我只是认为如果他知道文件中的位置,那么这种方式可能是可能的,但你是对的,别无他法。


有几种不同的方法可以做到这一点。最简单的实现是将整个文件读入向量,插入新值并写出新文件。

第二个选项是读取文件,直到找到正确的位置,”标记”在文件中的位置(例如使用 istream::tellg()),然后将以下所有元素读入向量,更新新的记录,并写回过去的一次。

第三种选择是在文件中保持列表无序,并在阅读时对信息进行排序。这样,您可以只追加到末尾,从而节省了一遍又一遍地写入文件。

实际上,我怀疑编写一个非常大的文件仍然足够快,几乎不会产生任何影响。现代硬盘驱动器每秒将写入数兆字节,而每行只有几十个字节,因此文件中需要有数百万行才能产生任何影响。比如我刚刚在我的机器上复制了一些132MB的大文件,读取和写入132MB的时间为1.2s。如果你的每条记录都是 26 字节,那就是 5000 万个”分数”。

  • 当然请注意,如果您要插入的元素位于文件开头附近,则选项 2 将与选项 1 基本相同。
  • 显而易见的第四个选项是简单地将文件中的记录与要插入的记录合并 – 假设两者都已排序。我的回答显示了如何通过对标准算法的一次调用来做到这一点。无需将任何部分保存在内存中(比较中的元素除外)。
  • 最好保持简单。我更喜欢第一个选项
  • @SuneelVLN 那么哪个解决方案很简单?我很想看到这里勾画的解决方案附带的代码示例。标准算法仍然被低估。


如果你仔细定义一个类型来表示你的数据记录:

1
2
3
4
5
6
7
8
9
struct Record {
    std::string name; int score;
    friend std::istream& operator>>(std::istream& is, Record& r)       { return is >> r.name         >> r.score; }
    friend std::ostream& operator<<(std::ostream& os, Record const& r) { return os << r.name <<\\t” << r.score; }

    bool operator<(Record const& other) const {
        return other.score < score;
    }
};

注意它知道如何

  • 从流中读取记录
  • 将其写回流
  • 按分数比较记录

那么,C 算法又是你的朋友了:

1
2
3
4
5
6
7
8
9
10
11
int main()
{
    std::ifstream ifs(“input.txt”);
    std::vector<Record> const insert { Record {“Jodi”, 70 } };

    std::merge(
            std::istream_iterator<Record>(ifs), {},
            insert.begin(), insert.end(),
            std::ostream_iterator<Record>(std::cout,\
));
}

在 Coliru 现场观看

  • 我没有看到这会将数据写回文件的位置?
  • @MatsPetersson 嗯。这是一个很好的观点,我将它写入另一个文件(在这种情况下,stdout)。就地更新文本文件是一项艰巨的任务,但您可以这样做:如何在 c 中将一行与另一行交换 – 此示例使用内存映射来替换大文本文件中的一行。



一种方法是加载文件,然后在包含新数据的情况下重写它:

1) 您必须使用 C 文件处理 API(或任何您认为更好的 API)将文件加载到结构中。

2) 由于按顺序加载,数据将在结构中排序。然后,您必须在结构中添加所需的节点(新数据),使其保持排序状态。

3) 最后,从结构中重写你的文件。

对于您的情况,您可以使用 std::vector。您可以打开文件并将其所有行加载到该向量中。您可以通过执行字符串操作来隔离数据。
然后,将您的数据放入结构中,以使其保持排序状态。例如,您可以分割一条线,然后获取分数部分,将其解析为 int 并与新数据分数进行比较。之后,该结构包含您的数据状态。
打开文件并逐行重写。


它的行为方式取决于文件系统。一般没有解决办法。但我不认为有一个真实的文件系统可以让你做这些事情。

关于这样的操作前后文件在磁盘上的样子。文件是磁盘上的一大块。所以重写是需要完成的动作。

如果您对一些不同的方法持开放态度,可能会有解决方案。把这个文件想象成内存。如果它不在磁盘上,你会怎么做?您可以在数组中使用哪种数据结构(我们可以将文件定义为数组)?

如果您不想创建自己的,使用 sth,就完成了。我个人会使用数据库来完成这样的任务。这正是你想要的。您可以插入数据,然后对其进行排序,并且运行速度很快。它经过优化,可以在硬盘驱动器等环境中工作。如果你想把它存档,你可以使用 SQLite.


来源:https://www.codenong.com/22873898/

微信公众号
手机浏览(小程序)

Warning: get_headers(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57

Warning: get_headers(): Failed to enable crypto in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57

Warning: get_headers(https://static.shanhubei.com/qrcode/qrcode_viewid_9534.jpg): failed to open stream: operation failed in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57
0
分享到:
没有账号? 忘记密码?