如何解决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
也不使用 trunc
。 out
并不意味着删除所有文件内容。您只需在您写入的地方替换原始字节即可。
所以你应该使用:
ostream.open("LS22731.json",std::fstream::out | std::fstream::in);
那么你:
- 读取插入点并丢弃数据
- 注意带有
tellp
的位置 - 读取文件末尾并保存
- 转到插入点
- 写入新数据
- 写入保存的数据
- 关闭信息流
这里是对之前算法的改编。谨慎点为:
- 您必须使用
fstream
和std::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::ofstream
和 ios::in
模式,我不确定它是否有效。但 std::ofstream
必须用 ios::out
或 ios::app
打开。当您覆盖默认值时,您还应该提供默认值。
如果你需要打开一个文件进行读写,你应该使用std::fstream
。
另一个问题是您试图在文本文件中间添加一些字符串,这不是一个好主意,它与在记事本中打开时在文本文件中粘贴一些字符串不同。您必须用另一个长度相同的部分替换一个部分,推动一些字符串不会向前移动其余的数据。
我认为最简单的方法是将整个 JSON 读取到内存中,通过添加或删除一些数据来处理它,最后将整个 JSON 重写到文件中。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。