C++ ifstream/fstream 损坏数据

发布于 2024-10-02 18:48:24 字数 1340 浏览 0 评论 0原文

我是 C++ 新手,我必须为学校做作业。

我需要在不使用 api 调用或系统集成命令的情况下复制二进制* 文件。在学校我们使用 Windows 机器。

我搜索了一下,发现不使用任何 api 复制数据的最佳方法是使用 iostream (ifstream/fstream) 这是我正在使用的代码:

int Open(string Name){

  int length;
  char * buffer;
  ifstream is;
  fstream out;
  FILE* pFile;
  is.open (Name.c_str(), ios::binary );

  // get length of file:
  is.seekg (0, ios::end);
  length = is.tellg();
  is.seekg (0, ios::beg);

  // allocate memory:
  buffer = new char [length];

  // read data as a block:
  is.read (buffer,length);
  is.close();

   pFile = fopen ( "out.exe" , "w" );
   fclose(pFile);

  out.open("out.exe", ios::binary);

  out.write( buffer, length);

  out.close();

  delete[] buffer;
  return 0;
}

out.exe 工作不正常,在 winhex.exe 中查看后 我看到数据已被修改,而我没有对其进行任何操作

有人可以帮助我吗?

*该文件是一个简单的 hello world 程序,它的消息框为“hello world”

编辑:

抱歉我没有反应,它正在睡觉。 无论如何,我已经在十六进制编辑器中打开了两个程序(结果和原始)。 似乎我尝试这一行的所有内容:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000200   4C 00 00 00 00 30 00 00  00 02 00 00 00 0D 0A 00   L    0     

更改为:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000200   4C 00 00 00 00 30 00 00  00 02 00 00 00 0A 00 00   L    0    

正如您在读取或写入过程中可以或看不到的那样,一个字节正在被删除(或添加,有时也会发生)

I'm new to C++ and I've to do an assignment for school.

I need to copy a binary* file without using api calls or system integrated commands. At school we use a windows machine.

I've searched around a bit, and I found out that the best way to copy data without using any api's is to use iostream (ifstream/fstream)
Here's the code I'm using:

int Open(string Name){

  int length;
  char * buffer;
  ifstream is;
  fstream out;
  FILE* pFile;
  is.open (Name.c_str(), ios::binary );

  // get length of file:
  is.seekg (0, ios::end);
  length = is.tellg();
  is.seekg (0, ios::beg);

  // allocate memory:
  buffer = new char [length];

  // read data as a block:
  is.read (buffer,length);
  is.close();

   pFile = fopen ( "out.exe" , "w" );
   fclose(pFile);

  out.open("out.exe", ios::binary);

  out.write( buffer, length);

  out.close();

  delete[] buffer;
  return 0;
}

out.exe isnt working properly, and after looking at it in winhex.exe
I see that the data has been modefied, while I'm not doing anything with it

Can anyone help me?

*the file is a simple hello world program, it messageboxes "hello world"

EDIT:

Sorry for my unresponsiveness, It was sleeping.
Anyways, I've opened both (the result and the original) programs inside an hex editor.
It seems that with everything I try this line:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000200   4C 00 00 00 00 30 00 00  00 02 00 00 00 0D 0A 00   L    0     

Changes into this:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000200   4C 00 00 00 00 30 00 00  00 02 00 00 00 0A 00 00   L    0    

As you can or cannot see somehow during the reading or writing process a byte is being removed (or added, that sometimes happens as well)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

[浮城] 2024-10-09 18:48:25

未指定仅将 ios_base::binary 传递给 fstream 的 ctor(in 和/或 out 也必须提供)。

为了避免这种情况,您可以使用 ofstream(注意 exra 'o')作为 out 而不是 fstream。作为奖励,这将避免需要首先使用“w”标志进行 fopen,因为 ofstream 的 ctor 默认创建文件。

Passing only ios_base::binary to fstream's ctor is not specified (in and/or out must be supplied too).

To avoid that, you could use ofstream (note the exra 'o') for out instead of fstream. As a bonus, this would avoid the need to first fopen with the "w" flag since ofstream's ctor creates the file by default.

娜些时光,永不杰束 2024-10-09 18:48:25

is.read(buffer, length) 不保证读取 length 字节。

我忘记了 out.write 是否也是如此。

is.read(buffer, length) is not guaranteed to read length bytes.

I forget if the same is true for out.write or not.

小嗲 2024-10-09 18:48:25

让我们把它变得更整洁一点:

