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;
Related
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
how can I convert istream to string, when my istream also includes newline characters and I don't want to escape whitespaces?
Thank you.
If you mean how to copy the whole std::istream into a std::string then there are many ways.
Here is one:
int main()
{
// here is your istream
std::ifstream ifs("test.txt");
// copy it to your string
std::string s;
for(char c; ifs.get(c); s += c) {}
// display
std::cout << s << '\n';
}
You can just allocate a string large enough for your whole file and read it at once:
ifstream fd(filename); // open your stream (here a file stream)
if (!fd)
exit(1);
fd.seekg(0, ios_base::end); // go to end of file
size_t filesize = fd.tellg(); // dtermine size to allocate
fd.seekg(0, ios_base::beg); // go to the begin of your file
string s; // create a new string
s.resize(filesize+1); // reserve enough space to read
fd.read(&s[0], filesize); // read all the file at one
size_t bytes_read = fd.gcount(); // it could be than less bytes are read
s.resize(bytes_read); // adapt size
You can use a istreambuf_iterator like
#include <iostream>
#include <string>
#include <fstream>
int main()
{
std::ifstream ifile("test.txt"); // open
std::string str(std::istreambuf_iterator<char>(ifile), {}); // initialize
std::cout << str; // display
}
I'm trying to read a binary file and I need to determine its size, but regardless of the method I've tried, I'm getting a size of zero.
For example:
fstream cbf(address, ios::binary | ios::in | ios::ate);
fstream::pos_type size = cbf.tellg(); // Returns 0.
char* chunk = new char[size];
cbf.read(chunk, size);
//...
If I were to use the following:
#include <sys/stat.h>
struct stat st;
stat(address.c_str(),&st);
int size = st.st_size;
The size is still zero. I've also tried the following, but it's still zero.
File* fp;
fp = open(address.c_str(), "rb");
How do I get the size of the file?
Thanks for the responses... I've identified the problem:
The binary file I was trying to access was created during the execution, and I just had forgotten to close it before trying to read from it...
Neither of your examples checks for failure. This program, using your first method, works perfectly well for me. It correctly identifies the size of /etc/passwd and the non-existence of /etc/motd.
#include <fstream>
#include <iostream>
#include <string>
void printSize(const std::string& address) {
std::fstream motd(address.c_str(), std::ios::binary|std::ios::in|std::ios::ate);
if(motd) {
std::fstream::pos_type size = motd.tellg();
std::cout << address << " " << size << "\n";
} else {
perror(address.c_str());
}
}
int main () {
printSize("/etc/motd");
printSize("/etc/passwd");
}
Try to load the file in this method.
Note: Use ifstream insted of fstream in this line ifstream cbf(address, ios::binary | ios::in );
long size;
ifstream cbf(address, ios::binary | ios::in);
cbf.seekg(0, ios::end);
size=cbf.tellg();
cbf.seekg(0, ios::beg);
char* chunk = new char[size];
cbf.read(chunk, size);
#include <iostream>
#include <fstream>
int main() {
std::ofstream outfile("text.txt", ios::trunc);
std::ifstream infile("text.txt", ios::trunc);
outfile.seekp(0);
std::cout << "This is a file";
infile.seekg(0, ios::end);
int length = infile.tellg();
infile.read(0, length);
infile.close();
outfile.close();
return 0;
}
I think I get the idea behind this, but I feel like (and I'm pretty sure) I have no idea what I'm doing. I've looked it up and everything has confused me. I've read through a C++ reference, and then I googled it, but I still don't understand what I'm doing wrong.
#include <iostream>
#include <fstream>
#include <cstring>
int main() {
std::fstream file("text.txt", std::ios_base::in | std::ios_base::out);
file << "This is a file";
int length = file.tellg();
std::string uberstring;
file >> uberstring;
std::cout << uberstring;
char *buffer = new char[length + 1];
file.read(buffer, length);
buffer[length] = '\0';
file.close();
delete [] buffer;
return 0;
}
I tried this, but it isn't printing anything. Why isn't this working?
If you want to read and write to the same file, just use a normal std::fstream ... there is no need to attempt and open the same file as both a ifstream and ofstream. Also if you want to write data to the file, use the operator<< on the actual fstream instance object, not std::cout ... that will simply write to wherever std::cout is set, which is typically the console. Finally, the call to read has to go back into a buffer, you can't use NULL as an argument. So your code would change to the following:
int main()
{
std::fstream file("text.txt", ios_base::in | ios_base::out);
//outfile.seekp(0); <== not needed since you just opened the file
file << "This is a file"; //<== use the std::fstream instance "file"
//file.seekg(0, ios::end); <== not needed ... you're already at the end
int length = file.tellg();
//you have to read back into a buffer
char* buffer = new char[length + 1];
infile.read(buffer, length);
buffer[length] = '\0'; //<== NULL terminate the string
file.close();
delete [] buffer;
return 0;
}
I'm trying to write code to read a binary file into a buffer, then write the buffer to another file. I have the following code, but the buffer only stores a couple of ASCII characters from the first line in the file and nothing else.
int length;
char * buffer;
ifstream is;
is.open ("C:\\Final.gif", ios::binary );
// get length of file:
is.seekg (0, ios::end);
length = is.tellg();
is.seekg (0, ios::beg);
// allocate memory:
buffer = new char [length];
// read data as a block:
is.read (buffer,length);
is.close();
FILE *pFile;
pFile = fopen ("C:\\myfile.gif", "w");
fwrite (buffer , 1 , sizeof(buffer) , pFile );
If you want to do this the C++ way, do it like this:
#include <fstream>
#include <iterator>
#include <algorithm>
int main()
{
std::ifstream input( "C:\\Final.gif", std::ios::binary );
std::ofstream output( "C:\\myfile.gif", std::ios::binary );
std::copy(
std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>( ),
std::ostreambuf_iterator<char>(output));
}
If you need that data in a buffer to modify it or something, do this:
#include <fstream>
#include <iterator>
#include <vector>
int main()
{
std::ifstream input( "C:\\Final.gif", std::ios::binary );
// copies all data into buffer
std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(input), {});
}
Here is a short example, the C++ way using rdbuf. I got this from the web. I can't find my original source on this:
#include <fstream>
#include <iostream>
int main ()
{
std::ifstream f1 ("C:\\me.txt",std::fstream::binary);
std::ofstream f2 ("C:\\me2.doc",std::fstream::trunc|std::fstream::binary);
f2<<f1.rdbuf();
return 0;
}
sizeof(buffer) == sizeof(char*)
Use length instead.
Also, better to use fopen with "wb"....
sizeof(buffer) is the size of a pointer on your last line NOT the actual size of the buffer.
You need to use "length" that you already established instead
You should pass length into fwrite instead of sizeof(buffer).
Here is implementation of standard C++ 14 using vectors and tuples to Read and Write Text,Binary and Hex files.
Snippet code :
try {
if (file_type == BINARY_FILE) {
/*Open the stream in binary mode.*/
std::ifstream bin_file(file_name, std::ios::binary);
if (bin_file.good()) {
/*Read Binary data using streambuffer iterators.*/
std::vector<uint8_t> v_buf((std::istreambuf_iterator<char>(bin_file)), (std::istreambuf_iterator<char>()));
vec_buf = v_buf;
bin_file.close();
}
else {
throw std::exception();
}
}
else if (file_type == ASCII_FILE) {
/*Open the stream in default mode.*/
std::ifstream ascii_file(file_name);
string ascii_data;
if (ascii_file.good()) {
/*Read ASCII data using getline*/
while (getline(ascii_file, ascii_data))
str_buf += ascii_data + "\n";
ascii_file.close();
}
else {
throw std::exception();
}
}
else if (file_type == HEX_FILE) {
/*Open the stream in default mode.*/
std::ifstream hex_file(file_name);
if (hex_file.good()) {
/*Read Hex data using streambuffer iterators.*/
std::vector<char> h_buf((std::istreambuf_iterator<char>(hex_file)), (std::istreambuf_iterator<char>()));
string hex_str_buf(h_buf.begin(), h_buf.end());
hex_buf = hex_str_buf;
hex_file.close();
}
else {
throw std::exception();
}
}
}
Full Source code can be found here
There is a much simpler way. This does not care if it is binary or text file.
Use noskipws.
char buf[SZ];
ifstream f("file");
int i;
for(i=0; f >> noskipws >> buffer[i]; i++);
ofstream f2("writeto");
for(int j=0; j < i; j++) f2 << noskipws << buffer[j];
Or you can just use string instead of the buffer.
string s; char c;
ifstream f("image.jpg");
while(f >> noskipws >> c) s += c;
ofstream f2("copy.jpg");
f2 << s;
normally stream skips white space characters like space or new line, tab and all other control characters.
But noskipws makes all the characters transferred.
So this will not only copy a text file but also a binary file.
And stream uses buffer internally, I assume the speed won't be slow.
It can be done with simple commands in the following snippet.
Copies the whole file of any size. No size constraint!
Just use this. Tested And Working!!
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
ifstream infile;
infile.open("source.pdf",ios::binary|ios::in);
ofstream outfile;
outfile.open("temppdf.pdf",ios::binary|ios::out);
int buffer[2];
while(infile.read((char *)&buffer,sizeof(buffer)))
{
outfile.write((char *)&buffer,sizeof(buffer));
}
infile.close();
outfile.close();
return 0;
}
Having a smaller buffer size would be helpful in copying tiny files. Even "char buffer[2]"
would do the job.