I'm trying to get better understanding of endianness when someone read a file.
The machine i'm using is little endian.
The code down below is supposed to read any file type.
But what if the file we are reading is in UTF-16BE encoding, should we after reading the whole file change the endianness?
I'm asking this becouse i'm planing on editing the content of the file and output it in console.
In case we should change the endianness, how can that be done?
Right now i'm reading the files like this:
std::ifstream file("/RANDOME/PATH/file.html", std::ios::in | std::ios::binary);
std::string result;
file.seekg(0, std::ios::end);
result.reserve(t.tellg());
file.seekg(0, std::ios::beg);
result.assign((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
file.close();
I have no idea how to change the endianness from Big to little when reading a file. Can someone kindly show me step by step how that is done correctly?
i'm only trying to learn. I know the file is using UTF-16BE encoding that is not a guess.
Here is some code that does what you want. Note that this code reads the input file a line at a time rather than reading it all in one fell swoop.
#include <string>
#include <fstream>
void swap_bytes (char16_t *s)
{
while (*s)
{
unsigned char *uc = (unsigned char *) s;
unsigned char swap = *uc;
*uc = uc [1];
uc [1] = swap;
++s;
}
}
int main ()
{
std::basic_ifstream <char16_t> file ("/RANDOME/PATH/file.html", std::ios::in);
if (!file)
return 1;
std::basic_string <char16_t> line;
while (std::getline (file, line))
{
swap_bytes (line.data ());
// ...
}
file.close();
}
If anything is unclear please say so in the comments.
Live demo
Related
I am currently working with files in c++ and I want to read a file after a certain position. I read online that you can't open a file to read and write simultaneously. Is there a way to return the position of the file pointer at a certain moment and use it to extract the information after it?
What you read was wrong.
#include <fstream>
#include <string>
int main()
{
std::fstream file("test.txt", std::ios::in | std::ios::out | std::ios::binary);
std::string s;
file >> s;
// get current read position
auto read_pos = file.tellg();
// set current write position
file.seekp(read_pos, std::ios::beg);
static const char data[] = "aaa";
// write some data
file.write(data, 3);
}
I need to read a jpg file to a string. I want to upload this file to our server, I just find out that the API requires a string as the data of this pic. I followed the suggestions in a former question I've asked Upload pics to a server using c++ .
int main() {
ifstream fin("cloud.jpg");
ofstream fout("test.jpg");//for testing purpose, to see if the string is a right copy
ostringstream ostrm;
unsigned char tmp;
int count = 0;
while ( fin >> tmp ) {
++count;//for testing purpose
ostrm << tmp;
}
string data( ostrm.str() );
cout << count << endl;//ouput 60! Definitely not the right size
fout << string;//only 60 bytes
return 0;
}
Why it stops at 60? It's a strange character at 60, and what should I do to read the jpg to a string?
UPDATE
Almost there, but after using the suggested method, when I rewrite the string to the output file, it distorted. Find out that I should also specify that the ofstream is in binary mode by ofstream::binary. Done!
By the way what's the difference between ifstream::binary & ios::binary, is there any abbreviation for ofstream::binary?
Open the file in binary mode, otherwise it will have funny behavior, and it will handle certain non-text characters in inappropriate ways, at least on Windows.
ifstream fin("cloud.jpg", ios::binary);
Also, instead of a while loop, you can just read the whole file in one shot:
ostrm << fin.rdbuf();
You shouldn't read the file to a string because it is legal for a jpg to contain values that are 0. However in a string, the value 0 has a special meaning (it's the end of string indicator aka \0). You should instead read the file into a vector. You can do this easily like so:
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
int main(int argc, char* argv[])
{
std::ifstream ifs("C:\\Users\\Borgleader\\Documents\\Rapptz.h");
if(!ifs)
{
return -1;
}
std::vector<char> data = std::vector<char>(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
//If you really need it in a string you can initialize it the same way as the vector
std::string data2 = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
std::for_each(data.begin(), data.end(), [](char c) { std::cout << c; });
std::cin.get();
return 0;
}
Try opening the file in binary mode:
ifstream fin("cloud.jpg", std::ios::binary);
At a guess, you were probably trying to read the file on Windows and the 61st character was probably 0x26 -- a control-Z, which (on Windows) will be treated as marking the end of the file.
As far as how to best do the reading, you end up with a choice between simplicity and speed, as demonstrated in a previous answer.
I want to write a program that opens the binary file and encrypts it using DES.
But how can I read the binary file?
"how can I read the binary file?"
If you want to read the binary file and then process its data (encrypt it, compress, etc.), then it seems reasonable to load it into the memory in a form that will be easy to work with. I recommend you to use std::vector<BYTE> where BYTE is an unsigned char:
#include <fstream>
#include <vector>
typedef unsigned char BYTE;
std::vector<BYTE> readFile(const char* filename)
{
// open the file:
std::streampos fileSize;
std::ifstream file(filename, std::ios::binary);
// get its size:
file.seekg(0, std::ios::end);
fileSize = file.tellg();
file.seekg(0, std::ios::beg);
// read the data:
std::vector<BYTE> fileData(fileSize);
file.read((char*) &fileData[0], fileSize);
return fileData;
}
with this function you can easily load your file into the vector like this:
std::vector<BYTE> fileData = readfile("myfile.bin");
Hope this helps :)
I'm having some trouble reading and writing binary information. I can successfully write a simple string to a text file, in this case, my file 'output.dat' contains the sentence "Hello, this is a sentence".
However, I cannot read my information back. I cannot identify the problem. I intend to change every byte of the information read from the binary file later on so returning the value as a string helps.
Thanks for any help you can provide.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void write(const string &input) {
fstream output("output.dat", ios::out | ios::binary);
if (output.is_open()) {
output.write(input.c_str(), input.size());
output.close();
}
}
string read(const string &fname) {
int size;
char* buffer;
fstream input(fname, ios::in | ios::binary);
if (input.is_open()) {
input.seekg(0, ios::end);
size = input.tellg();
input.seekg(0, ios::beg);
buffer = new char[size];
input.read(buffer, size);
input.close();
}
string result(buffer);
return result;
}
int main () {
cout << read("output.dat") << endl;
system("pause");
return 0;
}
The bug is here.
char* buffer;
input.read(buffer, size);
You're reading to the memory that buffer is pointing to.
But where is it pointing to? The pointer buffer has never been initialized.
If you know how much space you need, an approach like this will work.
std::vector<char> buffer(size);
input.read(&buffer.front(), size);
I really cannot understand what is going wrong in this code, as it looks fine, and works fine with me. Nevertheless, the buffer you are allocating is missing the null terminator to mark char-string end. Just change it to this:
buffer = new char[size+1];
input.read(buffer, size);
buffer[size] = 0;
I am writing a C++ program to read an exe file. I wrote it and I test it on a text file instead of exe file. it was true.
when I test it with an exe file I understand that my exe file have 0x00 value in it (not at its end). so my while loop stop before end of file because I used:
class A{
private:
ifstream myFile;
void Read(char *filename)
};
void A::Read(char *str)
{
myFile.open(str,ios::binary);
while (!myFile.eof())
{
InputFile.get(ch);
myString.push_back(ch);
}
}
what should I do? if I should use size of the file, how can i get it?
You must open the file stream with the std::ios::binary mode flag.
As James McNellis pointed out you need to open the file in binary mode: Try something like the following:
#include <iostream>
#include <fstream>
int main()
{
std::ifstream in("main.obj", std::ios_base::binary);
std::streamsize bytes_read = 0;
if (in.is_open())
{
while (!in.eof())
{
char buf[1024];
// Use unformatted read.
in.read(buf, 1024);
if (in.gcount() > 0)
{
// The first 'in.gcount()' chars in
// 'buf' were read.
bytes_read += in.gcount();
}
}
}
in.close();
std::cout << "bytes read=" << bytes_read << "\n";
return 0;
}
EDIT:
Example modified to use get():
#include <iostream>
#include <fstream>
int main()
{
std::ifstream in("main.obj", std::ios_base::binary);
std::streamsize bytes_read = 0;
if (in.is_open())
{
while (!in.eof())
{
in.get();
if (1 == in.gcount())
{
bytes_read++;
}
}
}
in.close();
std::cout << "bytes read=" << bytes_read << "\n";
return 0;
}
Tested and works correctly.
In addition to opening the file in binary mode, the current code has a subtle bug which will cause the last character in the file to be read twice. The problem is that the myFile.eof() call does not do what you think it does. It does not tell you when you're at the end of the file. It tells you that you have tried to read beyond the end of the file. The idiomatic way to write a read-until-eof loop in C++ is:
while (myFile.get(ch))
myString.push_back(ch);
get returns an istream reference which, in this context, is implicitly convertible to bool and is used to indicate that there is no more data to read.
Only a hunch here, but my suspicion is that you're actually reading the whole file correctly, but measuring it wrong.
File reading (with binary mode) won't stop on a 0-byte, but there are several string related methods that will.
For example, you can't measure the size of a binary "blob" using strlen(), you can't copy it using strcpy().
Without seeing the actual way you're storing and measuring the data, it's hard to see where things go wrong, but I strongly suspect that you're actually reading the whole file correctly if you're using binary mode.
I found my mistake, The program read all the bytes but I cout that bytes in a vector<char>, So it's obvious I saw just bytes before 0x00.