How to read string from a binary file in C++? - c++

I have a function two functions, writing and reading from the binary file in C++.
void save_ascII(string ascII_text, string filename)
{
ofstream fout;
fout.open(filename,ofstream::binary);
size_t input_size = ascII_text.size();
if (fout.is_open())
{
fout.write(reinterpret_cast<char*>(&input_size), sizeof(input_size));
fout.write(reinterpret_cast<char*>(&input_size), input_size);
fout.close();
}
}
void read_ascII(string filename)
{
string read_input;
ifstream fin(filename,fstream::binary);
size_t read_size;
if (fin.is_open())
{
fin.read(reinterpret_cast<char*>(&read_size), sizeof(read_size));
read_input.resize(read_size);
fin.read(&read_input[0], read_size);
fin.close();
}
}
The problem is that when it reads from the binary, it just dummy data on the memory.
When it reads from the binary file, it shows:
►╠╠╠╠╠╠╠╠▄²A
Any suggestion really appreciates it.

In your code,
size_t input_size = ascII_text.size();
if (fout.is_open())
{
fout.write(reinterpret_cast<char*>(&input_size), sizeof(input_size));
fout.write(reinterpret_cast<char*>(&input_size), input_size); //<--bug
fout.close();
}
instead of the line marked with bug<--, you need
fout.write(ascII_text.data(), input_size);

Related

Write real binary to file

I am currently working on a project to read binary data from a file do stuff with it and to write it back again. The reading works well so far, but when I try to write the binary-data stored in a string to a file, it writes the binarys as text. I think it has soemthing to do with the opening mode.
Here is my code:
void WriteBinary(const string& path, const string& binary)
{
ofstream file;
file.open(path);
std::string copy = binary;
while (copy.size() >= 8)
{
//Write byte to file
file.write(binary.substr(0, 8).c_str(), 8);
copy.replace(0, 8, "");
}
file.close();
}
In the function above the binary parameter looks like this: 0100100001100101011011000110110001101111
With the help of "aschelper" I was able to create a solution for this problem. I converted the binary string to its usual representation, before writing it to the file. My code is below:
// binary is a string of 0s and 1s. it will be converted to a usual string before writing it into the file.
void WriteBinary(const string& path, const string& binary)
{
ofstream file;
file.open(path);
string copy = binary;
while (copy.size() >= 8)
{
char realChar = ByteToChar(copy.substr(0, 8).c_str());
file.write(&realChar, 1);
copy.replace(0, 8, "");
}
file.close();
}
// Convert a binary string to a usual string
string BinaryToString(const string& binary)
{
stringstream sstream(binary);
string output;
while (sstream.good())
{
bitset<8> bits;
sstream >> bits;
char c = char(bits.to_ulong());
output += c;
}
return output;
}
// convert a byte to a character
char ByteToChar(const char* str) {
char parsed = 0;
for (int i = 0; i < 8; i++) {
if (str[i] == '1') {
parsed |= 1 << (7 - i);
}
}
return parsed;
}

How do I get input for file streams correctly using a function with pointer and string parameters?

I am working on a file assignment for C++ and am having a difficult time distinguishing the test code in main, from what I'm supposed to have my logic doing in my functions. For instance, I need to implement the function:
Here is the code I'm using to test with:
int main()
{
std::string filename = "cars.txt";
std::ifstream fin;
bool isOpen = GetInputFileStream(&fin, filename);
if (isOpen == false)
{
std::cout << "Couldn't find file " << filename << "!" << std::endl;
}
else
{
double newTotalPrice = 0;
double newTotalMileage = 0;
double usedTotalPrice = 0;
double usedTotalMileage = 0;
int numUsed = 0;
int numNew = 0;
AnalyzeFile(fin, numUsed, numNew, newTotalPrice, newTotalMileage,
usedTotalPrice, usedTotalMileage);
PrintStatistics(std::cout, numUsed, numNew, newTotalPrice, newTotalMileage,
usedTotalPrice, usedTotalMileage);
}
}
Here is the function (one of many) I need to implement:
bool GetInputFileStream(std::ifstream * fin, std::string filename)
{
}
The caller will supply a pointer to an input file stream object. I will use this object to open an input file that has
the name filename. If the file doesn’t exist, alert the user by returning false.
You can either use some platform specific code (access() in unistd.h for unix systems) to tell if the file exists, or just assume if you fail to open it, it does not exist (see std::ifstream::good()).
See the documentation of std::ifstream::open():
void open (const char* filename, ios_base::openmode mode =
ios_base::in);
void open (const string& filename, ios_base::openmode
mode = ios_base::in);
The second function is only available in C++11.
So, if you don't care about why the file failed to open:
fin->open(filename);
return fin->good();
Before use any stream file you should check if the file exist and it can be done with function _stat:
bool existFile(string path)
{
struct _stat attributos;
int rstat;
rstat = _stat(path.c_str(), &attributos);
if (rstat == 0)
return true;
return false;
}
For Unix/Linux use the header #include <sys/stat.h>
For Windows use the header #include <windows.h>
And, as #dlasalle recommend you, use the function open(..) to get the file stream (ifstream) and do I\O operations, for example:
ifstream f;
f.open("c:\..\file", ios::out | ios::app);
if (f.is_open()) {
// Do anything
}
So, you function could be this:
bool GetInputFileStream(std::ifstream& fin, std::string filename)
{
bool eFile = existFile(filename);
if(eFile)
{
fin.open(filename, ios::in);
}
return eFile;
}
Check that I change the parameter std::ifstream* fin to std::ifstream& fin, that's meaning you must invoke your function as:
std::ifstream fin;
bool isOpen = GetInputFileStream(fin, filename);
UPDATE: Answering your question:
ifstream* GetInputFileStream(bool& eFile, string filename)
{
ifstream* fin = NULL;
eFile = existFile(filename);
if(eFile)
{
fin = new ifstream();
fin->open(filename, ios::in);
}
return fin;
}
And you can get the pointer to ifstream in this way:
bool bExist;
string path;
ifstream* fin = GetInputFileStream(bExist, path);

