C ++ ifstream / fstream портит данные - PullRequest
0 голосов
/ 16 ноября 2010

Я новичок в 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"

EDIT:

Извините за мою неотзывчивость, Это спало. В любом случае, я открыл обе программы (результат и оригинал) в шестнадцатеричном редакторе. Кажется, что все, что я пытаюсь эту строку:

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    

Как вы можете или не можете видеть каким-либо образом в процессе чтения или записи, байт удаляется (или добавляется, что иногда случается также)

Ответы [ 5 ]

1 голос
/ 30 января 2015

Обычно файлы заканчиваются символом новой строки.Этот 0d0a ("\ r \ n") может быть не читаемой частью исходного файла.Windows обычно использует «\ r \ n» для перевода строки, в то время как UNIX использует просто «\ n».По какой-то причине, когда он пишет новый файл, он использует только 0a для последней новой строки.Может быть интересно посмотреть, что произойдет, если вы прочитаете и скопируете файл, который вы написали в первый раз.

Короткий ответ: это как раз та проблема, которая возникает при использовании системы Windows.: D

Чтобы взломать его, вы всегда можете безоговорочно написать дополнительный "\ r" в качестве последней вещи, которую вы выводите.

1 голос
/ 19 ноября 2010

Передача только ios_base::binary в fstream ctor не указан (in и / или out также должны быть поставлены).

Чтобы избежать этого,Вы можете использовать ofstream (обратите внимание на exra 'o') для out вместо fstream.В качестве бонуса это позволило бы избежать необходимости сначала fopen с флагом "w", так как ctor ofstream создает файл по умолчанию.

1 голос
/ 16 ноября 2010

is.read (буфер, длина) не гарантирует чтение байтов длины.

Я забыл, верно ли то же самое для out.write или нет.

0 голосов
/ 17 ноября 2010

Давайте сделаем это немного аккуратнее:

// 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;
}
0 голосов
/ 17 ноября 2010

Я думаю, что

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

добьется цели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...