Reading Binary file till the end c++ [duplicate] - c++

I am trying to read a string from a binary file but cant seem to get it to work. I am a pretty new to c++. Can anybody help please? Thanks.
string Name = "Shaun";
unsigned short int StringLength = 0;
int main()
{
StringLength = Name.size();
ofstream oFile("File.txt", ios::binary|ios::out);
oFile.write((char*)&StringLength, sizeof(unsigned short int));
oFile.write(Name.c_str(), StringLength);
oFile.close();
StringLength = 0;
Name = "NoName";
ifstream iFile("File.txt", ios::binary|ios::in);
if(!iFile.is_open())
cout << "Failed" << endl;
else
{
iFile.read((char *)&StringLength, sizeof(unsigned short int));
iFile.read((char *)&Name, StringLength);
}
cout << StringLength << " " << Name << endl;
system("Pause>NUL");
return 0;
}

This is the problematic line.
iFile.read((char *)&Name, StringLength);
You are reading the char* part of a std::string directly into the memory of Name.
You need to save both the size of the string as well as the string so that when you read the data, you would know how much memory you need to read the data.
Instead of
oFile.write(Name.c_str(), StringLength);
You would need:
size_t len = Name.size();
oFile.write(&len, sizeof(size_t));
oFile.write(Name.c_str(), len);
On the way back, you would need:
iFile.read(&len, sizeof(size_t));
char* temp = new char[len+1];
iFile.read(temp, len);
temp[len] = '\0';
Name = temp;
delete [] temp;

you need to create a buffer of char type.
char *buffer = new char[size];
Then use your buffer as the parameter to read function
iFile.read(buffer, size);

Instead of this
iFile.read((char *)&Name, StringLength);
Try this:
Name.resize(StringLength);
iFile.read((char *)&Name[0], StringLength);
Your original line overwrites the string object data from the beginning, which may contain the string length and capacity, for instance, instead of the character data. Also you don't resize the string appropriately to be able to contain the data.

Conceptually, you need to understand the data stream which you are reading. Not everything use ASCII which uses a byte size of 8 bits. I also notice you did not set bit size read which can be as little as one bit to as large as {R, B, G, A} color set. Using your basic 2 dimensional reiteration structured code.

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;

read structure from binary file having pointer pointed to memory

struct st {
char *p;
int len;
};
this is the structure which i need to write to a binary file, along with the string which is saved in
char *p
I am supposed to write a binary file with the char array data. After writing to binary file. Is should also be able to read it in the same structure from binary file.
I tried using FSEEK_END to get the binary size, and doing fread according to file size, but it is not saving string. Please suggest. Any help/suggestion/pointer would be appreciated.
thanks in advance.
sample code:
struct st {
char *p;
int len;
};
struct st varr;
varr.len = 100;
varr.p = new char[gen];
strcpy(varr.p, "Hello World");
FILE *p;
p=fopen("address","wb");
fwrite(&varr,sizeof(struct st),1,p);
fclose(p);
this will write me the pointer to the binary file. But i want to write here whole string, but the point is, it should done with one fwrite.
There is no use writing this to a binary file. A text file would suffice.
However, if this is your homework assignment (or so), I suggest you proceed as follows:
write the length as an integer;
write len bytes of the string. This does not include a terminating null.
When reading back:
read the integer length;
allocate memory of this length plus one byte
read the string into that memory and add the terminating null.
Fill your structure with this length and the pointer to allocated memory.
In your comments you keep iterating you want to read and write in one step. With your current data structure that is not possible because the character string wil always be somewhere else in memory and fwrite can only write a contiguous block of memory.
However, would you change your data structure to:
struct st{
char p[128];
int len;
};
then you can write and read in one go because now the struct is a contiguous memory block. But now the string is limited to this 128 bytes(or any size you make it).
I would suggest saving the strlen(p) first, followed by all the chars pointed by char *p. If you try to fwrite the struct as it is, you'll end up (in the file) with the value for the address with regrads to the first char. You do not want to save the address of the 1st char, do you?
If you are so much concerned about not having two fwrite you can have wrapper structure with zero length array.
struct st_wrap {
int len;
char p[0];
};
struct st_wrap *temp= malloc (sizeof (struct st_wrap ) + strlen(varr.p)+1);
temp->len = strlen(varr.p);
//Copy the data
strcpy(temp->p,varr.p);
//Then write it to file
fwrite(temp,sizeof(struct st_wrap)+strlen(varr.p),1,p);
Assuming you have written the length and string to binary file:
FILE* fp = fopen("file.bin", "wb");
/* writing */
st str = { .p = "foo", .len = 3 };
fwrite((char*)(&str.len), sizeof(str.len), sizeof(str.len), fp);
fwrite(str.p, str.len, str.len, fp);
You can now (in a different context) read the content from file into the struct object:
FILE* fp = fopen("file.bin", "rb");
st str;
/* read length */
fread((char*)&str.len, sizeof(str.len), sizeof(str.len), fp);
/* allocate enough space */
str.p = malloc((str.len + 1) * sizeof(char));
/* read string */
fread(str.p, str.len + 1, str.len + 1, fp);
Remember to free memory when you're done with p:
free(str.p);
I tried lot of ways, but #kiran Biradar's answer helped me a lot. hence displaying the working code here.
WriteBinaryFile.cpp
struct st_wrap {
int len;
int crc;
char p[0];
};
int main ()
{
char p[100] = "Hello World";
struct st_wrap *temp= (struct st_wrap*) malloc (sizeof (struct st_wrap ) + strlen(p)+1);
temp->len = strlen(p);
temp->crc = 400;
strcpy(temp->p,p);
cout << temp->p << endl;
cout << temp->len << endl;
cout << temp->crc << endl;
FILE *p1;
p1=fopen("binary.dat","wb");
fwrite(temp,sizeof(struct st_wrap)+strlen(p),1,p1);
fclose(p1);
}
ReadBinaryFile.cpp
struct st_wrap {
int len;
int crc;
char p[0];
};
int main ()
{
struct st_wrap *vw;
FILE *f=fopen("binary.dat","rb");
fseek(f, 0, SEEK_END);
long int filesize = ftell(f);
fseek(f, 0, SEEK_SET);
vw = (struct st_wrap*) malloc (filesize);
fread(vw,filesize,1,f);
cout << vw->len << endl;
cout << vw->p << endl;
cout << vw->crc << endl;
return 0;
}

