std::stringstream and std::ios::binary - c++

I want to write to a std::stringstream without any transformation of, say line endings.
I have the following code:
void decrypt(std::istream& input, std::ostream& output)
{
while (input.good())
{
char c = input.get()
c ^= mask;
output.put(c);
if (output.bad())
{
throw std::runtime_error("Output to stream failed.");
}
}
}
The following code works like a charm:
std::ifstream input("foo.enc", std::ios::binary);
std::ofstream output("foo.txt", std::ios::binary);
decrypt(input, output);
If I use a the following code, I run into the std::runtime_error where output is in error state.
std::ifstream input("foo.enc", std::ios::binary);
std::stringstream output(std::ios::binary);
decrypt(input, output);
If I remove the std::ios::binary the decrypt function completes without error, but I end up with CR,CR,LF as line endings.
I am using VS2008 and have not yet tested the code on gcc. Is this the way it supposed to behave or is MS's implementation of std::stringstream broken?
Any ideas how I can get the contents into a std::stringstream in the proper format? I tried putting the contents into a std::string and then using write() and it also had the same result.

AFAIK, the binary flag only applies to fstream, and stringstream never does linefeed conversion, so it is at most useless here.
Moreover, the flags passed to stringstream's ctor should contain in, out or both. In your case, out is necessary (or better yet, use an ostringstream) otherwise, the stream is in not in output mode, which is why writing to it fails.
stringstream ctor's "mode" parameter has a default value of in|out, which explains why things are working properly when you don't pass any argument.

Try to use
std::stringstream output(std::stringstream::out|std::stringstream::binary);

Related

How to append to a std::fstream after you got to the end (std::fstream::eof() is true)