Appending and reading binary file

I am confused as to where in my code am I getting it wrong. Instead of resulting to 1,2,3 the output is 1,1,1. Any suggestions as to what I can do? I am guessing my error lies either in the writing data or when I use the variable value.
class Binary
{
public:
Binary(int num);
~Binary();
void createBinary();
void writeBinary();
void readBinary();
string binFile;
int value;
fstream binaryFile;
};
Binary::Binary(int num)
{
value = num;
binFile = "BinaryFile.bin";
}
Binary::~Binary()
{
}
void Binary::createBinary()
{
binaryFile.open(binFile, ios::out | ios::binary);
binaryFile.close();
}
void Binary::writeBinary()
{
if (!binaryFile) //if file does not exist
{
createBinary();
}
binaryFile.open(binFile, ios::app | ios::binary);
binaryFile.write((char*)&value, sizeof(value));
binaryFile.close();
}
void Binary::readBinary()
{
binaryFile.open(binFile, ios::in |ios::binary);
binaryFile.read((char*)&value, sizeof(value));
binaryFile.close();
cout << value << ", ";
}
int main()
{
Binary num1(1);
Binary num2(2);
Binary num3(3);
num1.writeBinary();
num2.writeBinary();
num3.writeBinary();
num1.readBinary();
num2.readBinary();
num3.readBinary();
return 0;
}
Since you use a single file and read from start at each Binary()::readBinary(), your result is as expected. Either use different files for each of your objects.
// In general we may need some random part in name but for this special case,
// since you are just writing / reading value, the following seems to work.
Binary::Binary(int num)
{
value = num;
binFile = "BinaryFile"; // common start
binFile += std::to_string(value); // differentiator
binFile += ".bin"; // extension
}
Or, if you want to use the same file, try to get help from a static variable for not to read the same line again and again.

Reading Binary Files into an array of ints c++

