I'm trying to create a compression program but I need to know the basics of how to open a file in binary and print out its contents.
In a text file, called "Tester.txt", I have this:
MJ
In a .cpp file, I have this:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main
{
fstream istr;
istr.open("Tester.txt", ios::binary);
}
From my understanding in the cplusplus reference, this uses a stream object to open the file specified in binary?
But I'm stuck on how exactly I can "print" out the first byte of the file, i.e. the letter M in binary?
I know that M (capital letter) in binary is 01001101.
So how do I do a cout of M in binary?
Thanks
You have a confusion between numbers and representations of numbers, probably created by the fact that the word "binary" can sometimes be used to describe both. When you open a file in "binary mode", that means you see the raw values of the bytes in the file. This has nothing to do with "binary" in the sense of representing numbers in base two.
Say a file has "x" followed by a newline and a return. In "binary mode", you will see that as three byte-size values, one containing the ASCII code for "x", one containing the ASCII code for newline, and one containing the ASCII code for return. These are values that you read from the file. You can represent them in binary, but you can also represent them in decimal or hex, you still have read the exact same values from the file.
Reading a file in "binary" determines the values you read, not how you represent them. Two cars are the same two cars whether you represent the value two as "2" (decimal), "10" (binary), or "two" (English).
Binary input/output on streams is done using their member functions read() and write().
Like this:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main
{
fstream istr;
istr.open("Tester.txt", ios::binary);
if (istr) {
// Read one byte
char byte;
if (!istr.read(&byte, 1)) {
// Error when reading
}
// Alternative way to read one byte (thanks to DyP)
byte = istr.get();
// Another alternative:
if (!istr.get(byte)) {
// Error when reading.
}
// Read a block of bytes:
char buffer[1024];
if (!istr.read(buffer, 1024)) {
// Read error, or EOF reached before 1024 bytes were read.
}
}
}
Here is a quick program which uses the C++ Standard Library to do all the heavy lifting.
#include <iostream>
#include <iterator>
#include <bitset>
#include <algorithm>
int main() {
std::istreambuf_iterator< char > in( std::cin ), in_end;
std::ostream_iterator< std::bitset< 8 > > out( std::cout, " " );
std::copy( in, in_end, out );
std::cout << '\n';
}
See it run. I used std::cin for demonstration, but you should open a file with std::ios::binary and pass that instead.
Since each variable is only used once, this could all be done on one line. Even if you open the file instead of using std::cin.
EDIT:
std::copy is a function encapsulating the loop for ( ; in != in_end; ++ in ) * out ++ = * in;.
The type std::istreambuf_iterator either takes an istream constructor argument and provides an iterator in suitable for such a loop, or takes no constructor argument and provides an iterator in_end such that in == in_end if in.eof() == true. The iterator gets unformatted bytes (type char) from the stream.
The type std::ostream_iterator< std::bitset< 8 > > provides an iterator out so * out ++ = x converts x to std::bitset< 8 > and prints the result. In this case x is a byte and bitset provides a constructor for such a byte value, and overloads operator<< to print a binary representation of 1's and 0's.
To output a value in binary you need to do it manually as the standard library does not support that output format.
int mask = 0x80;
while(mask)
{
std::cout << (byteValue & mask ? '1' : '0');
mask >>= 1;
}
std::cout << std::endl;
This will scan from the top bit to the low bit and print out a value representing each one.
try this:
#include <fstream>
#include <iostream>
#include <string>
#include <bitset>
#include <iomanip>
int main()
{
// Set up your objects.
char c;
std::fstream istr("Tester.txt", ios::binary);
unsigned long loc = 0;
// Read the file one character at a time.
// Remembering not to skip white space in this situation.
for(;istr >> std::noskipws >> c;++loc)
{
// When printing compensate for non printable characters.
// If the character is outside the ASCII range then print it as an integer.
std::stringstream charStr;
if ((c < 32) || (c > 126))
{
charStr << "Char: " << c;
}
else
{
charStr << "Non Printable: " << static_cast<int>(c);
}
// Print the value and location in a nicely formatted way.
std::cout << std::setw(16) << location
<< " : "
<< std::bitset<8>(c).to_string() // Prints the character as an 8 bit binary value.
<< " : "
<< charStr.str()
<< "\n";
}
}
But there are standard tools that do this already:
Look at od
Related
I am new to C++. I have an assignment where I have to read a Little Endian Binary data file and in the data file I have to read every 2 Bytes and check for a header value. I have written the following code but I am not getting correct data. Can someone please guide me on how to approach for this problem.
std::vector<char> checkValues = { (char)0xCA5E , (char)0xBEAD };
std::ifstream input("abc.dat", std::ios::binary | std::ios::in);
if (input)
{
input.seekg(0, ios::end);
size_t fileSize = input.tellg();
input.seekg(0, ios::beg);
/*How to run loop here for every two byte*/
{
char * buffer = new char[2];
input.read(buffer, sizeof(buffer) / sizeof(*buffer));
std::vector<char>::iterator it = std::find(checkValues.begin(), checkValues.end(), buffer);
if (it != checkValues.end())
std::cout << "Element Found" << std::endl;
else
std::cout << "Element Not Found" << std::endl;
delete[] buffer;
}
}
I have doubts about my approach, I am still learning. Please if you can guide me towards a better solution that would be helpful. Thank you.
Basically your approach is not bad. And there is no optimum solution. There are roundabout 42 million solutions :-)
There are some necessary optimizations. They are all shown in the comments under your question.
Ands the while loop can simply be done with testing the filestream variable. The "bool operator !" is overloaded for that variable type. The result will be false in case of error. Also for eof (end of file).
I would like to show you the more "C++" or "Object Oriented" approach. You start thinking what you want to do and then derive the howto from that. Obviously you want to read something like 2 bytes and compare that 2 bytes with some given value. OK, then let us define a new class TwoBytes. We add some functions, so that the 2 bytes can be read from any istream. And since we want to compare later, we add the comparison operator. All very straight forward. And only one possible solution. You can add many more functions . . .
This should later give you the idea about software design or software architecture. When you a bit more experienced, you will maybe notice that this is the fun part.
So, please see the below as just an example.
#include <iostream>
#include <vector>
#include <array>
#include <fstream>
#include <algorithm>
#include <iterator>
using Byte = char;
// An ultra simple class
struct TwoBytes {
// Hold 2 bytes
std::array<Byte,2> tb;
// Define comparison operator
bool operator == (const TwoBytes& other) { return tb == other.tb; }
// And overlaod extractor operatror >> . With tha we can easily read 2 bytes
friend std::istream& operator >> (std::ifstream& ifs, TwoBytes& b) {
// In case of odd file size, we set the 2nd value to 0
b.tb[1] = 0;
return ifs >> b.tb[0] >> b.tb[1];
}
};
int main(void)
{
const TwoBytes compareValue1 = { '1', '2' };
const TwoBytes compareValue2 = { 0x34, 0x45 };
// Open the file
std::ifstream inputFileBinary("r:\\abc.dat", std::ios::binary);
// We will read the input data to this value
TwoBytes twoBytes{};
// This is the loop to read the values
while (inputFileBinary) {
// Read 2 bytes
inputFileBinary >> twoBytes;
// In case of odd file size, inputFileBinary would be false. So you could check with "if (inputFileBinary)"
// Compare values and show result
if (twoBytes == compareValue1 || twoBytes == compareValue2) {
std::cout << "Found value\n";
}
else {
std::cout << "Did not find value\n";
}
}
return 0;
}
I hope this helps a little . . .
I am having a string which contains the hex value:
string str = "e101";
I need to write this in a file as 2 bytes. While I am trying to write a file, it will write like the following 4 bytes value:
65 31 30 31
I am using the following operation for file write:
myfile.open ("file.cf3",std::ios::binary);
myfile << str << "\n";
myfile.close();
but I want to write it as a 2 bytes value.
For example, if i g How to write it as 2 bytes to a file?
std::string wut="b6306edf953a6ac8d17d70bda3e93f2a3816eac333d1ac78";
i want the output like
.0n..:j..}p...?*8...3..x
I think your question is ambiguous ...
Keep in mind that, from your string, every two char you have 1 byte (not two).
So you want to write two numbers (meaning in ascii) representing the hex value of the string...
If this is the right interpretation, you need to split the string in pairs of chars and then convert each one to the equivalent integer.
Here is my code ...
It writes out to stdout, but you can modify it easily in order to write to file instead to the screen.
#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <stdlib.h>
using namespace std;
int main () {
string str = "e101";
string two_char;
unsigned char byte;
for (int i=0 ; i<str.size(); i+=2) {
two_char = str.substr(i,2);
byte = strtol(two_char.c_str(),0,16);
cout << two_char << " " << (int)byte <<"\n";
}
}
Here is an example for a solution.
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ofstream file("file.txt", std::ios::binary);
if(!file.is_open()) {
return -1;
}
std::string str("e101");
for (std::size_t i = 0; i < str.length() - 1; ++++i) {
file << static_cast<char>(str[i] * 16 + str[i + 1]);
}
file.close();
}
You can simply iterate over your string and take two characters as one byte. You multiply the first character with 16 and add the second character.
In answer to your original question about writing 2-bytes out in binary to a file in C++, you have a basic 2-step process. (1) convert your string representation of the number to a numeric value using stoi with base 16. This provides a numeric values you can store in an unsigned short. (2) write that value out to your file with f.write, not frwite where f is your open stream reference.
If you want to format the output in hex for cout, then you must set the flags for cout to output numeric values in hex-format (though not directly part of your question, it ties in the stream I/O formatting if desired.)
So essentially you have your string and convert it to a number, e.g.
std::string str = "e101";
unsigned short u = stoi(str, 0, 16);
Now u holds a numeric value converted from the text in str using base-16 that you can simply write to your file as a 2-byte value, e.g.
std::string filename = "out.bin"; /* output filename */
...
std::ofstream f (filename, f.trunc | f.binary); /* open out in binary */
if (!f.write(reinterpret_cast<char*>(&u), sizeof u)) { /* write 2 bytes */
std::cerr << "error: write of short to file failed.\n";
return 1;
}
Putting it altogether, you could do something short that outputs the hex value being written with cout as well as writing it to the file "out.bin", e.g.
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
int main (void) {
std::string filename = "out.bin"; /* output filename */
std::string str = "e101";
unsigned short u = stoi(str, 0, 16);
/* output converted value to terminal in hex */
std::cout.setf(std::ios::hex, std::ios::basefield); /* set hex output */
std::cout << "writing value to file: " << u << '\n'; /* for cout */
/* output converted value to file */
std::ofstream f (filename, f.trunc | f.binary); /* open out in binary */
if (!f.write(reinterpret_cast<char*>(&u), sizeof u)) { /* write 2 bytes */
std::cerr << "error: write of short to file failed.\n";
return 1;
}
}
Example Use/Output
$ ./bin/stoi_short
writing value to file: e101
Resulting Output File
Confirm by dumping the contents of the file with a hexdump program, e.g.
$ hexdump out.bin
0000000 e101
0000002
Look things over and let me know if you have further questions.
I have a program that reads the hex of a file, modifies it, and stores the modified hex in a std::string.
For example, how would I write this to a file
std::string wut="b6306edf953a6ac8d17d70bda3e93f2a3816eac333d1ac78";
and get its value
.0n..:j..}p...?*8...3..x
in the outputted file?
I'd prefer not to use sprintf, but I guess if it's necessary, I'll do what I must.
If I understand your question correctly you want the text converted to it's numeric equivalent and then written to file. Given the hint you provided in your question it looks like this should be done byte by byte. Below is one way to achieve this. Note the need to convert each byte from a string to an integer value.
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <ios>
std::string wut = "b6306edf953a6ac8d17d70bda3e93f2a3816eac333d1ac78";
int main()
{
std::ofstream datafile("c:\\temp\\temp1.dat", std::ios_base::binary | std::ios_base::out);
char buf[3];
buf[2] = 0;
std::stringstream input(wut);
input.flags(std::ios_base::hex);
while (input)
{
input >> buf[0] >> buf[1];
long val = strtol(buf, nullptr, 16);
datafile << static_cast<unsigned char>(val & 0xff);
}
}
The answer of #Peter R will lead to an output which is not 100% equal, due to the stringstream interpreting more than one '0's in a row in an unintended way.
Example: If we want to write the hex value "00000000", the stringstream would output " 000000".
The solution below works in every case, no matter how many zeros are contained in the hex string:
// Input
std::string hex = "180f00005e2c3415"; // (or longer)
std::basic_string<uint8_t> bytes;
// Iterate over every pair of hex values in the input string (e.g. "18", "0f", ...)
for (size_t i = 0; i < hex.length(); i += 2)
{
uint16_t byte;
// Get current pair and store in nextbyte
std::string nextbyte = hex.substr(i, 2);
// Put the pair into an istringstream and stream it through std::hex for
// conversion into an integer value.
// This will calculate the byte value of your string-represented hex value.
std::istringstream(nextbyte) >> std::hex >> byte;
// As the stream above does not work with uint8 directly,
// we have to cast it now.
// As every pair can have a maximum value of "ff",
// which is "11111111" (8 bits), we will not lose any information during this cast.
// This line adds the current byte value to our final byte "array".
bytes.push_back(static_cast<uint8_t>(byte));
}
// we are now generating a string obj from our bytes-"array"
// this string object contains the non-human-readable binary byte values
// therefore, simply reading it would yield a String like ".0n..:j..}p...?*8...3..x"
// however, this is very useful to output it directly into a binary file like shown below
std::string result(begin(bytes), end(bytes));
Then you can simply write this string to a file like this:
std::ofstream output_file("filename", std::ios::binary | std::ios::out);
if (output_file.is_open())
{
output_file << result;
output_file.close();
}
else
{
std::cout << "Error could not create file." << std::endl;
}
I'm not sure what's happening, but I'm using an ofstream object to write to a file in binary mode.
I am writing a byte to a file, but the file is printing gibberish. It's printing this type of gibberish: ôß
I have a class called ByteOutput with a function called inByte defined as so:
void inByte(int byte)
{
ostreamObj.write(&buffer, byte & 255);
}
&buffer is a reference to a bit buffer I am using to store a byte of data
In my main, I defined an ofstream obj and opened a file in binary using:
obj.open("tester", std::ios::binary);
I write a byte of data to the file using a ByteOutput object using:
writeObj.inByte(1001011);
However, when I check the file, it is all hieroglyphics. It does not show the letter K, which has the binary presentation 1001011.
What am I doing wrong?
this
writeObj.inByte(1001011);
calls the function with an integer = 1,001,001 decimal, not binary.
If you want to use binary, consider hex or std::bitset
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
int a = 0x4B; // 01001011
bitset<8> bs(a);
cout << hex << a << endl;
cout << bs << endl;
}
if you output std::bitset to a file, every bit will be represented as a char, i.e., you will see 01001011 in you file.
I'm making a C++ program to be able to open a .bmp image and then being able to put it in a 2D array. Right now i have the code like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "Image.h"
using namespace std;
struct colour{
int red;
int green;
int blue;
};
Image::Image(string location){
fstream stream;
string tempStr;
stringstream strstr;
stream.open(location);
string completeStr;
while(!stream.eof()){
getline(stream, tempStr);
completeStr.append(tempStr);
}
cout << endl << completeStr;
Image::length = completeStr[0x13]*256 + completeStr[0x12];
Image::width = completeStr[0x17]*256 + completeStr[0x16];
cout << Image::length;
cout << Image::width;
cout << completeStr.length();
int hexInt;
int x = 0x36;
while(x < completeStr.length()){
strstr << noskipws << completeStr[x];
cout << x << ": ";
hexInt = strstr.get();
cout << hex << hexInt << " ";
if((x + 1)%3 == 0){
cout << endl;
}
x++;
}
}
Now if i run this on my test file of 256x256 it will print fine, until it reaches 0x36E where it gives an error / doesn't go further. This happens because the completeStr string doesn't recieve all the data that is in the bmp file. Why isn't able to read all the lines in the bmp file?
There are a number of problems with your code. The principal
one (and probably the reason for your problem) is that you are
opening the file in text mode. Technically, this means that if
the file contains anything but printable characters and a few
specific control characters (like '\t'), you have undefined
behavior. In practice, under Windows, this means that sequences
of 0x0D, 0x0A will be converted into a single '\n', and that
a 0x1A will be interpreted as the end of the file. Not really
what one wants when reading binary data. You should open the
stream in binary mode (std::ios_base::binary).
Not a serious error, but you shouldn't really use an fstream
if you are only going to read the file. In fact, using an
fstream should be very rare: you should use either ifstream
or ofstream. The same thing holds for stringstream (but
I don't see any role for stringstream when reading a binary
file).
Also (and this is a real error), you are using the results of
getline without checking whether is succeeded. The usual
idiom for reading lines would be:
while ( std::getline( source, ling ) ) ...
But like stringstream, you don't want to use getline on
a binary stream; it will remove all of the '\n' (which have
already been mapped from CRLF).
If you want all of the data in memory, the simplest solution is
something like:
std::ifstream source( location.c_str(), std::ios_base::binary );
if ( !source.is_open() ) {
// error handling...
}
std::vector<char> image( (std::istreambuf_iterator<char>( source ) ),
(std::istreambuf_iterator<char>()) );
std::getline reads in a line of text.
It's not useful for a binary file.
Open the file in binary mode and use unformatted input operations (like read).