I would like to use gzip from C++ (or C) to gzip a string. If possible, I would like to use zlib.
When I learned that I would have to use zlib to compress and uncompress, I Googled it for a few minutes and then quickly wrote a program to gzip a file and then ungzip it. However, I don't actually have any need to do that. I need to use gzip to compress and uncompress a string, not a file. I couldn't find much good documentation for using gzip on strings. Every example I find works with files.
Could someone show me a simple example?
Thanks in advance.
It's built into Poco (C++ library/framework, lots of utilities, networking, what you have). Here's a sample program:
#include <iostream>
#include <sstream>
#include <Poco/InflatingStream.h>
#include <Poco/DeflatingStream.h>
#include <Poco/StreamCopier.h>
int main() {
std::ostringstream stream1;
Poco::DeflatingOutputStream
gzipper(stream1, Poco::DeflatingStreamBuf::STREAM_GZIP);
gzipper << "Hello World!";
gzipper.close();
std::string zipped_string = stream1.str();
std::cout << "zipped_string: [" << zipped_string << "]\n";
std::ostringstream stream2;
Poco::InflatingOutputStream
gunzipper(stream2, Poco::InflatingStreamBuf::STREAM_GZIP);
gunzipper << zipped_string;
gunzipper.close();
std::string unzipped_string = stream2.str();
std::cout << "unzipped_string back: [" << unzipped_string << "]\n";
return 0;
}
The nice thing is that instead of the ostringstreams above, you could hook up the Poco gzipping streams to files etc..
Related
I want to read a binary file in 16 bit words. Right now, I'm using an std::ifstream to read into a 2 character array c.
#include <iostream>
#include <fstream>
#include <stdint.h>
int main() {
std::ifstream file("./tetris.rom", std::ios::in | std::ios::binary);
char c[2];
while (file.read(c, 2)) {
uint16_t word = (static_cast<uint8_t>(c[0]) << 8) | static_cast<uint8_t>(c[1]);
std::cout << "word\t" << std::hex << word << std::endl;
}
}
This works for me, but is there a better (either safer or faster) way of doing this in C++11?
There are no new APIs of reading files in C++11.
If the file fits into your RAM, the most optimal way is to map it into memory and access it as a byte array. However, the C++ standard library does not provide an API for that. You can do that with Boost though, see Boost.Interprocess Memory Mapped Files.
The usual advice stands though: start with your simple and correctly working code, benchmark and see if file reading is the bottleneck.
"Handling map of files in c++" says no, one shall use std::map<std::string, std::ofstream*>, but this leads to the new and delete actions, which is not so neat.
Since "Is std::ofstream movable? Yes!" and it's possible to "std::map<>::insert using non-copyable objects and uniform initialization", is it possible to handle a collection of ofstream using std::map? so that one won't worry about closing filestreams and delete to release memory.
I can compromise that during using std::map<std::string, std::ofstream>, only create, use (it to write) and close, not to copy it.
Yes it is possible. See sample code below.
I can compromise that during using std::map<std::string, std::ofstream>, only create, use (it to write) and close, not to copy it.
They are not copyable, so in your final comment, you are correct, you will be unable to copy it. You can move assign though, if that's what you want to do.
#include <iostream>
#include <fstream>
#include <map>
int main()
{
std::map<std::string, std::ofstream> map;
map.emplace("foo", std::ofstream("/tmp/foo"));
map.emplace("bar", std::ofstream("/tmp/bar"));
map["foo"] << "test";
map["foo"].flush();
std::ifstream ifs("/tmp/foo");
std::string data;
ifs >> data;
std::cout << data << '\n';
return 0;
}
Output:
test
To learn/understand the various concepts of modern C++, I tried to write similar program like "ls -R /" which would recursively lists sub directories. To achieve this I am using the future C++ TS filesystem library so that program could be portable. So far I am able to write the below program to achieve this.
#include<filesystem>
//Other herader files
// Below typedef is for VS2013
using fspath = std::tr2::sys::path;
using dir_iterator = std::tr2::sys::directory_iterator;
using namespace std::tr2::sys;
struct directory {
std::vector<fspath> files;
std::vector<fspath> operator()(const fspath& input) {
std::cout << "Input Directory Name: " << input.string() << std::endl;
dir_iterator bgnitr(input);
dir_iterator enditr;
for (dir_iterator itr = bgnitr; itr != enditr; ++itr) {
// Only store the directory from input directory,
// otherwise display the name
fspath tmp = *itr;
if (is_directory(tmp)) {
files.push_back(tmp);
}
else {
tmp = tmp.filename();
std::cout << tmp.string() << std::endl;
}
}
return files;
}
};
int main(int argc, const char** argv) {
fspath input{argv[1]};
directory dir;
auto files = dir(input);
std::sort(std::begin(files), std::end(files));
std::for_each(std::begin(files), std::end(files), directory());
return 0;
}
The above program works fine and produce the expected result if my input directory has one level of sub-directory. I could have used the "recursive_directory_iterator", but it gives the list of all files within all directory inside the input directory.
It does not handle the scenario where actual input directory contains the sub-directory which itself contains sub-directory and files. Basically these level can be upto any level which gets handled by UNIX "ls -R " utility.
Question
I would like to know that whats could be next approach to handle the n level of hierarchy in the directory?
In general whats sort of approaches we should follow when we need to model/design similar things where "part-whole hierarchies(recursive)" needs to model. I am little bit aware about the "composite design pattern" which can be used to model such stuff. Could this pattern be applied in this particular problem?. If yes, could someone provide explanation/comment?
My main intention over here is to understand general guideline to handle such problem using modern C++ concepts/library/design concepts.Kindly let me know in case someone require any information on this.
I would rename your directory class, it doesn't model a directory, it is a function that prints the contents of a directory.
You can use a range-based for loop with a directory_iterator to make the syntax simpler:
for (auto f : fs::directory_iterator{dir})
Your program assumes it will only be called with a single argument that refers to a directory, whereas ls -R can be called with zero or more arguments that are files or directories.
I would do it like this, although this could probably be improved to simplify the logic in main and incorporate it into the ls function:
#include <utility>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
void ls(std::ostream& out, const fs::path& dir)
{
std::vector<std::pair<std::string, bool>> files;
for (auto f : fs::directory_iterator{dir})
files.emplace_back(f.path().filename(), is_directory(f));
std::sort(files.begin(), files.end());
// print directory contents
out << dir.string() << ":\n";
for (auto& f : files)
out << f.first << '\n';
out << std::endl;
// recurse into directories
for (auto& f : files)
if (f.second)
ls(out, dir / f.first);
}
int main(int argc, char** argv)
{
if (argc < 2)
ls(std::cout, ".");
else
{
std::vector<std::string> files;
std::vector<std::string> dirs;
for (int i = 1; i < argc; ++i)
if (fs::is_directory(argv[i]))
dirs.push_back(argv[i]);
else
files.push_back(argv[i]);
std::sort(files.begin(), files.end());
for (auto& f : files)
std::cout << f << '\n';
std::cout << '\n';
std::sort(dirs.begin(), dirs.end());
for (auto& d : dirs)
ls(std::cout, d);
}
}
I'm going for absolute minimalism here. (It's been a while since I've worked with the Lua C API.)
#include <lua.hpp>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char** argv)
{
lua_State* state = luaL_newstate();
luaL_openlibs(state);
string input;
while (getline(cin, input))
{
auto error = luaL_dostring(state, input.c_str());
if (error)
{
cerr << "Lua Error: " << lua_tostring(state, -1) << '\n';
lua_pop(state, 1);
}
}
lua_close(state);
return 0;
}
This program works fine as long as I feed it perfect Lua. However, if I enter something bad (such as asdf()), the program crashes! Why is it not handling my error gracefully?
I've tried breaking out the calls before. It crashes on the call to lua_pcall itself. I never make it past that line.
The binary download (5.2.1 I believe) has a bug that was corrected in 5.2.3. I rebuilt the library from source, and now my program works fine.
I'm having some issue serializing a std::string with boost::serialization on a text_oarchive. AFAICT, I have two identical pieces of code that behaves differently in two different programs.
This is the program that I believe is behaving correctly:
#include <iostream>
#include <string>
#include <sstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
template <typename T>
void serialize_deserialize(const T & src, T & dst)
{
std::string serialized_data_str;
std::cout << "original data: " << src << std::endl;
std::ostringstream archive_ostream;
boost::archive::text_oarchive oarchive(archive_ostream);
oarchive << src;
serialized_data_str = archive_ostream.str();
std::cout << "serialized data: " << serialized_data_str << std::endl;
std::istringstream archive_istream(serialized_data_str);
boost::archive::text_iarchive iarchive(archive_istream);
iarchive >> dst;
}
int main()
{
std::string archived_data_str = "abcd";
std::string restored_data_str;
serialize_deserialize<std::string>(archived_data_str, restored_data_str);
std::cout << "restored data: " << restored_data_str << std::endl;
return 0;
}
And this is its output:
original data: abcd
serialized data: 22 serialization::archive 10 4 abcd
restored data: abcd
(You can compile it with: g++ boost-serialization-string.cpp -o boost-serialization-string -lboost_serialization)
This one, on the other hand, is an excerpt of the program I'm writing (derived from boost_asio/example/serialization/connection.hpp) that serializes std::string data converting each character in its hex representation:
/// Asynchronously write a data structure to the socket.
template <typename T, typename Handler>
void async_write(const T& t, Handler handler)
{
// Serialize the data first so we know how large it is.
std::cout << "original data: " << t << std::endl;
std::ostringstream archive_stream;
boost::archive::text_oarchive archive(archive_stream);
archive << t;
outbound_data_ = archive_stream.str();
std::cout << "serialized data: " << outbound_data_ << std::endl;
[...]
And this is an excerpt of its output:
original data: abcd
serialized data: 22 serialization::archive 10 5 97 98 99 100 0
The version (10) is the same, right? So that should be the proof that I'm using the same serialization library in both programs.
However, I really can't figure out what's going on here. I've been trying to solve this puzzle for almost an entire work day now, and I'm out of ideas.
For anyone that may want to reproduce this result, it should be sufficient to download the Boost serialization example, add the following line
connection_.async_write("abcd", boost::bind(&client::handle_write, this, boost::asio::placeholders::error));
at line 50 of client.cpp, add the following member function in client.cpp
/// Handle completion of a write operation.
void handle_write(const boost::system::error_code& e)
{
// Nothing to do. The socket will be closed automatically when the last
// reference to the connection object goes away.
}
add this cout:
std::cout << "serialized data: " << outbound_data_ << std::endl;
at connection.hpp:59
and compile with:
g++ -O0 -g3 client.cpp -o client -lboost_serialization -lboost_system
g++ -O0 -g3 server.cpp -o server -lboost_serialization -lboost_system
I'm using g++ 4.8.1 under Ubuntu 13.04 64bit with Boost 1.53
Any help would be greatly appreciated.
P.s. I'm posting this because the deserialization of the std::strings isn't working at all! :)
I see two causes of such behavior.
The compiler does not explicitly converts "abcd" from const char * to std::string and the serialization handles it as a vector of "bytes" and not as an ASCII string. Changing the code to the connection_.async_write(std::string("abcd"), boost::bind(&client::handle_write, this, boost::asio::placeholders::error)); should fix the problem.
Probably, the string type passed as the t argument of the async_write template method is not std::string but std::wstring and it is serialized not as an ASCII string ("abcd") but as an unsigned short vector and 97 98 99 100 is a decimal representation of the ASCII characters a, b, c and d.