【问题标题】:Write to the middle of an existing binary file c++写入现有二进制文件c ++的中间
【发布时间】:2011-09-19 15:21:08
【问题描述】:

我正在尝试打开一个二进制文件进行写入而不删除内容。但我不想写信给eof。我想写入文件中的特定位置。

这是一个小例子:

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();

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

【问题讨论】:

    标签: c++ file stream append seek


    【解决方案1】:

    您不能神奇地从中间扩展文件。也许最容易写入新文件:首先复制初始段,然后写入新数据,然后复制剩余段。全部完成后,就可以覆盖原文件了。

    【讨论】:

    • 我不想在中间扩展文件。我想覆盖初始值!
    • @Jonny:这不是你在问题中所说的。您说“不删除内容”。否则很简单,只打开写(没有“附加”),寻找开头并写。
    • 我不想写到开头。我想在文件的某处写。问题是再次打开文件会删除内容。例如: 开头的文件:____________ 操作后的文件:______Bla_______
    • 这不起作用:std::ofstream myfile("test.txt", std::ios::binary); myfile.seekp(125, std::ios::beg); myfile.write(buf, n);?这将寻求 125 并从那里写入,覆盖原来的内容。确保文件大小至少为 125。
    【解决方案2】:

    尝试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);。这不会改变任何事情。
    • 除非你指定 ios::trunc,否则它不应该删除文件
    • @Jonny Schubert,你能发布你的完整例子吗?
    • 使用命名空间标准; int main() { ifstream in("test.txt", ios::binary | ios::app); ofstream out("test.txt", ios::binary); for(int i = 0; i > 一;返回0; }
    • 实际上,@stefaanv 的回答很有道理,试试fstream 而不是ofstream
    【解决方案3】:

    当使用ios::app打开时,就好像您打开了一个恰好附加到现有文件的新文件:您无法访问现有文件。我不确定,因为我会按照 Kerrek 的回答做,但如果你真的想尝试,你可能必须用“ios::in | ios::out”打开,类似于fopen("test.txt", "rw").

    或者正如 crashmstr 指出的那样:ios::out 可能就足够了。

    【讨论】:

    • 你需要ios::outios::in,否则,它只会覆盖methinks..
    • 是的,因为 ios::out 单独会在 linux 上导致以下类型的开放调用:O_WRONLY|O_CREAT|O_TRUNC,而组合 ios::out | ios::in 会导致 O_RDWR 调用,没有 O_TRUNC。
    【解决方案4】:

    这里根据fstream的规范

    fstream::open

    ios::app "在每次输出操作之前将流的位置指示器设置为流的末尾。"所以 ios::app 不能用于替换,任何类型的搜索都会失败,至少对我来说是这样。

    仅使用 ios::out 确实会清除仅保留大小的文件内容,基本上会将文件变成垃圾。

    ios::in|ios::out 对我来说是唯一有效的东西。

    【讨论】:

      【解决方案5】:

      工作代码:此代码在 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;
      }`
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-18
        • 1970-01-01
        • 2012-05-15
        • 2017-01-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多