Writing and reading in and from a binary file in c++ - c++

I am a beginner in working with files. What I want to do in my code is to get a name from the user, and hide it in a .bmp picture. And also be able to get the name again from the file. But I want to change the characters into ASCII codes first ( that's what my assignment says)
What I tried to do is to change the name's characters to ASCII codes, and then add them to the end of the bmp picture which I'll open in binary mode. And after adding them, i want to read them from the file and be able to get the name again.
This is what I've done so far. But I am not getting a proper result. All i get is some meaningless characters. Is this code even right?
int main()
{
cout<<"Enter your name"<< endl;
char * Text= new char [20];
cin>> Text; // getting the name
int size=0;
int i=0;
while( Text[i] !='\0')
{
size++;
i++;
}
int * BText= new int [size];
for(int i=0; i<size; i++)
{
BText[i]= (int) Text[i]; // having the ASCII codes of the characters.
}
fstream MyFile;
MyFile.open("Picture.bmp, ios::in | ios::binary |ios::app");
MyFile.seekg (0, ios::end);
ifstream::pos_type End = MyFile.tellg(); //End shows the end of the file before adding anything
// adding each of the ASCII codes to the end of the file.
int j=0;
while(j<size)
{
MyFile.write(reinterpret_cast <const char *>(&BText[j]), sizeof BText[j]);
j++;
}
MyFile.close();
char * Text2= new char[size*8];
MyFile.open("Picture.bmp, ios:: in , ios:: binary");
// putting the pointer to the place where the main file ended and start reading from there.
MyFile.seekg(End);
MyFile.read(Text2,size*8);
cout<<Text2<<endl;
MyFile.close();
system("pause");
return 0;
}

Many flaws are in your code, one important is:
MyFile.open("Picture.bmp, ios::in | ios::binary |ios::app");
Must be
MyFile.open("Picture.bmp", ios::in | ios::binary |ios::app);
^ ^
| |
+-----------+
Second, use std::string instead of C-style strings:
char * Text= new char [20];
should be
std::string Text;
Also, use std::vector to make a array:
int * BText= new int [size];
should be
std::vector<int> BText(size);
And so on...

You write int (which is 32 bits) but read char (which is 8 bits).
Why not write the string as-is? There's no need to convert it to an integer array.
And also, you don't terminate the array you read into.

your write operation is incorrect, you should pass the complete text directly
MyFile.write(reinterpret_cast <const char *>(BText), sizeof (*BText));
Also, casting your string to ints and back to chars will insert spaces between your characters which you don't take into account in your reading operation

Related

c++ read function getting extra letter

int main() {
int len;
cout<<"Enter the size of dynamic array you want: ";
cin>>len;
int file_len;
int *new_num;
ifstream in("test.txt");
in.seekg(0, ios::end);
file_len = in.tellg();
in.close();
if(file_len>len)
{
int times= file_len/len;
for(int i=0; i<times; i++)
{
ifstream in("test.txt");
if(i==0)
{
char *n_ch = new char[len];
in.seekg(0, ios::cur);
in.read(n_ch, len);
cout<<n_ch<<"\'";
delete n_ch;
} else {
char *n_ch = new char[len];
in.seekg(i*len, ios::cur);
in.read(n_ch, len);
cout<<",,"<<n_ch<<"..";
delete n_ch;
}
}
in.close();
}
return 0;
}
What I want to do is to get the nth to (n+len)th letters and put them into an array, and then print them.
right now I'm getting this result,
the content of test.txt is:
ABCDEABCDE
qwerty poiuy
zxcvb
mnbhhg
ooooo
I can't find the reason why I am getting extra letters, which i guess is the first letter of the next letters.
Is there a way to solve this problem?
After in.read(n_ch, len) you need to use gcount() to see how many characters were actually read. Say your file has 37 characters, and you're reading in chunks of 10: the last read will only return 7 characters and you want to make sure you only try to write 7 to the output (you can use cout.write(n_ch, gcount());).
You are reading C strings. C strings are null terminated, that is they need a null character at the end to indicate how long the string is. Your code doesn't do that. Try this
char *n_ch = new char[len + 1]; // one extra for the null terminator
in.seekg(0, ios::cur);
in.read(n_ch, len);
n_ch[len] = '\0'; // add the null terminator
cout<<n_ch<<"\'";
delete n_ch;

C++ From text file to Binary file

I've a task to copy elements from .txt file[direct access file] to .bin file[fixed length record file] (homework).
.txt file holds strings. Every line has one word.
I came up with code below, but I'm not sure if that's what is needed and even slighly correct. Any help will be useful! (I'm new to C++)
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int buffer_size = 30;
class Word{
char name[buffer_size];
public:
void setName () // Trying to get every word from a line
{
string STRING;
ifstream infile;
infile.open ("text.txt");
while(!infile.eof()) // To get you all the lines.
{
getline(infile,STRING); // Saves the line in STRING.
}
infile.close();
}
};
void write_record()
{
ofstream outFile;
outFile.open("binFILE.bin", ios::binary | ios::app);
Word obj;
obj.setName();
outFile.write((char*)&obj, sizeof(obj));
outFile.close();
}
int main()
{
write_record();
return 0;
}
NEW APPROACH:
class Word
{
char name[buffer_size];
public:
Word(string = "");
void setName ( string );
string getName() const;
};
void readWriteToFile(){
// Read .txt file content and write into .bin file
string temp;
Word object;
ofstream outFile("out.dat", ios::binary);
fstream fin ("text.txt", ios::in);
getline(fin, temp);
while(fin)
{
object.setName(temp);
outFile.write( reinterpret_cast< const char* >( &object ),sizeof(Word) );
getline(fin, temp);
}
fin.close();
outFile.close();
}
int main()
{
readWriteToFile();
return 0;
}
Word::Word(string nameValue)
{
setName(nameValue);
}
void Word::setName( string nameString )
{
// Max 30 char copy
const char *nameValue = nameString.data();
int len = strlen(nameValue);
len = ( len < 31 ? len : 30);
strncpy(name, nameValue, len);
name[len] = '\0';
}
string Word::getName() const
{
return name;
}
Quick commentary and walk through
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
Avoid using namespace std; while you are learning. It can lead to some really nasty, hard to pin-down bugs as your functions may be silently replaced by functions with the same name in the standard library.
const int buffer_size = 30;
class Word
{
char name[buffer_size];
Since it looks like you are allowed to use std::string why not use it here?
public:
void setName() // Trying to get every word from a line
Really bad name for a function that apparently is supposed to // Trying to get every word from a line
{
string STRING;
ifstream infile;
infile.open("text.txt");
while (!infile.eof()) // To get you all the lines.
{
getline(infile, STRING); // Saves the line in STRING.
}
Few things wrong here. One is the epic Why is iostream::eof inside a loop condition considered wrong?
Next is while the code reads each line, it doesn't do anything with the line. STRING is never stored anywhere.
Finally in a class that sounds as though it should contain and manage a single word, it reads all the words in the file. There may be a case for turning this function into a static factory that churns out a std::vector of Words.
infile.close();
}
};
void write_record()
{
ofstream outFile;
outFile.open("binFILE.bin", ios::binary | ios::app);
ios::app will add onto an existing file. This doesn't sound like what was described in the assignment description.
Word obj;
obj.setName();
We've already coverred the failings of the Word class.
outFile.write((char*) &obj, sizeof(obj));
Squirting an object into a stream without defining a data protocol or using any serialization is dangerous. It makes the file non-portable. You will find that some classes, vector and string prominent among these, do not contain their data. Writing a string to a file may get you nothing more than a count and an address that is almost certainly not valid when the file is loaded.
In this case all the object contains is an array of characters and that should write to file cleanly, but it will always write exactly 30 bytes and that may not be what you want.
outFile.close();
}
int main()
{
write_record();
return 0;
}
Since this is homework I'm not writing this sucker for you, but here are a few suggestions:
Read file line by line will get you started on the file reader. Your case is simpler because there is only one word on each line. Your teacher may throw a curveball and add more stuff onto a line, so you may want to test for that.
Read the words from the file into a std::vector. vector will make your job so easy that you might have time for other homework.
A very simplistic implementation is:
std::vector<std::string> words;
while (getline(infile, STRING)) // To get you all the lines.
{
words.push_back(STRING);
}
For writing the file back out in binary, I suggest going Pascal style. First write the length of the string in binary. Use a known, fixed width unsigned integer (no such thing as a negative string) and watch out for endian. Once the length is written, write only the number of characters you need to write.
Ignoring endian, you should have something like this:
uint32_t length = word.length(); // length will always be 32 bits
out.write((char*)&length, sizeof(length));
out.write(word.c_str(), length);
When you are done writing the writer, write a reader function so that you can test that the writer works correctly. Always test your code, and I recommend not writing anything until you know how you'll test it. Very often coming at a program from the test side first will find problems before they even have a chance to start.

ifstream wont read all integer

When i read TestData.txt file it gives me wrong output. What am i doing wrong. I am using int array so i can do MergeSort after saving data into array.
TestData.txt
-------------------
31791 564974 477059 269094 972335
739154 206345 634644 227684 398536
910177 507975 589785 67117 395140
598829 372499 364165 450187 996527
700285 263407 918021 661467 457544
656297 846316 221731 240676 68287
913 141702 845802 477617 109824
{
int myArray[1000];
int i;
//reading givin data
const char* filename= "TestData.txt";
ifstream file(filename);
if(file.is_open())
{
for(i = 0; i <=999; ++i)
{
file >> myArray[i];//storing data to array
}
}
Need to check if you ifstream is end of file, in that case you get garbage value from out of the file bound.
With One modification, the code would be OK.
Change:
for(i = 0; i <=999; ++i)
to:
for(i = 0; i <=999 && !file.eof(); ++i)
You are reading 1000 enties from your file which contains clearly less than 1000 integers.
The first values of your array must be correct, but after you reach the end of your file the operator>> will not ready anything.
For example here is one way to write it:
const char* filename= "TestData.txt";
std::vector<int> myArray;
std::ifstream file(filename);
if(file.is_open())
{
int v;
while(file >> v) {
myArray.push_back(v);
}
}
int if I'm not wrong can keep data from -32768 to 32767.
So if u have bigger values than that (which you have, from your source file), you won't have the results you are expecting.
btw, it would be nice to know also what output you are getting.

Getting weird number when trying to read a number from file

I'm trying to read a number from a text file, and I'm not allowed to use a binary file.
I've tried two methods to do this, and both return a strange result.
The first method:
char *theNumber;
int i = 0;
while(data>>text)
{
theNumber[i] = text;
i++;
}
returns some weird accented characters.
The second
int theNumber;
while(data>>text)
{
theNumber = text; // I tried theNumber<<text; as well
}
When I cout the result of this one it returns some big number when the text file contained 123.
string filename;
char text;
int p; //first prime number
int q; //second prime number
unsigned long long toBeEncrypted;
cout<<"Enter name of file to encrypt: ";
cin>>filename;
ifstream data;
ofstream encryptedData;
encryptedData.open("RSA_cipher.txt");
cout<<"Please enter two prime numbers:"<<endl;
p = getPrime(1);
q = getPrime(2);
//doing stuff with file
int theNumber;
data >> theNumber;
//int i = 0;
/*while(data>>text)
{
theNumber[i] = text;
i++;
}*/cout<<theNumber;
...//other stuff unrelated to the problem
This code:
char *theNumber;
int i = 0;
while(data>>text)
{
theNumber[i] = text;
i++;
}
Has Undefined Behavior, because you are using theNumber[i] to access an array which you haven't even allocated. You should have done:
char theNumber[255]; // Buffer size depends on the particular application
int i = 0;
while(data>>text)
{
theNumber[i] = text;  
i++;
}
The second attempt:
theNumber = text;
May or may not work, depending on how you defined text. This is impossible to answer without knowing the definition of text.
Anyway, if you want to read in a number from an input stream, just do:
int number;
data >> number;
UPDATE:
In the last code snippet you updated, the data stream is constructed, but never open. It is not associated to any file. Therefore, attempting to read from that stream won't succeed, and nothing will be stored into number (which is uninitialized).
ifstream data;
// data is not associated to any file after construction...
int theNumber;
data >> theNumber;
This does not create storage for your number.
char *theNumber;
It's a pointer. It points somewhere arbitrary, since you haven't assigned an address to it.
Try this.
char theNumber[10]; // Whatever size you need.
Or this.
int theNumber;
You didn't allocate any memory for char *theNumber;.
The theNumber points to a random location and you are printing random characters

Weird characters appear after writing to a textfile

I am currently trying to read a file, put extra backward slash () if it finds a backward slash, and write it to another file. The problem is, there are weird characters being printed inside the path.txt. I suspect that, the space characters from the file logdata is the root of this problem. Need advice how to solve this.
Here is the code:
// read a file
char str[256];
fstream file_op("C:\\logdata",ios::in);
file_op >> str;
file_op.close();
// finds the slash, and add additional slash
char newPath[MAX_PATH];
int newCount = 0;
for(int i=0; i < strlen(str); i++)
{
if(str[i] == '\\')
{
newPath[newCount++] = str[i];
}
newPath[newCount++] = str[i];
}
// write it to a different file
ofstream out("c:\\path.txt", ios::out | ios::binary);
out.write(newPath, strlen(newPath));
out.close();
Every char string in C has to end with character \0. It is an indicator that the string ends right there.
Your newPath array, after iterating through your for-loop is not correctly ended. It probably ends somewhere later, where \0 appears by accident in memory.
Try doing the following right after exiting the for-loop:
newPath[newCount]=0;
A safer way for using strings in C++, is to use std::string class over plain char arrays.
Try putting a string terminator in the buffer, after the loop :
newPath[newCount] = 0;