Я хотел бы использовать ifstream и ofstream в C ++ для имитации функциональности BinaryReader / BinaryWriter в C #

Я ищу способ записи float / ints / strings в файл и читать их как floats / ints / strings. (в основном чтение / запись как ios :: binary).

1

Решение

Я подкласс ifstream а также ofstream: ibfstream а также obfstream, Я создал небольшой вспомогательный класс, который бы определял порядковый номер машины, на которой я компилировал / работал. Затем я добавил флаг для ibfstream а также obfstream это указывало на необходимость переворачивать байты в примитивных типах. Эти классы также имели методы для чтения / записи примитивных типов и массивов таких типов, изменяющих порядок байтов по мере необходимости. Наконец я установил ios::binary для этих классов по умолчанию.

Я часто работал на машине с прямым порядком байтов и хотел писать файлы с прямым порядком байтов или наоборот. Это использовалось в программе, которая выполняла много операций ввода-вывода с файлами 3D-графики различных форматов.

0

Другие решения

Я подкласс ifstream а также ofstream: ibfstream а также obfstream, Я создал класс, который бы определял порядковый номер машины, на которой я компилировал / работал. Затем я добавил флаг для ibfstream а также obfstream это указывало на необходимость переворачивать байты в примитивных типах. Эти классы также имели методы для чтения / записи примитивных типов и массивов таких типов, изменяющих порядок байтов по мере необходимости.

Я часто работал на машине с прямым порядком байтов и хотел писать файлы с прямым порядком байтов или наоборот. Это использовалось в программе, которая выполняла много операций ввода-вывода с файлами 3D-графики различных форматов.

0

Я закончил писать сам. Просто хотел поделиться этим с другими.

Это может быть не оптимизировано, но у меня возникли некоторые трудности с поиском кода C ++, который имитирует C # BinaryReader & BinaryWriter классы. Поэтому я создал один класс, который обрабатывает как чтение, так и запись.

Быстрые вещи, чтобы отметить:

1) «БМ» это просто префикс для моих занятий.

2) BMLogging это вспомогательный класс, который просто делает:

cout << "bla bla bla" << endl;

Так что вы можете игнорировать вызовы BMLogging, я сохранил их, чтобы выделить случаи, когда мы могли бы предупредить пользователя.

Вот код:

#include <iostream>
#include <fstream>

using namespace std;

// Create the macro so we don't repeat the code over and over again.
#define BMBINARY_READ(reader,value) reader.read((char *)&value, sizeof(value))

enum BMBinaryIOMode
{
None = 0,
Read,
Write
};

class BMBinaryIO
{
// the output file stream to write onto a file
ofstream writer;
// the input file stream to read from a file
ifstream reader;
// the filepath of the file we're working with
string filePath;
// the current active mode.
BMBinaryIOMode currentMode;

public:
BMBinaryIO()
{
currentMode = BMBinaryIOMode::None;
}

// the destructor will be responsible for checking if we forgot to close
// the file
~BMBinaryIO()
{
if(writer.is_open())
{
BMLogging::error(BMLoggingClass::BinaryIO, "You forgot to call close() after finishing with the file! Closing it...");
writer.close();
}

if(reader.is_open())
{
BMLogging::error(BMLoggingClass::BinaryIO, "You forgot to call close() after finishing with the file! Closing it...");
reader.close();
}
}

// opens a file with either read or write mode. Returns whether
// the open operation was successful
bool open(string fileFullPath, BMBinaryIOMode mode)
{
filePath = fileFullPath;

BMLogging::info(BMLoggingClass::BinaryIO, "Opening file: " + filePath);

// Write mode
if(mode == BMBinaryIOMode::Write)
{
currentMode = mode;
// check if we had a previously opened file to close it
if(writer.is_open())
writer.close();

writer.open(filePath, ios::binary);
if(!writer.is_open())
{
BMLogging::error(BMLoggingClass::BinaryIO, "Could not open file for write: " + filePath);
currentMode = BMBinaryIOMode::None;
}
}
// Read mode
else if(mode == BMBinaryIOMode::Read)
{
currentMode = mode;
// check if we had a previously opened file to close it
if(reader.is_open())
reader.close();

reader.open(filePath, ios::binary);
if(!reader.is_open())
{
BMLogging::error(BMLoggingClass::BinaryIO, "Could not open file for read: " + filePath);
currentMode = BMBinaryIOMode::None;
}
}

// if the mode is still the NONE/initial one -> we failed
return currentMode == BMBinaryIOMode::None ? false : true;
}

// closes the file
void close()
{
if(currentMode == BMBinaryIOMode::Write)
{
writer.close();
}
else if(currentMode == BMBinaryIOMode::Read)
{
reader.close();
}
}

bool checkWritabilityStatus()
{
if(currentMode != BMBinaryIOMode::Write)
{
BMLogging::error(BMLoggingClass::BinaryIO, "Trying to write with a non Writable mode!");
return false;
}
return true;
}

// Generic write method that will write any value to a file (except a string,
// for strings use writeString instead).
void write(void *value, size_t size)
{
if(!checkWritabilityStatus())
return;

// write the value to the file.
writer.write((const char *)value, size);
}

// Writes a string to the file
void writeString(string str)
{
if(!checkWritabilityStatus())
return;

// first add a \0 at the end of the string so we can detect
// the end of string when reading it
str += '\0';

// create char pointer from string.
char* text = (char *)(str.c_str());
// find the length of the string.
unsigned long size = str.size();

// write the whole string including the null.
writer.write((const char *)text, size);
}

// helper to check if we're allowed to read
bool checkReadabilityStatus()
{
if(currentMode != BMBinaryIOMode::Read)
{
BMLogging::error(BMLoggingClass::BinaryIO, "Trying to read with a non Readable mode!");
return false;
}

// check if we hit the end of the file.
if(reader.eof())
{
BMLogging::error(BMLoggingClass::BinaryIO, "Trying to read but reached the end of file!");
reader.close();
currentMode = BMBinaryIOMode::None;
return false;
}

return true;
}

// reads a boolean value
bool readBoolean()
{
if(checkReadabilityStatus())
{
bool value = false;
BMBINARY_READ(reader, value);
return value;
}

return false;
}

// reads a character value
char readChar()
{
if(checkReadabilityStatus())
{
char value = 0;
BMBINARY_READ(reader, value);
return value;
}
return 0;
}

// read an integer value
int readInt()
{
if(checkReadabilityStatus())
{
int value = 0;
BMBINARY_READ(reader, value);
return value;
}
return 0;
}

// read a float value
float readFloat()
{
if(checkReadabilityStatus())
{
float value = 0;
BMBINARY_READ(reader, value);
return value;
}
return 0;
}

// read a double value
double readDouble()
{
if(checkReadabilityStatus())
{
double value = 0;
BMBINARY_READ(reader, value);
return value;
}
return 0;
}

// read a string value
string readString()
{
if(checkReadabilityStatus())
{
char c;
string result = "";
while((c = readChar()) != '\0')
{
result += c;
}
return result;
}
return "";
}
};