I open a file like this (Because it's part of an exercise and it may require overwriting the file):
#include <fstream> //std::fstream.
std::fstream file("file.txt", std::ios::in | std::ios::out);
And let's say I have read a file until the end (To get to the end of the file).
std::string tmp_buff;
while(std::getline(file, tmp_buff)) {}
file.seekp(file.tellg());
Now I have got to the end of the stream, How do I append to the file from here. Because if I just try to write like regularly, it will fail (It will not actually write):
file << "Text";
The only solution I have found is to reopen the file at the end of the file:
if(file.eof())
{
file.close();
file.open("file.txt", std::ios::in | std::ios::out | std::ios::app);
file << '\n';
}
Any help would be appreciated.
First, there is no need to state std::ios::in and std::ios::out when using a fstream because they are there the default value in the constructor. (it is actually std::ios_base::in/out to be more exact. std::ios (std::basic_ios<char>) inherits from std::ios_base)
So std::fstream file(filename) works the same.
The problem here is how C++ streams work.
When the file is read completely, the eofbit is set. After that, another reading happens which will trigger the failbit because there is nothing to read and the stream's bool conversion operator returns false and it exits the loop.
The bits will stay on until they are cleared. And while they are on, the stream doesn't do anything.
So to clear them:
file.clear();
Will do the work. You can use the stream after that.

C++ file handle

I am trying to implement a file handle class similar to the one in Bjarne Stroustrup's FAQ page. (Scroll to "Why doesn't C++ provide a 'finally' construct".) Unlike his example, however, I want to use C++ file streams instead of a FILE*.
Right now, I am considering creating a FileHandleBase class, or something similarly named, and two derived classes—one for input files and one for output files. Below is the implementation I wrote as a proof-of-concept; keep in mind that it is very simple and unfinished.
class FileHandle {
public:
FileHandle(const char* fn, ios_base::openmode mode = ios_base::in | ios_base::out) {
file.open(fn, mode);
// Check to make sure file is open
}
FileHandle(const string &fn, ios_base::openmode mode = ios_base::in | ios_base::out) {
file.open(fn, mode);
// Check to make sure file is open
}
~FileHandle() {
file.close();
}
private:
fstream file;
};
I would like to know if this is a viable way of making a file handle, that is, whether my inheritance idea is good. I also want to know the best way to deal with the ios_base::openmode parameter because the C++ reference page for std::ifstream says this:
Note that even though ifstream is an input stream, its internal filebuf object may be set to also support output operations.
In what cases would an ifstream be used for output operations, and, similarly, when would an of stream be used for input operations; and should I restrict the options for the ios_base::openmode parameter for my file handle class(es)? That way my input file handle would only handle input operations, and the output version would only handle output operations.
In what cases would an ifstream be used for output operations, and, similarly, when would an ofstream be used for input operations
You would open an output file stream with an std::ios_base::in openmode and vice-versa for an input file stream if you would still like to perform those associated operations using the internal std::filebuf object, which is accessible by stream->rdbuf(). Note that the streams std::ofstream and std::ifstream will still be able to perform output and input respectively even if they are opened with opposite openmodes.
int main() {
std::ofstream stream("test.txt");
stream << "Hello" << std::flush;
stream.close();
stream.open("test.txt", std::ios_base::in);
char buffer[SIZE] = {};
stream.rdbuf()->sgetn(buffer, SIZE);
std::cout << buffer << std::endl;
}

How to handle file I/O outside of main when redirecting input and output?

A restriction of the program I am working on is that it should be invoked as: ./a.out < input.txt > output.txt. The input of this program should be read from the first file, and the output should be written to the second.
So, this redirects standard input and output from and to these two files. I could simply, from main() for example, call std::cin and std::cout. However, I have a dedicated component which adapts my input from a file to an intermediate structure that I use elsewhere in my program.
In order to build this struct I could #include <iostream> in this component and read with std::cin from input.txt. However, I don't like the idea of including iostream here, and I am not sure how I would test this.
My issue comes from the I/O redirect, if the executable were invoked with filenames as strings, I would do something along the lines of
InputAdapter inputAdapter;
ifstream infile;
infile.open(filename ,std::ios_base::in);
auto structHoldingParsedInput = inputAdapter.adapt(infile);
How can I achieve something similar here?
I would suggest you make your adapter parameters std::istream& and std::ostream& so you can pass in either the standard std::cin/std::cout or files you open yourself like std::ifstream.
A bit like this:
class InputAdapter
{
public:
void adapt(std::istream& in)
{
// code to convert input to output here
return created_object;
}
};
// ...
InputAdapter inputAdapter;
std::ifstream in("input_file");
auto structHoldingParsedInput = inputAdapter.adapt(in);
Now you are coding to streams rather than files you can use any stream, for example the standard input stream:
auto structHoldingParsedInput = inputAdapter.adapt(std::cin);
And, for testing you could use std::istringstream:
std::istringstream test_stream(R"(
put your test data in here
)");
auto structHoldingParsedInput = inputAdapter.adapt(test_stream);

Param syntax for substituting boost filtering_stream for std::ofstream

Some basic questions about boost filtering_streams. I have dozens of functions that take a parameter of std::ofstream&
void foo(std::ofstream& outStream)
{
// lots of operations, like this:
outStream << "various bits of text";
}
void StreamSomeTextToFile(char* fileName)
{
ofstream myFileStream(fileName, ios::out | ios::app | ios::binary);
foo(myFileStream);
myFileStream.close();
}
Now I'd like to use the boost filtering_stream to output to a compressed ZIP file. The commonly cited boost filtering_streams test code for packing and unpacking compiled, linked, and worked perfectly for me. I'd like to substitute the filtering_stream:
void StreamSomeCompressedTextToFile(char* fileName)
{
ofstream myFileStream(destPath, std::ios_base::out | std::ios_base::app | std::ios_base::binary);
boost::iostreams::filtering_streambuf<boost::iostreams::output> myCompressedFileStream;
myCompressedFileStream.push(boost::iostreams::zlib_compressor());
myCompressedFileStream.push(myFileStream);
foo(myCompressedFileStream); // I can't just pass myCompressedFileStream to foo(std::ofstream&), right?
myFileStream.close();
}
THREE QUESTIONS:
1) Do all my functions that previously accepted std::ofstream& outStream need to now accept a parameter of type boost::iostreams::filtering_streambuf& ? Or is there a proper parameter type so those numerous ("foo") functions could work with EITHER type of stream type?
2) In my simple test cases, I was not able to use stream operator syntax with the filtering_streambuf:
myCompressedFileStream << "some text";
this generated the the error: no match for 'operator<<'. I similarly had compile errors with write():
error: 'class boost::iostreams::filtering_streambuf<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char>, boost::iostreams::public_>' has no member named 'write'
3) In the common test case example code (below), I was confused that I could not locate the file "hello.z" after it had been created. The unpack code (also below) clearly references it -- so where can it be found? NOTE: the location was finally discovered: it was in the /Library/Preferences/
void pack()
{
std::ofstream file("hello.z", std::ios_base::out | std::ios_base::binary);
boost::iostreams::filtering_streambuf<boost::iostreams::output> out;
out.push(boost::iostreams::zlib_compressor());
out.push(file);
char data[5] = {'a', 'b', 'c', 'd', 'e'};
boost::iostreams::copy(boost::iostreams::basic_array_source<char>(data, sizeof(data)), out);
file.close();
}
void unpack()
{
std::fstream file("hello.z", std::ios_base::in | std::ios_base::binary);
boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
in.push(boost::iostreams::zlib_decompressor());
in.push(file);
boost::iostreams::copy(in, std::cout);
}
BTW: XCode 3.2.6, GNU 4.0, OS X 10.6.8
Taking the questions in order:
1: Stream buffer objects (like boost::iostream::filtering_streambuf or std::streambuf) are not interchangeable with stream objects (such as std::ostream or boost's implementation). That being said, you can pass a streambuf object like "myCompressedFileStream" to a constructor of an ostream object (this boost iostream tutorial provides a decent explanation with examples). And because boost's streambufs are compatible with those in the standard library, you need not change any of the functions accepting std::ostream/ofstream references. You just can't pass streambufs as streams.
2: Same as above, the insertion operator is defined for streams, not streambufs.
3: Normally, files without a preceding directory name are created in the directory of the executable. That being said, I've found at times Finder has been somewhat slow reflect files updated/created by non-Finder processes. I didn't experience those problems in Terminal using ls. No idea if that's related to your problem, though.
SUCCESS!
A combination of hints from Paul Schellin (above) and several on Boost-users resulted in the answer:
1) Boost User Frédéric pointed out that "nothing happen[s] until output_file [filtering_ostream] is destroyed. So enclose in { }". This was the essential missing piece, because I was trying to do file.close() on my ofstream BEFORE my filtering_streambuf was destroyed. That explained why the file was empty!
Re-reading the documentation revealed:
"By default, if the Device at the end of the chain is popped
or if the filtering_stream is complete when it is destroyed,
all the filters and devices in the chain are closed using the
function close. This behavior can be modified using the member
function set_auto_close"
This states is there is no need to "pop" the compressor() or the ofstream (file) off the filtering_stream's stack, nor to call close(). Just destruct the filtering_stream object, and everything gets written out and cleaned up. An obscure detail, and one that goes counter to what one might expect.
3) Boost User Holger Gerth questioned why I was using filtering_streambuf when I could've been using filtering_stream. Truth is, I wasn't sure, however, in my experiments I could neither construct the ostream (which I required to pass to other functions) from the filtering_stream, nor could I pass the filtering_stream in place of the ostream I required.
Even after reading several articles on filtering_streambuf vs filtering_stream, I'm still mystified how and why (FOR MY PURPOSE) I would use the filtering_stream over constructing an ostream from a filtering_streambuf.
SO, TO RECAP:
1) Construct a separate ostream from the filtering_streambuf, and pass THAT to foo() or to the Stream Insertion operator (i.e. <<).
2) Don't call myFileStream.close();