How to find a string in a binary file?

I want to find a specific string "fileSize" in a binary file.
The purpose of finding that string is to get 4 bytes that next to the string because that 4 bytes contains the size of data that I want to read it.
The content of the binary file like the following:
The same string in another position:
Another position:
The following is the function that writes the data to a file:
void W_Data(char *readableFile, char *writableFile) {
ifstream RFile(readableFile, ios::binary);
ofstream WFile(writableFile, ios::binary | ios::app);
RFile.seekg(0, ios::end);
unsigned long size = (unsigned long)RFile.tellg();
RFile.seekg(0, ios::beg);
unsigned int bufferSize = 1024;
char *contentsBuffer = new char[bufferSize];
WFile.write("fileSize:", 9);
WFile.write((char*)&size, sizeof(unsigned long));
while (!RFile.eof()) {
RFile.read(contentsBuffer, bufferSize);
WFile.write(contentsBuffer, bufferSize);
}
RFile.close();
WFile.close();
delete contentsBuffer;
contentsBuffer = NULL;
}
Also, the function that searches for the string:
void R_Data(char *readableFile) {
ifstream RFile(readableFile, ios::binary);
const unsigned int bufferSize = 9;
char fileSize[bufferSize];
while (RFile.read(fileSize, bufferSize)) {
if (strcmp(fileSize, "fileSize:") == 0) {
cout << "Exists" << endl;
}
}
RFile.close();
}
How to find a specific string in a binary file?
I think of using find() is an easy way to search for patterns.
void R_Data(const std::string filename, const std::string pattern) {
std::ifstream(filename, std::ios::binary);
char buffer[1024];
while (file.read(buffer, 1024)) {
std::string temp(buffer, 1024);
std::size_t pos = 0, old = 0;
while (pos != std::string::npos) {
pos = temp.find(pattern, old);
old = pos + pattern.length();
if ( pos != std::string::npos )
std::cout << "Exists" << std::endl;
}
file.seekg(pattern.length()-1, std::ios::cur);
}
}
How to find a specific string in a binary file?
If you don't know the location of the string in the file, I suggest the following:
Find the size of the file.
Allocate memory for being able to read everything in the file.
Read everything from the file to the memory allocated.
Iterate over the contents of the file and use std::strcmp/std::strncmp to find the string.
Deallocate the memory once you are done using it.
There are couple of problems with using
const unsigned int bufferSize = 9;
char fileSize[bufferSize];
while (RFile.read(fileSize, bufferSize)) {
if (strcmp(fileSize, "filesize:") == 0) {
cout << "Exists" << endl;
}
}
Problem 1
The strcmp line will lead to undefined behavior when fileSize actually contains the string "fileSize:" since the variable has enough space only for 9 character. It needs an additional element to hold the terminating null character. You could use
const unsigned int bufferSize = 9;
char fileSize[bufferSize+1] = {0};
while (RFile.read(fileSize, bufferSize)) {
if (strcmp(fileSize, "filesize:") == 0) {
cout << "Exists" << endl;
}
}
to take care of that problem.
Problem 2
You are reading the contents of the file in blocks of 9.
First call to RFile.read reads the first block of 9 characters.
Second call to RFile.read reads the second block of 9 characters.
Third call to RFile.read reads the third block of 9 characters. etc.
Hence, unless the string "fileSize:" is at the boundary of one such blocks, the test
if (strcmp(fileSize, "filesize:") == 0)
will never pass.