// Pass strings by const reference (just good habit)
// But may also save a copy. And it indicates that the function should
// not be messing with the name!
int Open(std::string const& Name, std::string const& out)
{
  // Declare variables as close to use as possable.
  // It is very C-Like to declare all the variables at the
  // head of a function.

  // Use the constructor to open the file.
  std::ifstream is(Name.c_str(), ios::binary);
  if (!is) // Failed to open
  {    return -1;
  }

  // get length of file:
  is.seekg (0, ios::end);
  std::size_t length = is.tellg();  // Use the correct type. int is not correct
  is.seekg (0, ios::beg);

  // allocate memory:
  // Using new/delete is risky. It makes the code not exception safe.
  // Also because you have to manually tidy up the buffer you can not
  // escape early. By using RAII the cleanup becomes automative and there
  // is no need to track resources that need to be tidied.
  // 
  // Look up the concept of RAII it makes C++ lfe so much easier.
  // std::vector implements the new/delete internally using RAII
  std::vector<char>    buffer(length);

  std::size_t  read = 0;
  do
  {
      // read does not gurantee that it will read everything asked for.
      // so you need to do int a loop if you want to read the whole thing
      // into a buffer.
      is.read(&buffer[read], length - read);
      std::size_t amount = is.gcount();
      if (amount == 0)
      {    return -2; // Something went wrong and it failed to read.
      }
      read += amount;
  } while(length != read);


  fstream out(out.c_str(), ios::binary );
  if (!out)
  {    return -3; // you may want to test this before spending all the time reading
  }


  // Probably need to loop like we did for read.
  out.write( &buffer[0], length);

  return 0;
}

Lets make that a bit neater:

// Pass strings by const reference (just good habit)
// But may also save a copy. And it indicates that the function should
// not be messing with the name!
int Open(std::string const& Name, std::string const& out)
{
  // Declare variables as close to use as possable.
  // It is very C-Like to declare all the variables at the
  // head of a function.

  // Use the constructor to open the file.
  std::ifstream is(Name.c_str(), ios::binary);
  if (!is) // Failed to open
  {    return -1;
  }

  // get length of file:
  is.seekg (0, ios::end);
  std::size_t length = is.tellg();  // Use the correct type. int is not correct
  is.seekg (0, ios::beg);

  // allocate memory:
  // Using new/delete is risky. It makes the code not exception safe.
  // Also because you have to manually tidy up the buffer you can not
  // escape early. By using RAII the cleanup becomes automative and there
  // is no need to track resources that need to be tidied.
  // 
  // Look up the concept of RAII it makes C++ lfe so much easier.
  // std::vector implements the new/delete internally using RAII
  std::vector<char>    buffer(length);

  std::size_t  read = 0;
  do
  {
      // read does not gurantee that it will read everything asked for.
      // so you need to do int a loop if you want to read the whole thing
      // into a buffer.
      is.read(&buffer[read], length - read);
      std::size_t amount = is.gcount();
      if (amount == 0)
      {    return -2; // Something went wrong and it failed to read.
      }
      read += amount;
  } while(length != read);


  fstream out(out.c_str(), ios::binary );
  if (!out)
  {    return -3; // you may want to test this before spending all the time reading
  }


  // Probably need to loop like we did for read.
  out.write( &buffer[0], length);

  return 0;
}
oО清风挽发oО 2024-10-09 18:48:25

通常,文件以换行符结尾。 0d0a(“\r\n”)可能不是源文件的可读部分。 Windows 通常使用“\r\n”作为换行符,而 UNIX 仅使用“\n”。由于某种原因,当它写入一个新文件时,它仅使用 0a 作为最后的换行符。如果读入并复制第一次写入的文件,看看会发生什么可能会很有趣。

简短的回答是,这正是您使用 Windows 系统时出现的问题。 :D

要破解它,您总是可以无条件地编写一个额外的“\r”作为最后输出的内容。

Generally, files end in a newline. That 0d0a ("\r\n") might not be a readable part of the source file. Windows usually uses "\r\n" for newline, while UNIX uses just "\n". For some reason, when it writes a new file, it's using just 0a for the final newline. It might be interesting to see what happens if you read in and copy the file you wrote the first time.

The short answer is, this is just the kind of problem that crops up when you use a Windows system. :D

To hack it, you could always unconditionally write an extra "\r" as the last thing you output.

撑一把青伞 2024-10-09 18:48:25

我认为这样

ifstream src(source.c_str(), ios::binary);
ofstream dest(destination.c_str(), ios::binary | ios::trunc);
dest << src.rdbuf();
src.close();
dest.close();

就可以了。

I think that

ifstream src(source.c_str(), ios::binary);
ofstream dest(destination.c_str(), ios::binary | ios::trunc);
dest << src.rdbuf();
src.close();
dest.close();

would do the trick.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文