Reading and writing int to a binary file in C++ - c++

I am unclear about how reading long integers work. If I say
long int a[1]={666666}
ofstream o("ex",ios::binary);
o.write((char*)a,sizeof(a));
to store values to a file and want to read them back as it is
long int stor[1];
ifstream i("ex",ios::binary);
i.read((char*)stor,sizeof(stor));
how will I be able to display the same number as stored using the information stored in multiple bytes of character array?

o.write does not write character, it writes bytes (if flagged with ios::binary). The char-pointer is used because a char has length 1 Byte.
o.write((char*)a,sizeof(a));
(char*) a is the adress of what o.write should write. Then it writes sizeof(a) bytes to a file. There are no characters stored, just bytes.
If you open the file in a Hex-Editor you would see something like this if a is int i = 10:
0A 00 00 00 (4 Byte, on x64).
Reading is analogue.
Here is a working example:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main (int argc, char* argv[]){
const char* FILENAM = "a.txt";
int toStore = 10;
ofstream o(FILENAM,ios::binary);
o.write((char*)&toStore,sizeof(toStore));
o.close();
int toRestore=0;
ifstream i(FILENAM,ios::binary);
i.read((char*)&toRestore,sizeof(toRestore));
cout << toRestore << endl;
return 0;
}

Sorry I took so long to see your question.
I think the difference between binary is the binary will read and write the file as is. But the non-binary (i.e. text) mode will fix up the end-of-line '\n' with carriage-return '\r'. The fix-up will change back and forth between '\n' and '\r', or "\n\r" or "\r\n" or leave it as '\n'. What it does depends on whether the target operating system is Mac, Windows, Unix, etc.
I think if you are reading and writing an integer, it will read and write your integer fine and it will look correct. But if some byte(s) of the integer look like '\r' and '\n', then the integer will not read back correctly from the file.
Binary assures that reading back an int will always be correct. But you want text mode to format a file to be read in a text editor such as Windows's Notepad.

Related

Binary input of text file

Programming Principles and Practice says in the Chapter 11:
"In memory, we can represent the number 123 as an integer value (each int on 4 bytes) or as a string value (each character on 1 byte)".
I'm trying to understand what is stored in the memory, when reading binary a text file.
So I'm writing the content of the vector v.
If the input file contains this text: "test these words"
The output file shows these numbers: 1953719668 1701344288 1998611827 1935962735 168626701 168626701 168626701 168626701 168626701 168626701
I tried to convert each char of "test" to binary
and I have 01110100 01100101 01100101 01110100
and if I consider this as an integer of 4 bytes and convert it to decimal I get 1952802164, which is still different from the output.
How is this done correctly, so I can understand what's going on? Thanks!
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
#include<sstream>
#include <fstream>
#include <iomanip>
using namespace std;
template <class T>
char *as_bytes(T &i) // treat a T as a sequence of bytes
{
void *addr = &i; // get the address of the first byte of memory used to store the object
return static_cast<char *>(addr); // treat that memory as bytes
}
int main()
{
string iname{"11.9_in.txt"};
ifstream ifs {iname,ios_base::binary}; // note: stream mode
string oname{"11.9_out.txt"};
ofstream ofs {oname,ios_base::binary}; // note: stream mode
vector<int> v;
// read from binary file:
for(int x; ifs.read(as_bytes(x),sizeof(int)); ) // note: reading bytes
v.push_back(x);
for(int x : v)
ofs << x << ' ';
}
Let me assume you are using little-endian machine (for example, x86) and ASCII-compatible character code (such as Shift_JIS and UTF-8).
test is represented as 74 65 73 74 as binary data.
Using little-endian, higher bytes of muitl-byte integer is placed to higher address.
Therefore, reading thes as 4-byte integer, it will be interpreted as 0x74736574 and it is 1953719668 in decimal.

Reading multiple bytes from file and storing them for comparison in C++

I want to binary read a photo in 1460 bytes increments and compare consecutive packets for corrupted transmission. I have a python script that i wrote and want to translate in C++, however I'm not sure that what I intend to use is correct.
for i in range(0, fileSize-1):
buff=f.read(1460) // buff stores a packet of 1460 bytes where f is the opened file
secondPacket=''
for j in buff:
secondPacket+="{:02x}".format(j)
if(secondPacket==firstPacket):
print(f'Packet {i+1} identical with {i}')
firstPacket=secondPacket
I have found int fseek ( FILE * stream, long int offset, int origin ); but it's unclear if it reads the first byte that is located offset away from origin or everything in between.
Thanks for clarifications.
#include <iostream>
#include <fstream>
#include <array>
std::array<char, 1460> firstPacket;
std::array<char, 1460> secondPacket;
int i=0;
int main() {
std::ifstream file;
file.open("photo.jpg", std::ios::binary);
while (file.read(firstPacket.data(), firstPacket.size())){
++i;
if (firstPacket==secondPacket)
std::cout<<"Packet "<<i<<" is a copy of packet "<<i-1<<std::endl;
memcpy(&secondPacket, &firstPacket, firstPacket.size());
}
std::cout<<i; //tested to check if i iterate correctly
return 0;
}
This is the code i have so far which doesn't work.
fseek
doesn't read, it just moves the point where the next read operation should begin. If you read the file from start to end you don't need this.
To read binary data you want the aptly named std::istream::read. You can use it like this wih a fixed size buffer:
// char is one byte, could also be uint8_t, but then you would need a cast later on
std::array<char, 1460> bytes;
while(myInputStream.read(bytes.data(), bytes.size())) {
// do work with the read data
}

