关于Binary:C ++ ifstream / fstream破坏数据

C++ ifstream/fstream corrupting data

我是C ++的新手,我必须做作业。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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"

编辑:

对不起,我反应迟钝,正在睡觉。
无论如何,我已经在十六进制编辑器中同时打开了(结果和原始)程序。
似乎我尝试了这一行:

1
2
3
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

更改为:

1
2
3
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

如您所知,在读取或写入过程中,字节已被删除(或添加,有时也会发生)


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

为避免这种情况,您可以对out使用ofstream(请注意,用" o"表示),而不是fstream。另外,由于ofstream的ctor默认情况下会创建文件,因此可以避免在fopen之前先加上" w"标志。


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

简短的答案是,这只是使用Windows系统时出现的那种问题。 :D

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


让我们稍微整洁一些:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 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;
}


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

我忘了out.write是否同样如此。


我觉得

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

会成功的