fstream won't print to file

The following code will print something to a file
std::fstream fout ("D_addr.txt", std::fstream::app);
fout << pkt->Addr() << std::endl;
flush(fout);
fout.close();
While debugging, I watched pkt->Addr() and it has some values. The fout line is passed without problem. Also the file D_addr.txt is created. However after closing the file, the file size is zero! nothing has been written to it.
Where is the problem?
This is not your actual code I guess and if it is I would start with that Addr() function of yours.
Note that fstream::close "closes the file currently associated with the object, disassociating it from the stream. Any pending output sequence is written to the physical file." flush(fout); can be omitted.
You should also specify std::fstream::out flag. "If the function is called with any value in that parameter the default mode is overridden, not combined." So instead of std::fstream::app you should pass std::fstream::app | std::fstream::out.
I'm wondering if you're not using the wrong class. If you want to write to a file, use std::ofstream, and not std::fstream. In particular, the constructor of std::ofstream forces the ios_base::out bit when calling rdbuf()->open; the constructor of std::fstream doesn't (so you're opening the file with neither read nor write access).
And you probably want to check the error status: did the open succeed, and after the close (or the flush), did all of the writes succeed. The usual way of doing this is just:
if ( fout ) {
// All OK...
}
if ( !fout ) {
// Something went wrong.
}
After the open (the constructor), you can use fout.is_open(), which has the advantage of being a little bit more explicit with regards to what you are checking for.
First of all, flush() and fout.close() do not make any harm, but are not needed here, because when fout gets destroyed the file will be closed (and flushed) as part of fstream destructor.
Second, you should use an ofstream or alternatively add the flag std::ios::out to the openmode parameter.
Try something along the lines of:
{
uint64_t x = 42;
std::fstream of("test.txt", std::ios::app);
of << x << std::endl;
}