Writing preceding zeros with ofstream

I am writing a program that will read and write a file format that dictates the content of the file, byte by byte. The nature of this program is that the first two bytes details how many bytes are left in that part of the file, followed by another two bytes that indicates what the part of the file actually represents. This pattern is repeated for the length of the file. This means I have to write the exact numbers buffered by preceding zeros such that each component is the exact size it needs to be. I have written up a dummy file that illustrates my points:
#include <fstream>
#include <stdint.h>
int main() {
std::ofstream outputFile;
outputFile.open("test.txt",
std::ios::out | std::ios::ate | std::ios::binary);
const int16_t HEADER = 0x0002;
int16_t recordSize = 2*sizeof(int16_t);
int16_t version = 0x0258;
outputFile << recordSize << HEADER << version;
outputFile.close();
}
which writes a file named "test.txt" who's hex contents are:
34 32 36 30 30
and for those of us that can read straight hex this translates to:
42600
As you can see the preceding zeros are removed and my record is not what I was hoping it to be. Is there a way to use ofstream to buffer my numbers with zeros as I naively tried to do by using int16_t for all of the writes that I wanted to be exactly two bytes long? Is there another, possibly more stylistically correct way of doing this?
operator<< is for text formatting. You probably want to use .write() instead.
e.g.
outputFile.write(reinterpret_cast<char*>(&recordSize), sizeof(int16_t));
outputFile.write(reinterpret_cast<char*>(&HEADER), sizeof(int16_t));
// ...

C++ fwrite corrupts binary file

I'm trying to open an exe file and place input taken from the user and replace existing data (overwriting it) of the same length at specific locations. I can do this with my code, but I'm seeing data corruption in other parts of my file. This is my first time with C++, I've tried looking at everything I could to help myself, but I'm at a loss. Only thing I can think is that its related to a null string char at the end of 'char test1[100];' (If I read the documentation right). But doesnt help my issue of resolving the issue. See linked image for example from Hex Viewer of Output and Original
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *key;
key=fopen ("Testfile.exe","r+b");
char test1[100];
char test2[100];
printf("Test data to input:");
fgets(test1, sizeof test1, stdin);
printf("Second test data to input:");
fgets(test2, sizeof test2, stdin);
fseek (key,24523,SEEK_SET); //file offset location to begin write
fwrite (test1,1,sizeof(test1),key);
fseek (key,24582,SEEK_SET); //file offset location to begin write
fwrite (test2,1,sizeof(test2),key);
fseek (key,24889,SEEK_SET); //file offset location to begin write
fwrite (test2,1,sizeof(test2),key);
fclose(key);
printf ("Finished");
return(0);
}
After my initial edits, I was still fighting with a Null Terminator being written at the end of my string (and thus affecting operation of the edited exe file). After a bit more reading this is my final solution that works as intended without any weird data being written. I used scanf ("%10s") to ensure only my string was being used and to get rid of any Null Terminator. Does anyone see anything majorly wrong here or improvements to be made? Eventually I'd like to implement string length checking to ensure proper length was input by user. Thanks for everyone's help.
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *key;
key=fopen ("test.exe","r+b");
char test1[10];
char test2[32];
printf("Input Test1 data:");
scanf ("%10s",test1); //only read 10 Chars
printf("Input test2 data:");
scanf ("%32s",test2); //only read 32 Chars
fseek (key,24523,SEEK_SET); //file offset location to begin write
fputs (test1,key);
fseek (key,24582,SEEK_SET); //file offset location to begin write
fputs (test2,key);
fseek (key,24889,SEEK_SET); //file offset location to begin write
fputs (test2,key);
fclose(key);
printf ("Finished");
return(0);
}
It looks like you're to write a string into the exe file but actually you're writing a string padded with garbage values up to a length of 100 bytes.
If you just want to write the string, replace fwrite with fputs.
sizeof(array) gives the allocated size of the static array (100 in this case) , not the string length. string length is done via strlen() which doesn't include the terminating NULL character.
You have two problems.
First: you're writing 100 byte buffers which have not been initialized except via fgets()... everything not put in there by fgets() is whatever happened to be in memory (on the stack in this case).
Second: you're writing 100 bytes with each write however your seek does not advance to at least 100 bytes later, meaning the second write() in this snippet partially overwrites the first.

