Hi,
I made a library which gets an std::ifstream and read a certain file
format. Now I would like to support also gzip compressed input files,
but it should also support not compressed files.
I used boost::iostreams to implement a new stream class which should
replace the std::ifstream in my library.
Following functions are called from std::ifstream:
- std::ifstream(const char*)
- read(...)
- seek(...)
- close(...)
My question is, is everything done correctly or is there a more elegant
way to implement this?
I'm not a stream expert, so I doubt if I do it in a good way :-).
Would be great if someone from the experts can have a look to it and
review it.
Thanks in advance,
Sascha
I derived my class from boost::iostreams::filtering_istream, here is my
implementation:
#ifndef PAT_INPUTSTREAM_H
#define PAT_INPUTSTREAM_H
#include
#include
#include
#include <string>
namespace my {
namespace io = boost::iostreams;
/*! Check if a given file is a (gzipped-)compressed format
It is using functions from zlib
*/
bool isCompressed(const char* p_name);
/*! \class ifstream
Special input stream to handle compressed files.
After opening an my::ifstream, it should be checked with is_open()
if it is openend correctly.
*/
class ifstream : public io::filtering_istream {
private:
std::string _name; // the filename is needed for re-opening in seek()
public:
ifstream(const char* p_name) : _name(p_name) {
if (isCompressed(p_name)) {
io::filtering_istream::push(io::gzip_decompressor());
io::filtering_istream::push(io::file_source(p_name,
std::ios::binary));
} else {
io::filtering_istream::push(io::file_source(p_name));
}
}
bool open(const char* p_name) {
if (!is_open()) {
_name = p_name;
if (isCompressed(p_name)) {
io::filtering_istream::push(io::gzip_decompressor());
io::filtering_istream::push(io::file_source(p_name,
std::ios::binary));
} else {
io::filtering_istream::push(io::file_source(p_name));
}
}
return is_open();
}
void close() {
if (is_open()) {
while (io::filtering_istream::size()) {
io::filtering_istream::pop();
}
}
}
bool is_open() {
if (io::filtering_istream::size()) {
// the last components is the file device
io::file_source* device =
io::filtering_istream::componentio::file_source(io::filtering_istream::size()-1);
if (device)
return device->is_open();
}
return false;
}
ifstream& seekg(std::streampos p_pos) {
// seek means close the stream
// and read until position is reached were we
// want to be
if (is_open()) {
close();
if (open(_name.c_str())) {
const std::streampos PAT_BLOCK_SIZE = 1024;
char* buf = new char[PAT_BLOCK_SIZE];
while (p_pos) {
if (p_pos / PAT_BLOCK_SIZE) {
read(buf, PAT_BLOCK_SIZE);
p_pos -= PAT_BLOCK_SIZE;
} else {
read(buf, p_pos % PAT_BLOCK_SIZE);
p_pos -= (p_pos % PAT_BLOCK_SIZE);
}
}
delete [] buf;
}
}
return *this;
}
};
} // end of namespace pat
#endif