ofstream ofs1("file1.dat", ios::out | ios::binary);
unsigned char data[64] = {0};
ofs1.write((char*) &data, sizeof(data));
if (some_condition)
{
ofstream ofs2("file2.dat", ios::out | ios::binary);
ofs2 << ofs1.rdbuf();// This does not work.
}
unsigned char more_data[32] = {1};
ofs1.write((char*) &more_data, sizeof(more_data));
As expected, file1.dat is 96 bytes in size after executing the code. However, file2.dat is 0 bytes, where I would expect it to be 64 bytes. Apparently ofstream::rdbuf() is always empty, or is it not supposed to be used like this?
Practical use for this: an application that writes several files using the same header (e.g. a colour palette). In this code example the contents of data (colour palette) are static, but it can obviously be replaced by a more complex computation, which would be overkill to repeat for each output file...
Your issue is that an ofstream by default opens its buffer in output mode only, and either way you're only passing std::ios_base::out, which means the buffer cannot be read from.
To fix this you will need to switch to using an fstream and open it with std::ios_base::in | std::ios_base::out | std::ios_base::binary.
You will also need to seek to the start of the file before calling rdbufby calling seekg(0, std::ios_base::beg).
Related
I am trying to read specific binary data (2 Bytes) of a file and this mission works well, the problem when rewriting that (2 Bytes) again in the same place. Unfortunately, it changes the entire file data to zeros.
Look at the following two screenshots:
Data before writing:
Data after writing:
The code:
bool myClass::countChanger() {
std::ifstream sggFileObj_r(this->sggFilePath, std::ios::binary);
if (!sggFileObj_r.is_open()) {
std::cerr << strerror(errno) << std::endl;
return false;
}
// Buffer variable
unsigned short count;
// Move the file pointer to offset 4
sggFileObj_r.seekg(4);
// Reading data
sggFileObj_r.read((char*)&count, sizeof(unsigned short));
sggFileObj_r.close();
//// ---------------------- ////
std::ofstream sggFileObj_w(this->sggFilePath, std::ios::binary | std::ios::app);
// Increase the buffer variable by one
count += 1;
// Move the file pointer again to offset 4
sggFileObj_w.seekp(4);
// Rewriting data again to the file after modification
sggFileObj_w.write((char*)&count, sizeof(unsigned short));
sggFileObj_w.close();
return true;
}
Why did that happen and how to resolve?
UPDATE:
I have appended std::ios::app to file mode, and zeros problem solved but the specific data that I want to update is not updated.
Using
std::ofstream sggFileObj_w(this->sggFilePath, std::ios::binary)
will wipe out the data in the file since that is what ofstream does by default. You can use
std::ofstream sggFileObj_w(this->sggFilePath, std::ios::binary | std::ios::app);
to stop the data from being overridden but the issue with this is that file stream starts at the end of the file and pretends like the rest of the file doesn't exist, so you can seek back to the beggining and overwrite its contents.
What you can do instead is use a fstream like
std::fstream sggFileObj_w(this->sggFilePath, std::ios::binary | std::ios::out | std::ios::in);
To open the file in binary mode from the beginning without losing any contents. Then you can seek to where you want to write into the file.
I'm new to C++, I have an image named "test.jpg", i convert it to base64 and decode it again like this:
std::ifstream inputFile;
inputFile.open("test.jpg",std::ios::binary);
std::filebuf* pbuf = inputFile.rdbuf();
inputFile.seekg (0, ios::end);
int length = inputFile.tellg();
// allocate memory to contain file data
char* buffer=new char[length];
// get file data
pbuf->sgetn (buffer,length);
inputFile.close();
CBase64 base64;
string encodedData = base64.base64_encode((unsigned char*)buffer,length);
delete[] buffer;
string decodedData = base64.base64_decode(encodedData);
ofstream outPutFile;
outPutFile.open("test2.jpg",ios::binary | ios::out);
outPutFile.write(decodedData.c_str(), decodedData.length());
outPutFile.close();
the "test2.jpg" has exact same size as "test.jpg"(the original file) but, i can't open it.
i couldn't find what is the problem.
i got it working. i just replaced:
outPutFile.open("test2.jpg",ios::binary | ios::out);
with
outPutFile.open("test2.jpg", ios_base::out | ios_base::binary);
std::string path = "file.txt";
std::string cfgString = "data";
std::ofstream output(path.c_str(), ios_base::out | std::ios::binary);
if (output.is_open()) {
output.write(cfgString.data(), cfgString.length());
}
output.close();
Apparently, there is no superficial problem with your file writing logic even though there are some irregularities. The biggest problem is in your main logic.
The program seems to be simple program of copying a file. What you are doing is reading a file, converting its data to base64 string and then again decoding the data to std::string. Now one small problem. Conversion of base64 string cannot be successfully done into a null terminated ANSI string for obvious reasons that any 0 in decoded binary data will terminate the string prematurely. Secondly you are opening a file in binary mode to write but trying to write std::string in the file. But that doesn't matter as you data has already been corrupted in your previous operation.
To solve this, you can simply use file copying example as this or make sure you write only binary data with care to your output file which means read in binary from input file and write to output file the same buffer. No base64 encoding decoding is required.
it looks like you forgot to write
inputFile.seekg (0, ios::beg);
after getting file length. it means you try to read from the end of the file instead of its beginning.
The reader and writer
#include<string>
#include<fstream>
#include<memory>
class BinarySearchFile{
BinarySearchFile::BinarySearchFile(std::string file_name){
// concatenate extension to fileName
file_name += ".dat";
// form complete table data filename
data_file_name = file_name;
// create or reopen table data file for reading and writing
binary_search_file.open(data_file_name, std::ios::binary); // create file
if(!binary_search_file.is_open()){
binary_search_file.clear();
binary_search_file.open(data_file_name, std::ios::out | std::ios::binary);
binary_search_file.close();
binary_search_file.open(data_file_name), std::ios::out | std::ios::in | std::ios::binary | std::ios::ate;
}
std::fstream binary_search_file;
void BinarySearchFile::writeT(std::string attribute){
if(binary_search_file){
binary_search_file.write(reinterpret_cast<char *>(&attribute), attribute.length() * 2);
}
}
std::string BinarySearchFile::readT(long filePointerLocation, long sizeOfData)
{
if(binary_search_file){
std::string data;
data.resize(sizeOfData);
binary_search_file.seekp(filePointerLocation);
binary_search_file.seekg(filePointerLocation);
binary_search_file.read(&data[0], sizeOfData);
return data;
}
};
The reader call
while (true){
std::unique_ptr<BinarySearchFile> data_file(new BinarySearchFile("classroom.dat"));
std::string attribute_value = data_file->read_data(0, 20);
}
The writer call
data_file->write_data("packard ");
The writer writes a total of 50 bytes
"packard 101 500 "
The reader is to read the first 20 bytes and the result is "X packard X" where X represents some malformed bytes of data. Why is the data read back in x-number of bytes corrupt?
You can't simply write data out by casting it's address to a char* and hoping to get anything useful. You have to define the binary format you want to use, and implement it. In the case of std::string, this may mean outputing the length in some format, then the actual data. Or in the case where fixed length fields are needed, forcing the string (or a copy of the string) to that length using std::string::resize, then outputting that, using std::string::data() to get your char const*.
Reading will, of course, be similar. You'll read the data into a std::vector<char> (or for fixed length fields, a char[]), and parse it.
binary_search_file.write(reinterpret_cast<char *>(&attribute), attribute.length() * 2);
It is incorrect to cast std::string to char* if you need char* you must use attribute.c_str().
std::string apart from string pointer contains other data members, for example, allocator, your code will write all of that data to file. Also I don't see any reason to multiply string length by 2. +1 makes sense if you want to output terminating zero.
I'm running a windows c++ multithreaded app in which one instance/thread of the server class is appending to the file. Other threads run client instances which only load up the file upon
each client's startup.
When I get to within 2k bytes of the end of loading the file I check to see if the file has changed
in size, so I know to update how many total bytes to read. Once in a while the file size
I get back is erroneously determined to be zero(0). I am using the stat call below for this. When zero is returned, then as a sanity check, I then call getFileSizeWithTellg() to see what it returns and it returns the expected non-zero value. A value that is the same or greater than the initial value.
I realize that the cast to unsigned int could be problematic, but the files are never
larger than 5 mgBytes.
What could be causing the stat() call to return a zero value, when the ..Tellg call doesn't?
Thanks for any insight into this.
/
/ snippets from methods in different classes
//
// from client class
ifstream fileSeqIn
fileSeqIn.open(fName.c_str(), ios::in | ios::binary |ios::ate);
// to get initial size
size = fileSeqIn.tellg();
fileSeqIn.seekg(0, ios::beg);
// later to determine if the file has grown
struct stat filestatus;
unsigned int size;
if (stat(fName, &filestatus ) == 0) {
size = (unsigned int)filestatus.st_size;
}
//
unsigned int getFileSizeWithTellg(char *fname)
{
// get length of file
is.open (fname, ios::binary );
is.seekg (0, ios::end);
length = is.tellg();
is.close();
return(length);
}
//-----------------------------------------------------------------------------
// from server class
ofstream fileSeqOut;
fileSeqOut.open(fName.c_str(), ios::app | ios::out |ios::ate |ios::binary);
One significant difference: stat returns the system's view of the size of the file; tellg returns a value dependend on the internal state of the stream. File bases streams are buffered, and the data may not be passed on to the system until you flush or close the file. Do you get the same difference if you precede the call to stat with a flush of the stream?
If what Larry Osterman said is true, using GetFileInformationByHandle might solve the problem.
Everytime I read in by fstream I got 1 extra character at the end, How can I avoid this?
EDIT:
ifstream readfile(inputFile);
ofstream writefile(outputFile);
char c;
while(!readfile.eof()){
readfile >> c;
//c = shiftChar(c, RIGHT, shift);
writefile << c;
}
readfile.close();
writefile.close();
This typically results from testing for the end of file incorrectly. You normally want to do something like:
while (infile>>variable) ...
or:
while (std::getline(infile, whatever)) ...
but NOT:
while (infile.good()) ...
or:
while (!infile.eof()) ...
The first two do a read, check whether it failed, and if so exit the loop. The latter two attempt a read, process what's now in the variable, and then exit the loop on the next iteration if the previous attempt failed. On the last iteration, what's in the variable after the failed read will normally be whatever was in it previously, so loops like either of the second two will typically appear to process the last item in the file twice.
To copy one file to another easily, consider using something like this:
// open the files:
ifstream readfile(inputFile);
ofstream writefile(outputFile);
// do the copy:
writefile << readfile.rdbuf();
This works well for small files, but can slow down substantially for a larger file. In such a case, you typically want to use a loop, reading from one file and writeing to the other. This also has possibilities for subtle errors as well. One way that's been tested and generally work reasonably well looks like this:
std::ifstream input(in_filename, std::ios::binary);
std::ofstream output(out_filename, std::ios::binary);
const size_t buffer_size = 512 * 1024;
char buffer[buffer_size];
std::size_t read_size;
while (input.read(buffer, buffer_size), (read_size = input.gcount()) > 0)
output.write(buffer, input.gcount());
Based on the code, it appears what you're trying to do is copy the contents of one file to another?
If so, I'd try something like this:
ifstream fin(inputFile, ios::binary);
fin.seekg(0, ios::end);
long fileSize = fin.tellg();
fin.seekg(0, ios::beg);
char *pBuff = new char[fileSize];
fin.read(pBuff, fileSize);
fin.close();
ofstream fout(outputFile, ios::binary)
fout.write(pBuff, fileSize);
fout.close;
delete [] pBuff;