РЕДАКТИРОВАТЬ: я заменил все методы чтения / записи выше с этими: (также обновил код использования)

// Generic write method that will write any value to a file (except a string,
// for strings use writeString instead)
template<typename T>
void write(T &value)
{
if(!checkWritabilityStatus())
return;

// write the value to the file.
writer.write((const char *)&value, sizeof(value));
}

// Writes a string to the file
void writeString(string str)
{
if(!checkWritabilityStatus())
return;

// first add a \0 at the end of the string so we can detect
// the end of string when reading it
str += '\0';

// create char pointer from string.
char* text = (char *)(str.c_str());
// find the length of the string.
unsigned long size = str.size();

// write the whole string including the null.
writer.write((const char *)text, size);
}

// reads any type of value except strings.
template<typename T>
T read()
{
checkReadabilityStatus();

T value;
reader.read((char *)&value, sizeof(value));
return value;
}

// reads any type of value except strings.
template<typename T>
void read(T &value)
{
if(checkReadabilityStatus())
{
reader.read((char *)&value, sizeof(value));
}
}

// read a string value
string readString()
{
if(checkReadabilityStatus())
{
char c;
string result = "";
while((c = read<char>()) != '\0')
{
result += c;
}
return result;
}
return "";
}

// read a string value
void readString(string &result)
{
if(checkReadabilityStatus())
{
char c;
result = "";
while((c = read<char>()) != '\0')
{
result += c;
}
}
}

Вот как вы могли бы использовать его, чтобы написать:

string myPath = "somepath to the file";
BMBinaryIO binaryIO;
if(binaryIO.open(myPath, BMBinaryIOMode::Write))
{
float value = 165;
binaryIO.write(value);

char valueC = 'K';
binaryIO.write(valueC);

double valueD = 1231.99;
binaryIO.write(valueD);

string valueStr = "spawnAt(100,200)";
binaryIO.writeString(valueStr);
valueStr = "helpAt(32,3)";
binaryIO.writeString(valueStr);

binaryIO.close();
}

Вот как вы могли бы использовать его для чтения:

string myPath = "some path to the same file";
if(binaryIO.open(myPath, BMBinaryIOMode::Read))
{
cout << binaryIO.read<float>() << endl;
cout << binaryIO.read<char>() << endl;

double valueD = 0;
binaryIO.read(valueD); // or you could use read<double()
cout << valueD << endl;

cout << binaryIO.readString() << endl;
cout << binaryIO.readString() << endl;

binaryIO.close();
}

РЕДАКТИРОВАТЬ 2: Вы могли бы даже написать / прочитать всю структуру в 1 строку:

struct Vertex {
float x, y;
};

Vertex vtx; vtx.x = 2.5f; vtx.y = 10.0f;

// to write it
binaryIO.write(vtx);

// to read it
Vertex vtxRead;
binaryIO.read(vtxRead); // option 1
vtxRead = binaryIO.read<Vertex>(); // option 2

Надеюсь, мой код достаточно ясен.

0