C++ std::ofstream正确地查找文件并向其中添加元素
我正在尝试将元素添加到C++ std::ofstream正确地查找文件并向其中添加元素,c++,json,windows,fstream,ofstream,C++,Json,Windows,Fstream,Ofstream,我正在尝试将元素添加到[]之间的.json文件中 如何使用std::ofstream移动光标在[…]之间添加元素 我尝试过几种开放模式,但有一些奇怪的事情。首先,我提出了一个问题:由于覆盖问题,无法使用文件流进行读写 #include <iostream> #include <fstream> int main () { char errmsg[2048]; std::ofstream ostream;
[]
之间的.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, 2048, errno);
std::cout << "Error (" << errno << "): " << errno << std::endl;
}
}
#包括
#包括
int main()
{
char errmsg[2048];
std::流奥斯特雷姆;
异常(std::ios_base::badbit);
尝试
{
ostream.open(“LS22731.json”,std::fstream::ate | std::fstream::in);
strerror_s(errmsg,2048,errno);
std::cout如果打开文件进行读取,则无法设置文件的写入头
您正在使用std::ofstream
和ios::in
模式,我不确定该模式是否有效。但是std::ofstream
必须使用ios::out
或ios::app
打开。当您覆盖默认值时,还应提供默认值
如果需要打开文件进行读写操作,则应使用std::fstream
另一个问题是,您试图在文本文件中间添加一些字符串,这不是一个好主意,它与在记事本打开时在文本文件中粘贴一些字符串是不一样的。您必须用一个长度相同的另一节替换一个部分,推一些字符串不会将其余的数据向前移动。
我认为最简单的方法是将整个JSON读取到内存中,通过添加或删除一些数据进行处理,最后将整个JSON重写到文件中。好吧,JSON文件是错误的……顺序文本文件。这意味着文件包含代表JSON内容的字节流。而且,没有文件系统提供在t中插入数据的功能他在一个连续文件的中间。最简单的方法是:
- 复制到临时文件的插入点
- 写入新数据
- 添加原始文件中的剩余数据
- 将旧文件重命名为备份名称
- 使用原始名称重命名临时文件
- (可选)删除备份文件
勇敢的方法是从结尾开始以块的形式移动第二部分,以创建一个EMPLE位置,将数据写入新的数据在该位置,并在整个操作过程中祈求在中间没有问题,因为文件将被不可挽回地损坏。
这两种方法可以处理任意大小的文件。对于小文件,您可以加载内存中的所有内容,在插入点写入新数据,并在新数据之后重写其余数据。您只需使用默认的
fstream
,并且既不使用ate
也不使用trunc
,out
并不意味着删除所有文件内容。您只需在写入位置替换原始字节
因此,您应该使用:
ostream.open("LS22731.json", std::fstream::out | std::fstream::in);
然后你:
- 读取到插入点并丢弃数据
- 用
tellp
- 读取文件的结尾并保存它
- 转到插入点
- 写入新数据
- 写入保存的数据
- 关闭小溪
以下是对先前算法的修改。注意事项如下:
- 您必须在
std::fstream::out | std::fstream::in
模式下使用fstream
,才能读取和写入文件。文件必须存在,并且您将首先定位在文件的开头
- 为了能够可靠地计算位置,您必须以二进制模式(
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();
}
...
。。。
std::fstream-ostream;
异常(std::ios_base::badbit);
尝试
{
//使用二进制模式可以可靠地查找文件。
ostream.open(“LS22731.json”,
std::fstream::out | std::fstream::in | std::fstream::binary);
strerror_s(errmsg,2048,errno);
std::我必须说,你可以用一种非常迂回的方式来解决这个问题。使用JSON
库(比如或举几个例子)若要将文件读入内存,请操作内容,然后将结果转储到文件。从一个文件中读取并输出到另一个文件如何。或者根据文件大小,将文件读入字符串流,并在需要的位置输入内容,然后覆盖原始文件。但如@TEDLYGMO所述。如果问题是如何操作正确地说,您可能应该使用lib:p谢谢您的评论@TEDLYNMO我会试试。谢谢您的评论@Lasersköld这是一个大文件,并且随着时间的推移越来越大。这是一个机器的物联网数据。@OrkunKasapoglu不客气!如果您的文件很大,而物联网机器中的内存有限,您可能不想将整个文档读入内存使用事件驱动的方法,比如使用JSON库的SAX接口。谢谢@SHR。是的,我知道,但这是使用std::ofstream
移动文件光标/指针的唯一方法。我可以处理删除问题,因为它只是一个]
。但它是一个用于大数据的JSON,当它长大后,读起来就不好了整个文档的电子书写。感谢您的回答。当我同时使用std::fstream::out | std::fstream::in
时,它不会覆盖我的文件吗?因为当我使用std::fstream::out
时tellp()
第一次打开时返回0,文件大小在文件资源管理器中直接变为0KB。我刚刚测试过,在一个16字节的文件中只能重写2字节。嘿,Serge,感谢您的测试,但我在尝试使用s时无法找到最后一个位置