c++ Reading string from binary file using fstream

I am trying to read a string from a binary file but cant seem to get it to work. I am a pretty new to c++. Can anybody help please? Thanks.
string Name = "Shaun";
unsigned short int StringLength = 0;
int main()
{
StringLength = Name.size();
ofstream oFile("File.txt", ios::binary|ios::out);
oFile.write((char*)&StringLength, sizeof(unsigned short int));
oFile.write(Name.c_str(), StringLength);
oFile.close();
StringLength = 0;
Name = "NoName";
ifstream iFile("File.txt", ios::binary|ios::in);
if(!iFile.is_open())
cout << "Failed" << endl;
else
{
iFile.read((char *)&StringLength, sizeof(unsigned short int));
iFile.read((char *)&Name, StringLength);
}
cout << StringLength << " " << Name << endl;
system("Pause>NUL");
return 0;
}
This is the problematic line.
iFile.read((char *)&Name, StringLength);
You are reading the char* part of a std::string directly into the memory of Name.
You need to save both the size of the string as well as the string so that when you read the data, you would know how much memory you need to read the data.
Instead of
oFile.write(Name.c_str(), StringLength);
You would need:
size_t len = Name.size();
oFile.write(&len, sizeof(size_t));
oFile.write(Name.c_str(), len);
On the way back, you would need:
iFile.read(&len, sizeof(size_t));
char* temp = new char[len+1];
iFile.read(temp, len);
temp[len] = '\0';
Name = temp;
delete [] temp;
you need to create a buffer of char type.
char *buffer = new char[size];
Then use your buffer as the parameter to read function
iFile.read(buffer, size);
Instead of this
iFile.read((char *)&Name, StringLength);
Try this:
Name.resize(StringLength);
iFile.read((char *)&Name[0], StringLength);
Your original line overwrites the string object data from the beginning, which may contain the string length and capacity, for instance, instead of the character data. Also you don't resize the string appropriately to be able to contain the data.
Conceptually, you need to understand the data stream which you are reading. Not everything use ASCII which uses a byte size of 8 bits. I also notice you did not set bit size read which can be as little as one bit to as large as {R, B, G, A} color set. Using your basic 2 dimensional reiteration structured code.

Concatenate multiple chars

I m reading a file and I would like to extract all of its contents and store them into a single char in C++. I know it can be done with strings however I cannot use strings and need to resort to char instead. I can I concatenate multiple chars to one char variable?
Here is what I've tried so far:
string str = "";
ifstream file("c:/path.....");
while (file.good())
{
str += file.get();
}
const char* content = str.c_str();
printf("%c", *content);
but this just gave me the first letter of the file and that's it.
If also tried:
ifstream file("c:/path.....");
char c = ' ';
char result[100];
while (file.good())
{
c= file.get();
strcat(result,c);
}
but this gave me runtime errors all the time.
For the second try you gave in your question (which I guess from your other hints, is what you finally want), you can try the following as a quick fix:
ifstream file("c:/path.....");
char c[2] = { 0, 0 };
char result[100] = { 0 };
for (int i = 0; file && (i < 99); ++i)
{
c[0] = file.get();
strcat(result,c);
}
Since using strcat() might not be very efficient for this use case, I think a better implementation would directly write to the result buffer:
ifstream file("c:/path.....");
char result[100] = { 0 };
for (int i = 0; file && (i < 99); ++i)
{
result[i] = file.get();
}
In your first code block:
const char* content = str.c_str();
printf("%c", *content);
prints only the first character of the string because *contents dereferences the
pointer to the (first character of) the string, and %c is the printf-format for
a single character. You should replace that by
printf("%s", content);
to print the entire string. Or just use
std::cout << str;
Maybe something like that :
char result[100];
int i = 0;
while (file.good())
{
c= file.get();
if(i<100)
result[i++]=c;
}
result[i]='\0';
There a lot of things to improve in this solution (what would you do if there more then 99 chars in your file, file.good() not the best option for loop condition, and so on...). Also it is much better to use strings.I don't know exactly why you can't use them, but just in case you change your mind you can read your file like that :
std::string line;
while ( getline(stream, line)) {
process(line);
}
You can create std::strings of your characters and concatenate them:
char c1 = 'a';
char c2 = 'b';
std::string concatted = std::string(1, c1) + std::string(1, c2);
This works because of the fill std::string constructor, see the reference.
Obviously, you are new to the c++ or at least you're using some strange terminology.
First of all, I advice you to read some c++ literature for beginners (you can find list of it on stackoverflow). Then you will understand all the conceptions of strings in c++.
Second, use this code to read file content and store it in a char*.
FILE *f = fopen("path to file", "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
char *content = new char[fsize + 1];
fread(content, fsize, 1, f);
fclose(f);
content[fsize] = 0;
cout << "{" << content <<"}";
delete content;