微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

std::ofstream 正确查找文件并将元素添加到其中

如何解决std::ofstream 正确查找文件并将元素添加到其中

我正在尝试将元素添加.json间的 [] 文件中作为最后一个

如何使用 [...] 有效地​​移动光标以在 std::ofstream 之间添加元素?

我尝试了几种开放模式,但有一些奇怪的事情。首先,我创建了这个关于由于覆盖问题而无法使用文件流进行读写的问题。

    #include <iostream>
    #include <fstream>

    int main ()
    {
        char errmsg[2048];
        std::ofstream ostream;
    
        ostream.exceptions(std::ios_base::badbit);

        try
        {
            ostream.open("LS22731.json",std::fstream::ate | std::fstream::in);
            strerror_s(errmsg,2048,errno);
            std::cout << "Error (" << errno << "): " << errmsg << std::endl;
            if (ostream && ostream.is_open())
            {
                auto ppos = ostream.tellp();
                std::streampos sub = 1; // 
                std::cout << "Tellp: " << ppos << std::endl; // Always show zero but file has large data
                if (ppos > 1)
                    ostream.seekp(ppos - sub) << "aa";

                ppos = ostream.teelp();
                std::cout << "New tellp: " << ppos << std::endl;
                ostream.close();
            }
        }
        catch (std::ios_base::failure& fb)
        {
            std::cout << "Failure: " << fb.what() << std::endl;
            char errmsg[2048];
            strerror_s(errmsg,errno);
            std::cout << "Error (" << errno << "): " << errno << std::endl;
        }
    }

搜索了打开模式,然后找到了 this,但是对于 std::fstream::ate | std::fstream::in,同时使用两种模式 std::ofstream 打开文件好吗?当我用 std::fstream::out 模式打开文件时,它正在重写,因此删除整个文档,

  • std::fstream::out删除文件的所有内容(覆盖)
  • std::fstream::app:无法使用seekp移动光标
  • std::fstream::ate删除文件的所有内容(覆盖)
  • std::fstream::binary删除文件的所有内容(覆盖)
  • std::fstream::ate | std::fstream::app:无法使用seekp移动光标
  • std::fstream::ate | std::fstream::out删除文件的所有内容(覆盖)
  • std::fstream::ate | std::fstream::in:可以移动光标但不能插入删除全部。

我不想使用 c FILE

解决方法

JSON 文件是错误的...顺序文本文件。这意味着该文件包含表示 JSON 内容的字节流。 AFAIK,没有文件系统规定在顺序文件中间插入数据。万无一失的方法是:

  • 复制到插入点到临时文件
  • 写入新数据
  • 添加原始文件中的剩余数据
  • 将旧文件重命名为备份名称
  • 使用原始名称重命名临时文件
  • (可选)删除备份文件

勇敢的方法是将第二部分从末尾开始逐块向上移动,以创建一个完整的位置,将数据写入该位置,并祈祷中间的操作过程中没有问题,因为文件将不可修复地损坏。

这两种方式可以处理任意大小的文件。对于小文件,您可以将所有内容加载到内存中,在插入点写入新数据并在新数据后重写剩余数据。您只需要使用默认的 fstream 并且既不使用 ate 也不使用 truncout 并不意味着删除所有文件内容。您只需在您写入的地方替换原始字节即可。

所以你应该使用:

ostream.open("LS22731.json",std::fstream::out | std::fstream::in);

那么你:

  • 读取插入点并丢弃数据
  • 注意带有 tellp 的位置
  • 读取文件末尾并保存
  • 转到插入点
  • 写入新数据
  • 写入保存的数据
  • 关闭信息流

这里是对之前算法的改编。谨慎点为:

  • 您必须使用 fstreamstd::fstream::out | std::fstream::in 模式才能读写文件。该文件必须存在,您将被初始定位在文件的开头
  • 为了能够可靠地计算位置,您必须以二进制模式 (std::fstream::binary) 打开文件(在文本模式下应该可以,但我找不到方法...)

这是对您的代码的密切改编:它打开文件,搜索第一个右括号 (]),并在之前插入 ,"h" 以模拟向列表中添加值。>

...
std::fstream ostream;

ostream.exceptions(std::ios_base::badbit);

try
{
    // use binary mode to ba able to relyably seek the file.
    ostream.open("LS22731.json",std::fstream::out | std::fstream::in | std::fstream::binary);
    strerror_s(errmsg,2048,errno);
    std::cout << "Error (" << errno << "): " << errmsg << std::endl;
    if (ostream && ostream.is_open())
    {
        std::streampos ppos;
        // search the first ]
        ostream.ignore(std::numeric_limits<std::streamsize>::max(),']');
        // we want to insert just before it
        ppos = ostream.tellg() - std::streampos(1);
        ostream.seekg(ppos);    // prepare to read from the ]
        std::string old = "",tmp;
        // save end of file,starting at the ]
        while (std::getline(ostream,tmp)) {
            old += tmp + "\n";
        }
        ostream.clear();                    // clear eof indicator
        ostream.seekp(ppos,std::ios::beg); // go back to the insertion point
        ostream << ",\"h\"";                // add some data
        ostream << old;                     // add the remaining of the original data
        ostream.close();
    }
...

免责声明:

  • 不要假装我是这样告诉你的。如果在处理过程中出现问题,文件将被彻底损坏。
  • 如果文本字段包含右括号,它将失败,因为它不是 JSON 解析器
,

如果你打开一个文件读,你不能设置它的写头。

您正在使用 std::ofstreamios::in 模式,我不确定它是否有效。但 std::ofstream 必须用 ios::outios::app 打开。当您覆盖默认值时,您还应该提供默认值。

如果你需要打开一个文件进行读写,你应该使用std::fstream

另一个问题是您试图在文本文件中间添加一些字符串,这不是一个好主意,它与在记事本中打开时在文本文件中粘贴一些字符串不同。您必须用另一个长度相同的部分替换一个部分,推动一些字符串不会向前移动其余的数据。

我认为最简单的方法是将整个 JSON 读取到内存中,通过添加或删除一些数据来处理它,最后将整个 JSON 重写到文件中。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。