I have a method which writes a binary file from an int array. (it could be wrong too)
void bcdEncoder::writeBinaryFile(unsigned int packedBcdArray[], int size)
{
fstream binaryIo;
binaryIo.open("PridePrejudice.bin", ios::out| ios::binary | ios::trunc);
binaryIo.seekp(0);
binaryIo.write((char*)packedBcdArray, size * sizeof(packedBcdArray[0]));
binaryIo.seekp(0);
binaryIo.close();
}
I need to now read that binary file back. And preferably have it read it back into another array of unsigned ints without any information loss.
I have something like the following code, but I have no idea on how reading binary files really works, and no idea how to read it into an array of ints.
void bcdEncoder::readBinaryFile(string fileName)
{
// myArray = my dnynamic int array
fstream binaryIo;
binaryIo.open(fileName, ios::in | ios::binary | ios::trunc);
binaryIo.seekp(0);
binaryIo.seekg(0);
binaryIo.read((int*)myArray, size * sizeof(myFile));
binaryIo.close();
}
Question:
How to complete the implementation of the function that reads binary files?
If you're using C++, use the nice std library.
vector<unsigned int> bcdEncoder::readBinaryFile(string fileName)
{
vector<unsigned int> ret; //std::list may be preferable for large files
ifstream in{ fileName };
unsigned int current;
while (in.good()) {
in >> current;
ret.emplace_back(current);
}
return ret;
}
Writing is just as simple (for this we'll accept an int[] but an std library would be preferable):
void bcdEncoder::writeBinaryFile(string fileName, unsigned int arr[], size_t len)
{
ofstream f { fileName };
for (size_t i = 0; i < len; i++)
f << arr[i];
}
Here's the same thing but with an std::vector
void bcdEncoder::writeBinaryFile(string fileName, vector<unsigned int> arr)
{
ofstream f { fileName };
for (auto&& i : arr)
f << i;
}
To simplify read operation consider storing size (i.e the number of elements in the array) before the data:
void bcdEncoder::writeBinaryFile(unsigned int packedBcdArray[], int size)
{
fstream binaryIo;
binaryIo.open("PridePrejudice.bin", ios::out| ios::binary | ios::trunc);
binaryIo.seekp(0);
binaryIo.write(&size, sizeof(size));
binaryIo.write((char*)packedBcdArray, size * sizeof(packedBcdArray[0]));
binaryIo.close();
}
The read would look something like:
void bcdEncoder::readBinaryFile(string fileName)
{
std::vector<unsigned int> myData;
int size;
fstream binaryIo;
binaryIo.open(fileName, ios::in | ios::binary | ios::trunc);
binaryIo.read(&size, sizeof(size)); // read the number of elements
myData.resize(size); // allocate memory for an array
binaryIo.read(myData.data(), size * sizeof(myData.value_type));
binaryIo.close();
// todo: do something with myData
}
Modern alternative using std::array
Here's a code snippet that uses more modern C++ to read a binary file into an std::array.
const int arraySize = 9216; // Hard-coded
std::array<uint8_t, arraySize> fileArray;
std::ifstream binaryFile("<my-binary-file>", std::ios::in | std::ios::binary);
if (binaryFile.is_open()) {
binaryFile.read(reinterpret_cast<char*>(fileArray.data()), arraySize);
}
Because you're using an std::array you'll need to know the exact size of the file during compile-time. If you don't know the size of the file ahead of time (or rather, you'll need to know that the file has at least X bytes available), use a std::vector and look at this example here: https://stackoverflow.com/a/36661779/1576548
Thanks for the tips guys, looks like I worked it out!! A major part of my problem was that half the arguments and syntax I added to the methods were not required, and actually messed things up. Here are my working methods.
void bcdEncoder::writeBinaryFile(unsigned int packedBcdArray[], int size, string fileName)
{
ofstream binaryIo;
binaryIo.open(fileName.substr(0, fileName.length() - 4) + ".bin", ios::binary);
if (binaryIo.is_open()) {
binaryIo.write((char*)packedBcdArray, size * sizeof(packedBcdArray[0]));
binaryIo.close();
// Send binary file to reader
readBinaryFile(fileName.substr(0, fileName.length() - 4) + ".bin", size);
}
else
cout << "Error writing bin file..." << endl;
}
And the read:
void bcdEncoder::readBinaryFile(string fileName, int size)
{
AllocateArray packedData(size);
unsigned int *packedArray = packedData.createIntArray();
ifstream binaryIo;
binaryIo.open(fileName, ios::binary);
if (binaryIo.is_open()) {
binaryIo.read((char*)packedArray, size * sizeof(packedArray[0]));
binaryIo.close();
decodeBCD(packedArray, size * 5, fileName);
}
else
cout << "Error reading bin file..." << endl;
}
With the AllocateArray being my class that creates dynamic arrays without vectors somewhat safely with destructors included.

Reading short from file

I'm trying to read a short from a binary file, but I end up with a lot of 0's
This is the write function
void AudioBuffer::WriteToFile(const string& strFilename)
{
fstream fout(strFilename.c_str(), ios::out|ios::binary);
short sample;
for (VECTOR_SHORT_ITER iter = m_vectorSamples.begin(); iter != m_vectorSamples.end(); iter++)
{
sample = (short) *iter;
fout.write((char *) &sample, sizeof(short));
}
fout.close();
}
And this is what I've got for the reading function, I'm aware of the possible overflow with atoi
void AudioBuffer::FileToBuffer(const string& strFilename)
{
fstream fin(strFilename.c_str(), ios::in|ios::binary);
short iSample;
char *temp = new char[sizeof(short)];
cout<<"Samples Output"<<endl;
while(!fin.eof())
{
fin.read(temp,sizeof(short));
iSample = atoi(temp);
cout<<iSample< " ";
m_vectorSamples.push_back(iSample);
*temp = NULL;
}
fin.close();
}
Also, clearing the char pointer by doing the *temp = NULL isn't the best thing right?
Thanks
Since you're just writing raw bits into the file, you want to read the same way, something on this order:
void AudioBuffer::FileToBuffer(const string& strFilename)
{
ifstream fin(strFilename.c_str(), ios::in|ios::binary);
short iSample;
cout<<"Samples Output"<<endl;
while(fin.read((char *)&iSample,sizeof(short)))
{
cout<<iSample<< " ";
m_vectorSamples.push_back(iSample);
}
}