Need Convert Binary file to Txt file

I have a dat(binary) file but i wish to convert this file into Ascii (txt) file using c++ but i am very new in c++ programming.so I juct opend my 2 files:myBinaryfile and myTxtFile but I don't know how to read data from that dat file and then how to write those data into new txt file.so i want to write a c+ codes that takes in an input containing binary dat file, and converts it to Ascii txt in an output file. if this possible please help to write this codes. thanks
Sorry for asking same question again but still I didn’t solve my problem, I will explain it more clearly as follows: I have a txt file called “A.txt”, so I want to convert this into binary file (B.dat) and vice verse process. Two questions:
1. how to convert “A.txt” into “B.dat” in c++
2. how to convert “B.dat” into “C.txt” in c++ (need convert result of the 1st output again into new ascii file)
my text file is like (no header):
1st line: 1234.123 543.213 67543.210 1234.67 12.000
2nd line: 4234.423 843.200 60543.232 5634.60 72.012
it have more than 1000 lines in similar style (5 columns per one line).
Since I don’t have experiences in c++, I am struggle here, so need your helps. Many Thanks
All files are just a stream of bytes. You can open files in binary mode, or text mode. The later simply means that it may have extra newline handling.
If you want your text file to contain only safe human readable characters you could do something like base64 encode your binary data before saving it in the text file.
Very easy:
Create target or destination file
(a.k.a. open).
Open source file in binary mode,
which prevents OS from translating
the content.
Read an octet (byte) from source
file; unsigned char is a good
variable type for this.
Write the octet to the destination
using your favorite conversion, hex,
decimal, etc.
Repeat at 3 until the read fails.
Close all files.
Research these keywords: ifstream, ofstream, hex modifier, dec modifier, istream::read, ostream::write.
There are utilities and applications that already perform this operation. On the *nix and Cygwin side try od, *octal dump` and pipe the contents to a file.
There is the debug utility on MS-DOS system.
A popular format is:
AAAAAA bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb cccccccccccccccc
where:
AAAAAA -- Offset from beginning of file in hexadecimal or decimal.
bb -- Hex value of byte using ASCII text.
c -- Character representation of byte, '.' if the value is not printable.
Please edit your post to provide more details, including an example layout for the target file.
Edit:
A complex example (not tested):
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>
using namespace std;
const unsigned int READ_BUFFER_SIZE = 1024 * 1024;
const unsigned int WRITE_BUFFER_SIZE = 2 * READ_BUFFER_SIZE;
unsigned char read_buffer[READ_BUFFER_SIZE];
unsigned char write_buffer[WRITE_BUFFER_SIZE];
int main(void)
{
int program_status = EXIT_FAILURE;
static const char hex_chars[] = "0123456789ABCDEF";
do
{
ifstream srce_file("binary.dat", ios::binary);
if (!srce_file)
{
cerr << "Error opening input file." << endl;
break;
}
ofstream dest_file("binary.txt");
if (!dest_file)
{
cerr << "Error creating output file." << endl;
}
// While no read errors from reading a block of source data:
while (srce_file.read(&read_buffer[0], READ_BUFFER_SIZE))
{
// Get the number of bytes actually read.
const unsigned int bytes_read = srce_file.gcount();
// Define the index and byte variables outside
// of the loop to maybe save some execution time.
unsigned int i = 0;
unsigned char byte = 0;
// For each byte that was read:
for (i = 0; i < bytes_read; ++i)
{
// Get source, binary value.
byte = read_buffer[i];
// Convert the Most Significant nibble to an
// ASCII character using a lookup table.
// Write the character into the output buffer.
write_buffer[i * 2 + 0] = hex_chars[(byte >> 8)];
// Convert the Least Significant nibble to an
// ASCII character and put into output buffer.
write_buffer[i * 2 + 1] = hex_chars[byte & 0x0f];
}
// Write the output buffer to the output, text, file.
dest_file.write(&write_buffer[0], 2 * bytes_read);
// Flush the contents of the stream buffer as a precaution.
dest_file.flush();
}
dest_file.flush();
dest_file.close();
srce_file.close();
program_status = EXIT_SUCCESS;
} while (false);
return program_status;
}
The above program reads 1MB chunks from the binary file, converts to ASCII hex into an output buffer, then writes the chunk to the text file.
I think you are misunderstanding that the difference between a binary file and a test file is in the interpretation of the contents.