Чтение и печать двоичных данных как они есть из двоичного файла с использованием C ++ - PullRequest
0 голосов
/ 22 сентября 2011

Как я могу прочитать двоичный файл (я не знаю его тип или что хранится в нем) и распечатать 0 s и 1 s в текстовый файл?

#include <iostream>
#include <fstream>
#include <string.h>
#include <iomanip>


using namespace std;


int main(int argc, char *argv[])
{
    char ch;
    bool x;
    int i = 0;

    if (argc < 3)
    {
        cout << endl << "Please put in all parameters" << endl;
        return 0;
    }

    char *c = new char[4];

    ifstream fin(argv[1], ios_base::in | ios_base::binary);

    if (!fin.is_open())
    {
        cout << "Error opening input file" << endl;
        return 0;
    }

    if (!strcmp(argv[2], "-file"))
    {
        ofstream fout(argv[3]);

        if (!fout.is_open())
        {
            cout << "Error opening output file" << endl;
            return 0;
        }

        while (fin.read(c, sizeof ch))
        {
            fout << c;
        }

        cout << "Contents written to file successfully" << endl;
        fout.close();
    }
    else if (!strcmp(argv[2], "-screen"))
    {

        cout << endl << "Contents of the file: " << endl;

        while (fin.read((char *)&x,sizeof x))
        {
            cout << x;
        }

        cout << endl;
    }
    else
    {
        cout << endl << "Please input correct option" << endl;
        return 0;
    }

    fin.close();
    return 0;
}

Ответы [ 4 ]

0 голосов
/ 22 сентября 2011

Самый простой способ - это, вероятно, создать std::bitset из входных данных и распечатать их. Не обращая внимания на проверку ошибок и прочее, простая версия будет выглядеть примерно так:

#include <bitset>
#include <fstream>
#include <iostream>
#include <ios>
#include <iomanip>

int main(int argc, char **argv) { 
    std::ifstream infile(argv[1], std::ios::binary);
    char ch;
    unsigned long count = 0;

    while (infile.read(&ch, 1)) {
        if (count++ % 4 == 0)
            std::cout << "\n" << std::setw(6) << std::hex << count;
        std::cout << std::setw(10) << std::bitset<8>(ch);
    }   
    return 0;
}

Я бы посчитал, что нормальный дамп в шестнадцатеричном формате намного удобнее для использования. Я показываю только четыре байта на строку выше (8 поместится в 80 столбцах, только если пропустить смещение в начале строки, что будет серьезной потерей, по крайней мере, по моему опыту), поэтому весь экран обычно будет всего ~ 200 байтов или около того. В шестнадцатеричном формате вы можете (и обычно делаете) отображать 16 байтов на строку, как в шестнадцатеричном, так и (для печатных символов), а также сами по себе.

Я должен добавить, однако, что я использую шестнадцатеричные дампы вот уже несколько десятилетий, поэтому мое мнение может основываться хотя бы частично на предвзятости, а не на реальных фактах.

0 голосов
/ 22 сентября 2011

К лучшему или худшему, я считаю, что это проще всего сделать с printf:

#include <fstream>
#include <cstdio>

static const std::size_t blocks = 256;
char buf[blocks * 16];

std::ifstream infile(filename, "rb");

do
{
  infile.read(buf, blocks * 16);

  for (std::size_t i = 0; i * 16 < infile.gcount(); ++i)
  {
    for (std::size_t j = 0; j < 16 && 16 * i + j < infile.gcount(); ++j)
    {
      if (j != 0) std::printf(" ");
      std::printf("0x%02X", static_cast<unsigned char>(buf[16 * i + j]));
    }
  }
} while (infile);

Для этого я выбрал произвольную длину строки в 16 байт на строку, и я читаю 4 КБ за раз - это можно настроить для максимальной эффективности. Важно использовать gcount(), чтобы получить фактическое количество прочитанных байтов, поскольку последний раунд цикла может прочитать меньше 4 кБ.

Обратите внимание, что это по сути эквивалентно утилите hexdump.

Если вы хотите получить точный двоичный вывод, вы можете просто написать небольшую вспомогательную процедуру для этого вместо printf.

0 голосов
/ 22 сентября 2011

Как я понял, вам нужен не шестнадцатеричный вывод, а двоичный (0 с и 1 с), несмотря на то, что я не понимаю, почему.Там нет Io манипулятор для вывода двоичных данных.Вы должны сделать это самостоятельно, используя побитовые операторы.Как то так:

char c; // contains byte read from input
for (size_t i = 0; i != sizeof(c); ++i) {
    std::cout << c & 0x80; // grab most significant bit
    c <<= 1; // right shift by 1 bit
} 
0 голосов
/ 22 сентября 2011

Да, просто используйте fstreams и откройте файл с бинарным флагом, тогда вы можете обрабатывать ресурс как обычный fstream и передавать его в текстовый файл. Если вы хотите преобразовать 0 и 1 в символы, это будет немного сложнее. Самым простым способом для этого, скорее всего, будет буферизация байтов в неподписанных символах, таких как здесь , а затем попытка манипулировать ими через sprintf.

fstream API

API-интерфейс sprintf

...