在C++中向现有的二进制文件中间写入数据

14

我试图以写入模式打开一个二进制文件,但不想擦除内容。我想要在文件中的特定位置进行写入,而不是写入到文件末尾。

这里有一个小例子:

ofstream out("test.txt", ios::binary | ios::app);
for(int i = 0; i < 100; i++)
    out.put('_');
out.write("Hallo", 5);
out.close();

ofstream out2("test.txt", ios::binary | ios::app);
out2.seekp(10);
out2.write("Welt", 4);
out2.close();

如果使用应用程序,则搜索不起作用。如果不使用应用程序打开文件会擦除数据。有人知道答案吗?

5个回答

12

尝试使用seekp的第二个重载,它允许你提供偏移量和方向参数,在你的情况下可能是文件开头(即ios_base::beg)。当然,这前提是你知道自己在做什么,只想覆盖现有的一些字符。

编辑:这里有一个完整的可用示例:

#include <iostream>
#include <fstream>

using namespace std;
int main()
{
  {
    ofstream out("test.txt", ios::binary);
    for(int i = 0; i < 100; i++)
      out.put('_');
    out.write("Hallo", 5);
  }

  {   
    fstream out2("test.txt", ios::binary | ios::out | ios::in);
    out2.seekp(10, ios::beg);
    out2.write("Welt", 4);
  }
}

我刚刚尝试了out2.seekp(10, ios_base::beg);。但是这并没有改变任何东西。 - Jonny Schubert
除非您指定ios::trunc,否则它不应该擦除文件。 - crashmstr
@Jonny Schubert,你能发布完整的示例吗? - Nim
使用命名空间std;int main() { ifstream in("test.txt", ios::binary | ios::app); ofstream out("test.txt", ios::binary); for(int i = 0; i < 100; i++) out.put('_'); out.write("Hallo", 5); out.close(); ofstream out2("test.txt", ios::binary | ios::app); out2.seekp(10); out2.write("Welt", 4); out2.close(); int a; cin >> a; return 0; } - Jonny Schubert
1
实际上,@stefaanv 在他的回答中有一点道理,尝试使用 fstream 而不是 ofstream - Nim

6
当使用 ios::app 打开时,就好像打开了一个新文件,并附加到现有文件上:您无法访问现有文件。我不确定,因为我会像Kerrek的答案一样做,但如果您真的想尝试,您可能需要使用 "ios::in | ios::out" 打开,类似于 fopen("test.txt", "rw")。
或者,如 crashmstr 指出的那样:ios::out 可能已经足够了。

6
如果不同时添加 ios::outios::in,它就会直接覆盖。 - Nim
是的,因为在Linux上仅使用ios::out会导致以下类型的打开调用:O_WRONLY|O_CREAT|O_TRUNC,而将ios::out | ios::in组合起来会导致一个O_RDWR调用,但不包括O_TRUNC。 - daminetreg

5

无法在文件中间神奇地扩展文件。可能最简单的方法是写入一个新文件:首先复制初始段,然后写入新数据,最后复制剩余段。完成所有操作后,您可以覆盖原始文件。


我不想在中间扩展文件,我想覆盖初始值! - Jonny Schubert
@Jonny:这不是你在问题中说的。你说“不删除内容”。否则,这很简单,只需打开写入(不带“追加”),定位到开头并写入即可。 - Kerrek SB
我不想写到文件开头,而是想在文件的某个位置写入内容。问题在于再次打开文件会擦除原有内容。 例如: 文件开头: ______________________ 操作后的文件: Bla_ - Jonny Schubert
这个有问题吗:std::ofstream myfile("test.txt", std::ios::binary); myfile.seekp(125, std::ios::beg); myfile.write(buf, n);?这将会从125处开始写入,覆盖原来的内容。确保文件大小至少为125。 - Kerrek SB

3
根据此处 fstream 的规范: fstream::open ios::app "在每次输出操作之前将流的位置指示器设置为流的末尾。" 因此,对于替换,任何寻址都会失败,至少对我来说是如此。
只使用 ios::out 就会清除文件内容,仅保留大小,基本上将文件变成垃圾。
ios::in|ios::out 对我来说是唯一有效的方法。

0
工作代码:此代码在cout.exe中搜索字符串(OLD-STRING),并将其替换为新字符串(NEW-STRING)。
`#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(int argc, char *argv[])
{
  fstream ifs;
  ifs.open ("C:\\Users\\user\\Desktop\\cout.exe", fstream::binary | fstream::in | fstream::out);

  std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

  size_t pos = str.find("OLD-STRING");

  if (pos != string::npos)
  {
    cout << "string found at position: " << int(pos) << endl;

    ifs.seekp(pos);

    ifs.write("NEW-STRING", 10);

  }
  else
  {
    cout << "could not find string" << endl;
  }

  if (ifs.is_open())
    ifs.close();

  return 0;
}`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接