C++ Save a Struct String into A Text File - c++

In my program, I save high scores along with a time in minutes and seconds. In my code, I currently store this as two ints in a struct called highscore. However, this is a little tedious when it comes to formatting when I display the output. I want to display the times as 12:02 not 12:2. I have a variable already made called string clock throughout my game, it is already formatted with the colon, all I want to do is add that inside my text file.
How can I refactor my code to have a single variable for the timestamp, which will be correctly formatted? I want to be able to write my data into the file by directly calling the structure.
// Used for Highscores
struct highscore
{
char name[10];
int zombiesKilled;
// I would like these to be a single variable
int clockMin;
int clockSec;
char Date[10];
};
// I write the data like this:
highscore data;
// ...
data[playerScore].clockMin = clockData.minutes;
data[playerScore].clockSec = clockData.seconds;
streaming = fopen( "Highscores.dat", "wb" );
fwrite( data, sizeof(data), 1 , streaming);
// ...

It seems that you want to simply just write a C-string or std::string to a file using C's fwrite() function.
This should be quite easy, given that your C-string is in ASCII-conforming format (no Unicode funny business):
//It appears you want to use C-style file I/O
FILE* file = NULL;
fopen("Highscores.dat", "wb");
//std::string has an internal C-string that you can access
std::string str = "01:00";
fwrite(str.c_str(), sizeof(char), sizeof(str.c_str()), file);
//You can also do this with regular C strings if you know the size.
We can also choose to try and use C++-style file I/O for cleaner interfaces.
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
int main() {
std::string str = "00:11";
std::ofstream file("example.txt");
if (file.good()) {
file << str;
std::cout << "Wrote line to file example.txt.\n";
}
file.close();
//Let's check if we actually wrote the file.
std::ifstream read("example.txt");
std::string buffer;
if (read.good())
std::cout << "Opened example.txt.\n";
while(std::getline(read, buffer)) {
std::cout << buffer;
}
return 0;
}
Additionally, there are data types in <chrono> that can prove quite helpful for times like there.
If you want to be able to do this:
file << data_struct;
then it would make sense for you to create an operator overload for std::ostream.

You can experiment with time functions. And reading/writing structures.
The right way however is to use c++ basic file storage instead of dumping binar data.
struct highscore
{
char name[10];
int n;
std::time_t dateTime;
};
int main()
{
int total_seconds = 61;
char buf[50];
sprintf(buf, "minutes:seconds=> %02d:%02d", total_seconds / 60, total_seconds % 60);
cout << buf << endl;
std::time_t timeNow = std::time(NULL);
std::tm timeFormat = *std::localtime(&timeNow);
cout << "Current date/time " << std::put_time(&timeFormat, "%c %Z") << endl;
highscore data;
//write data:
{
FILE *streaming = fopen("Highscores.dat", "wb");
strcpy(data.name, "name1");
data.n = 1;
data.dateTime = std::time(NULL);
fwrite(&data, sizeof(data), 1, streaming);
strcpy(data.name, "name2");
data.n = 2;
data.dateTime = std::time(NULL);
fwrite(&data, sizeof(data), 1, streaming);
fclose(streaming);
}
//read data:
{
FILE *streaming = fopen("Highscores.dat", "rb");
fread(&data, sizeof(data), 1, streaming);
cout << "reading:\n";
cout << data.name << endl;
cout << data.n << endl;
timeFormat = *std::localtime(&data.dateTime);
cout << std::put_time(&timeFormat, "%c %Z") << endl;
cout << endl;
fread(&data, sizeof(data), 1, streaming);
cout << "reading:\n";
cout << data.name << endl;
cout << data.n << endl;
timeFormat = *std::localtime(&data.dateTime);
cout << std::put_time(&timeFormat, "%c %Z") << endl;
cout << endl;
fclose(streaming);
}
return 0;
}

Related

Why does fstream not working correctly when I'm trying to use read and write?

I'm trying to create a local file database using fstream and map.
I'm using class fstream to read and write.
But it is creating an empty file, I tried with operator >>, << and with function read(), write(). And it also not working.
Here is code:
#include <iostream>
#include <map>
#include <fstream>
#include <string>
using str = std::string;
class MapDB{
public:
MapDB(str path){
this->dbfile.open(path, std::fstream::in | std::fstream::out | std::fstream::trunc);
}
void PushValue(str key, str value){
this->Load();
this->db[key] = value;
this->Save();
}
str GetValue(str key){
this->Load();
return this->db[key];
}
void RemoveKey(str key){
this->db.erase(key);
this->Save();
}
~MapDB(){
this->dbfile.close();
}
private:
void Load(){
//this->dbfile.read((char*)&this->db, sizeof(MapDB));
this->dbfile >> (char*)&this->db;
}
void Save(){
this->dbfile.clear();
//this->dbfile.write((char*)&this->db, sizeof(MapDB));
this->dbfile << (char*)&this->db;
}
std::fstream dbfile;
std::map<str, str> db;
};
int main(int argc, char *argv[]){
std::map<str, str> mydb;
MapDB mydata("/path/to/file/data.data");
mydata.PushValue("key", "value");
std::cout << mydata.GetValue("key") << std::endl;
}
any ideas?
Multiple problems exist in your code:
std::map<> is not trivial and cannot be serialized the way you try
to do it. You have to serialize it yourself - item by item.
dbfile.clear(); only clears the error flags of the stream which is
probably not what you want to do.
Load() should position the read cursor, Save() should position the
write cursor.
Your constructor truncates the file. So there is no chance to read
something that has been written by another instance of MapDB. (Maybe this is indentionally)
I would not risk to say this list is nearly complete. Hopefully this example will give you a few hints:
class MyDB
{
public:
// constructor.
// creates or opens the file in binary mode (because we store binary data like the number of items and, the length of the strings).
// truncates the file on open if the flag 'truncateOnOpen' is set.
MyDB(const std::string& filename, bool truncateOnOpen)
: dbfile(filename, std::fstream::binary | std::fstream::in | std::fstream::out | (truncateOnOpen ? std::fstream::trunc : 0))
{}
void Load()
{
// drop old database content
db.clear();
// position read cursor to the beginning of the file
dbfile.seekg(0);
// read the number of entries
size_t entries = 0;
dbfile.read(reinterpret_cast<char*>(&entries), sizeof(entries));
// read key and value for each entry
std::string key, value;
for (size_t i = 0; i < entries; ++i)
{
readString(&key);
readString(&value);
db[key] = value;
}
}
void Save()
{
// position the write cursor to the beginning of the file
dbfile.seekp(0);
// write thenumber of entries
size_t entries = db.size();
dbfile.write(reinterpret_cast<const char*>(&entries), sizeof(entries));
// write key and value for each entry
for (auto& it : db)
{
writeString(it.first);
writeString(it.second);
}
}
private:
// reads a single string from the file
bool readString(std::string* target)
{
// read the length of the string stored in the file
size_t len;
if (dbfile.read(reinterpret_cast<char*>(&len), sizeof(len)).fail())
return false;
// preallocate memory for the string
target->resize(len);
// read the string from the file
return dbfile.read(&target->front(), target->size()).good();
}
// writes a single string to the file
void writeString(const std::string& source)
{
// write the length of the string to the file
size_t len = source.size();
dbfile.write(reinterpret_cast<char*>(&len), sizeof(len));
// write the string itself to the file
dbfile.write(source.data(), source.size());
}
private:
std::fstream dbfile;
public:
std::map<std::string, std::string> db;
};
Ok, lets go through it step by step:
But it is creating an empty file
That is because you are emptying the file with
std::fstream::trunc - Delete everything in the file (truncate it)
Meaning the moment you open your data.data file you erase all data in it if any is already present.
There are two standard formats in 'std::fstream':
format is the std::ios::binary format, data.data is not readable with a text editor but it is compact and efficient. Y
format is storing the strings in printable characters.
in that case data.data is readable like a txt-file with a common file editor.
Since #Andreas H. provided a binary file format example and you didn't used the binary format, I provide a minimal executable example that stores your data with printable characters.
int main(int argc, char *argv[]) needs [ ]-brackets to work properly
Type casting in the old c-style (char*)&this->db; is working fine, Scott Meyers writes in "Effective C++" old c-style should be avoided because because old-c type casting is not type safe and "hides" in the code so it is not easy to find like static_cast<char*>(...)
Here you see the difference - both are doing the same thing:
int firstNumber = 1, secondNumber = 2;
double result1 = ((double)firstNumber) /secondNumber;
double result2 = static_cast<double>(firstNumber)/secondNumber;
std::cout << result1 << std::endl;
std::cout << result2 << std::endl;
For the sake of providing a minimal executable example and
a better understanding I skipped the class ;)
Should be easy enough for you to parse it in a nice interface.
#include <iostream>
#include <map>
#include <fstream>
#include <string>
int main(int argc, char *argv[])
{
std::map<std::string, std::string> db{{"Key1","value"},{"Key2","value"}};
std::fstream mydata;
//PRINT MAP
for(const auto &[k,v] : db)
std::cout << k << " " << v << std::endl;
//WRITE MAP TO FILE
//Open File in write mode
mydata.open("data.data", std::ios::out);
if(!mydata.is_open())
std::cout << "Could not open file!" << std::endl;
//Write data to file
for(const auto &[k,v] : db)
mydata << k <<" " << v << std::endl;
//Close file
mydata.close();
//proof of concept, DESTROY MAP VALUES
db.clear();
//READ MAP BACK IN FROM FILE
std::string key , value;
//Open Data in read mode
mydata.open("data.data", std::ios::in);
if(!mydata.is_open())
std::cout << "Could not open file!" << std::endl;
//Read data back to map
while(mydata >> key >> value)
db[key] = value;
//Close File again
mydata.close();
//PRINT MAP
for(const auto &[k,v] : db){
std::cout << k << " " << v << std::endl;
}
return 0;
}
I hope this will help you finish your project :)
Btw. if you have more than one word as key or value, you can use getline with a delimiter, and store your data file in a csv-format (coma separated values file) for easy import of your data f.e. in email software if you store contact data in your database.
Just as an exercise for me I wrote a minimal executable example to write a map of strings in a binary format to a file:
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#define FILENAME "BinaryMap.bin"
int main()
{
std::fstream file;
std::string key{"Key One"}, value{"Value One"};
std::map<std::string, std::string> map{{key,value},{"Key Two","Value Two"}};
//Print Map
for(const auto &[key,value] : map){
std::cout << key << " " << value << '\n';
}
//Open file and check for errors
file.open(FILENAME, std::ios::binary | std::ios::out);
if(!file.is_open())
std::cout << "Could not open file!" << '\n';
//Position write cursor to the beginning of the file
file.seekp(0);
//Write the number of entries
size_t entries = map.size();
file.write(reinterpret_cast<const char*>(&entries), sizeof(entries));
//Write the number of entries
for(auto& it : map){
//Write the lenth of the key string to the file
size_t len = it.first.size();
file.write(reinterpret_cast<char*>(&len), sizeof(len));
//Write the string itself to the file
file.write(it.first.data(), it.first.size());
//Write the length of the value string to the file
len = it.second.size();
file.write(reinterpret_cast<char*>(&len), sizeof(len));
//Write the value string itself to the file
file.write(it.second.data(), it.second.size());
}
//Close the file
file.close();
map.clear();
std::cout << "--------clear---------" << '\n';
//READ STUFF
file.open(FILENAME, std::ios::binary | std::ios::in);
if(!file.is_open())
std::cout << "Could not open file!" << '\n';
// Position read cursor to the beginning
file.seekg(0);
// read the number of entries
entries = 0;
file.read(reinterpret_cast<char*>(&entries), sizeof(entries));
//Read the length of the string stored in the file
size_t length {};
for(size_t i = 0; i < entries; ++i){
//Read the length of the string in the file
if(file.read(reinterpret_cast<char*>(&length), sizeof(length)).fail())
std::cout << "Failed to read bin" << '\n';
//Pointer to variable address
std::string* p_target = &key;
//Preallocate memory for the string
p_target->resize(length);
//Read string from file
file.read(&p_target->front(), p_target->size()).good();
//Read the length of the string in the file
if(file.read(reinterpret_cast<char*>(&length), sizeof(length)).fail())
std::cout << "Failed to read bin" << '\n';
//Dereference value
key = *p_target;
//Assign variable address to pointer
p_target = &value;
//Preallocate memory for the string
p_target->resize(length);
//Read string from file
file.read(&p_target->front(), p_target->size()).good();
//Dereference value
value = *p_target;
//Write key and value to map
map[key] = value;
}
//Close the file
file.close();
for(const auto &[key,value] : map){
std::cout << key << " " << value << '\n';
}
std::cout << "Hit 'return' to continue";
std::cin.get();
return 0;
}
It's not fstream that isn't working correctly. fstream works fine.
For this to work:
this->dbfile >> (char*)&this->db;
and this:
this->dbfile << (char*)&this->db;
... I'm not even sure what it would take. Imagine a possible implementation of:
std::map<str, str> db;
It's not going to just be a raw stream of data with a null byte on the end. It's going to be quite complicated, and it's going to have pointers. Even if you could somehow tell the << to write the number of characters you want, you'd be writing out pointers that point somewhere totally else, so reading them in later won't do you one bit of good.
Instead, you need to somehow to do it by hand, probably by iterating over the contents of the map and printing them out, maybe like this:
dbFile << dbElement.first << " == " << dbElement.second << endl;
Of course, that's not going to be safe if the data contains newlines. But at least you'd get closer. Then you could read lines in with getline and parse the line, splitting it into two pieces based on " == " as a divider.
It's probably 20 or 30 lines of code in all.

Reading or writing binary file incorrectly

The output of the code show gibberish values for all the variables of the Student struct. When the display function is ran.
I've include the relevant code in each of the add and display function for the binary file.
For the second function, does the seekg pointer automatically move to read the the next record each time the for loop runs?
//Student struct
struct Student
{
char name [30];
float labTest;
float assignments;
float exam;
};
//Writing function
afile.open(fileName,ios::out|ios::binary);
Student S;
strcpy(S.name,"test");
S.labTest = rand()%100+1;
S.assignments = rand()%100+1;
S.exam = rand()%100+1;
afile.write(reinterpret_cast<char*>(&S),sizeof(S));
afile.close();
//Reading function
afile.open(fileName,ios::in|ios::binary);
afile.seekg(0,ios::end);
int nobyte = afile.tellg();
int recno = nobyte / sizeof(Student);
Student S;
//Loop and read every record
for(int i = 0;i<recno;i++)
{
afile.read(reinterpret_cast<char*>(&S),sizeof(S));
cout << "Name of Student: " << S.name << endl
<< "Lab mark: " << S.labTest << endl
<< "Assignment mark: " << S.assignments << endl
<< "Exam mark: " << S.exam << endl << endl;
}
afile.close();
There are a lot of problems with your code:
Calling your write function will permanently overwrite the last written data set. You have to add: ios::append, so that new data will be written behind the last data you wrote before.
After you move with afile.seekg(0,ios::end); to get with tellg the file size, you have to go back to the start of the file before reading with afile.seekg(0,ios::beg)
It looks that you use a char array to store a string. This is not c++ style! And it is dangerous how you use it. If you use strcpy, you can copy a string which is longer than the space you reserved for it. So you should prefer std::string for that. But you can't simply write a struct which constains std::string as binary! To get checked copy you can use strncpy, but that is still not c++ ;)
For the second function, does the seekg pointer automatically move to read the the next record each time the for loop runs?
Yes, the file position moves which each successful read and write.
A general remark writing binary data by simply dumping memory content:
That is not a good idea, because you can only read that data back, if you use the same machine type and the same compiler options. That means: A machine with different endianness will read data totally corrupted. Also a different integer type ( 32 bit vs 64 bit ) will break that code!
So you should invest some time how to serialize data in a portable way. There are a lot of libraries around which can be used to read/write also complex data types like std::string or container types.
A hint using SO:
Please provide code which everybody can simply cut and paste and compiled. I did not know what your Student struct is. So I take a lot of assumptions! Is your struct really using char[]? We don't know!
#include <iostream>
#include <fstream>
#include <cstring>
const char* fileName="x.bin";
struct Student
{
char name[100]; // not c++ style!
int labTest;
int assignments;
int exam;
};
// Writing function
void Write()
{
std::ofstream afile;
afile.open(fileName,std::ios::out|std::ios::binary|std::ios::app);
Student S;
strcpy(S.name,"test"); // should not be done this way!
S.labTest = rand()%100+1;
S.assignments = rand()%100+1;
S.exam = rand()%100+1;
afile.write(reinterpret_cast<char*>(&S),sizeof(S));
afile.close();
}
void Read()
{
//Reading function
std::ifstream afile;
afile.open(fileName,std::ios::in|std::ios::binary);
afile.seekg(0,std::ios::end);
int nobyte = afile.tellg();
int recno = nobyte / sizeof(Student);
afile.seekg(0, std::ios::beg);
Student S;
//Loop and read every record
for(int i = 0;i<recno;i++)
{
afile.read(reinterpret_cast<char*>(&S),sizeof(S));
std::cout << "Name of Student: " << S.name << std::endl
<< "Lab mark: " << S.labTest << std::endl
<< "Assignment mark: " << S.assignments << std::endl
<< "Exam mark: " << S.exam << std::endl << std::endl;
}
afile.close();
}
int main()
{
for ( int ii= 0; ii<10; ii++) Write();
Read();
}
EDIT. Apparently, I was a bit too late in responding. Klaus has compiled a better, more comprehensive response dwelling into other problems regarding C-style char [], std::string and the endianness of the platform.
You should append to the file opened for every record. In your code you don't have this, at all. Please write the code in a way we can copy and paste, and test. As a working example, you should write some code that can be compiled and run as below:
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
// Student struct
struct Student {
char name[30];
float labTest;
float assignments;
float exam;
};
// Serializer
void serialize_student(const Student &s, const std::string &filename) {
// Append to the file, do not overwrite it
std::ofstream outfile(filename, std::ios::binary | std::ios::app);
if (outfile)
outfile.write(reinterpret_cast<const char *>(&s), sizeof(Student));
}
// Deserializer
std::vector<Student> deserialize_students(const std::string &filename) {
std::ifstream infile(filename, std::ios::binary);
std::vector<Student> students;
Student s;
while (infile.read(reinterpret_cast<char *>(&s), sizeof(Student)))
students.push_back(std::move(s));
return std::move(students);
}
int main(int argc, char *argv[]) {
// Generate records
std::vector<Student> mystudents;
std::generate_n(std::back_inserter(mystudents), 10, []() {
Student s;
std::strcpy(s.name, "test");
s.labTest = rand() % 100 + 1;
s.assignments = rand() % 100 + 1;
s.exam = rand() % 100 + 1;
return s;
});
// Print and write the records
for (const auto &student : mystudents) {
std::cout << student.name << ": [" << student.labTest << ','
<< student.assignments << ',' << student.exam << "].\n";
serialize_student(student, "students.bin");
}
// Read and print the records
auto records = deserialize_students("students.bin");
std::cout << "===\n";
for (const auto &student : records)
std::cout << student.name << ": [" << student.labTest << ','
<< student.assignments << ',' << student.exam << "].\n";
return 0;
}

Naming a log file using date and time in C++

So, I want to create a log file for an app I am trying to create and I don't know how to name the log to something like "log/date&time"
Anyway, here is my code:
#include <iostream>
#include <fstream>
#include <time.h>
#include <stdio.h>
#include <sstream>
using namespace std;
int main (int argc, char *argv[])
{
time_t t = time(0);
struct tm * now = localtime( & t );
char buffer [80];
strftime (buffer,80,"%Y-%m-%d.",now); //i think i can't just put "log/%Y-%m-%d." there.
ofstream myfile;
myfile.open ("log/" + buffer); // this is my problem, i can't put the ' "log/" + ' part there
if(myfile.is_open())
{
cout<<"Success"<<std::endl;
}
return 0;
}
You should use std::string which supports concatenation via the overloaded operator+.
std::string buffer(80, '\0');
strftime( &buffer[0], buffer.size(), "some format string", now);
/* ... */
std::ofstream myfile( ("log/" + buffer).c_str() );
// Remove the (..).c_str() part when working with a C++11 conforming
// standard library implementation
you actual question is "why doesnt this work"
myfile.open ("log/" + buffer);
answer - because c++ doesnt support what you want - concatenate a string literal with a char * and return another char *.
do
std::string filetime(buffer);
std::string filename = "log/" + filetime;
open(filename.c_str());
Consider using std:: facilities instead (std::string and std::ostringstream come to mind):
std::ostream& time_digits(std::ostream& out, unsigned int digits)
{ // convenience function: apply width and fill for the next input
return out << std::setw(digits) << std::setfill('0');
}
std::string unique_log_name()
{ // generate unique log name, depending on local time
// example output: "log/2014-04-19.log"
auto now = time(0);
tm *ltm = localtime(&now);
std::ostringstream buffer;
buffer
<< "log/" << time_digits(4) << ltm.tm_year
<< "-" << time_digits(2) << ltm.tm_mon
<< "-" << time_digits(2) << ltm.tm_day;
// could also add these to the name format:
// buffer
// << "-" << time_digits(2) << ltm.dm_hour
// << "-" << time_digits(2) << ltm.tm_min
// << "-" << time_digits(2) << ltm.tm_sec;
buffer << ".log"; // add extension
return buffer.str();
}
void client_code()
{ // construct log stream on unique file name
ofstream myfile{ unique_log_name() };
if(myfile)
{
cout << "Success" << std::endl;
}
}

Reading a char* from a binary file

I have to store the name of a file into a binary file that I am writing, I currently have written it like this:
void write(map<char, bits> &bitstring,map<char,int> &ccount, string header,string fname,ofstream &outf)
{
ifstream inf(header+fname);
cout << "FName: " << fname << endl;
const char * pName = fname.c_str();
fname = header+ fname + ".mcp";
const char * c = fname.c_str();
FILE* pFile;
pFile = fopen(c, "w+b");
inf.seekg(ios::beg, ios::end);
int size = inf.tellg();
int length = 0;
string data = "";
int magicNum = 2262;
int fileNameSize = strlen(pName);
fwrite(&fileNameSize, sizeof(int), 1, pFile);
cout <<"FIle Name Size: "<< fileNameSize << endl;
fwrite(pName, fileNameSize, 1, pFile);
fclose(pFile);
}
And I also send the size of the file name, so that I know how much data I need to read to get the whole file name.
void read2(string fname, map<char, int> &charCounts, std::vector<bool> &bits,ofstream &outf)
{
string fname1 = fname + ".mcp", outfile = "binarycheck";
bool testDone = false, counts = false;
std::ifstream inf(fname1, std::ios::binary);
std::ofstream ouf("binarycheck.txt", std::ios::binary);
char character;
int count[1] = { 0 };
int checkcount = 0;
int mNum[1] = { 0 }, size[1] = { 0 };
int FNamesize = 0;
inf.read((char*)&FNamesize, sizeof(int));
char *name=new char[FNamesize+1];
inf.read(name, FNamesize);
name[FNamesize] = '\0';
string str(name);
cout << "File Name: ";
cout << std::string(name) << endl;
cout << "Magic Num: " << mNum[0] << endl;
cout << "File Name Size: " << FNamesize<< endl;
inf.close();
}
I get the Size correctly, but I have no idea how to iterate through name in order to save it back as a string. I tried using a vector but it didn't really help since inf.read uses a char* as its first parameter.
Any help would be great.
Well, in a fluke accident I ended up solving my own issue. For some reason when I declared
FILE* pFile;
pFile = fopen(c, "w+b");
Before the declaration of
const char * pName = fname.c_str();
The call corrupted the value of pName before it was written to the file, which is what caused the errors. Problem solved!
Seeing as you're using ifstream, why not also use ofstream? Then it would just be ofs << filename to store and ifs >> filename to read where filename is a string. No need to faff around with the length yourself.

lz4 compression c++ example [duplicate]

This question already has answers here:
Question about seekg() function of ifstream in C++?
(3 answers)
Closed 8 years ago.
In the process of writing a lz4 csv to compressed binary file converter (high volume forex tick data csv) in the hope of reducing the storage/disk bandwidth requirements on my tiny vps.
self contained code to illustrate
#include <string>
#include <fstream>
#include <iostream>
#include "lz4.h"
using namespace std;
int main()
{
char szString[] = "2013-01-07 00:00:04,0.98644,0.98676 2013-01-07 00:01:19,0.98654,0.98676 2013-01-07 00:01:38,0.98644,0.98696";
const char* pchSource = szString;
int nInputSize = sizeof(szString);
cout <<"- pchSource -" << endl << pchSource << endl;
cout <<"nbytes = "<< nInputSize << endl << endl;
ofstream source("pchSource.txt");
source << pchSource;
int nbytesPassed = 0;
int nMaxCompressedSize = LZ4_compressBound(nInputSize);
char *pszDest = new char[nMaxCompressedSize];
nbytesPassed = LZ4_compress(pchSource, pszDest, nInputSize);
cout <<"- pszDest Compressed-" << endl;
cout <<"nbytesPassed = "<< nbytesPassed << endl;
cout << pszDest << endl << endl;
// pszDest garbage ?
char *pszDestUnCompressed = new char[nInputSize];
LZ4_uncompress(pszDest, pszDestUnCompressed, nInputSize);
cout <<"- pszDestUnCompressed -" << endl;
cout <<"nbytesPassed = "<< nbytesPassed << endl;
cout << pszDestUnCompressed << endl << endl;
//pszDestUnCompressed is correct ?
delete[] pszDestUnCompressed;
pszDestUnCompressed = 0;
// ok lets write compressed pszDest to pszDest.dat
ofstream outCompressedFile("pszDest.dat",std::ofstream::binary);
outCompressedFile.write (pszDest,nMaxCompressedSize);
delete[] pszDest;
pszDest = 0;
//read it back in and try to uncompress it
ifstream infile("pszDest.dat",std::ifstream::binary);
infile.seekg (0,infile.end);
int nCompressedInputSize = infile.tellg();
infile.seekg (0);
char* buffer = new char[nCompressedInputSize];
infile.read (buffer,nCompressedInputSize);
const char* pchbuffer = buffer;
char* pszUnCompressedFile = new char[nInputSize];
nbytesPassed = LZ4_uncompress(pchbuffer, pszUnCompressedFile, nInputSize);
cout <<"- pszUnCompressedFile -" << endl;
cout <<"nbytesPassed = "<< nbytesPassed << endl;
cout << pszUnCompressedFile << endl;
//write uncompressed pszDest.dat to pszUnCompressedFile.txt
ofstream outUncompressedSource("pszUnCompressedFile.txt");
outUncompressedSource << pszUnCompressedFile;
// On my system 32bit ArchLinux 3.7.10-1 - gcc 4.7.2-4
// file contains random Garbage
delete[] buffer;
buffer = 0;
delete[] pszUnCompressedFile;
pszUnCompressedFile = 0;
return 0;
}
CONSOLE OUTPUT :
- pchSource -
2013-01-07 00:00:04,0.98644 .....
nbytes = 108
- pszDest Compressed-
nbytesPassed = 63
�2013-01-07 00:
- pszDestUnCompressed -
nbytesPassed = 63
2013-01-07 00:00:04,0.98644 .....
- pszUnCompressedFile -
nbytesPassed = -17
�W��W�-07 q
Process returned 0 (0x0) execution time : 0.010 s
Press ENTER to continue.
I'm obviously missing something, apart form the samples included in the source are there any-other usage examples ?
All working now thanks, here is the code for anyone that is interested
#include <fstream>
#include <iostream>
#include "lz4.h"
using namespace std;
int main()
{
char szSource[] = "2013-01-07 00:00:04,0.98644,0.98676 2013-01-07 00:01:19,0.98654,0.98676 2013-01-07 00:01:38,0.98644,0.98696";
int nInputSize = sizeof(szSource);
// compress szSource into pchCompressed
char* pchCompressed = new char[nInputSize];
int nCompressedSize = LZ4_compress((const char *)(&szSource), pchCompressed, nInputSize);
// write pachCompressed to binary lz4.dat
ofstream outBinaryFile("lz4.dat",ofstream::binary);
outBinaryFile.write(pchCompressed, nCompressedSize);
outBinaryFile.close();
delete[] pchCompressed;
pchCompressed = 0;
//read compressed binary file (assume we pass/encode nInputSize but don't know nCompressedSize)
ifstream infCompressedBinaryFile( "lz4.dat", ifstream::binary );
//Get compressed file size for buffer
infCompressedBinaryFile.seekg (0,infCompressedBinaryFile.end);
int nCompressedInputSize = infCompressedBinaryFile.tellg();
infCompressedBinaryFile.clear();
infCompressedBinaryFile.seekg(0,ios::beg);
//Read file into buffer
char* pchCompressedInput = new char[nCompressedInputSize];
infCompressedBinaryFile.read(pchCompressedInput,nCompressedSize);
infCompressedBinaryFile.close();
// Decompress buffer
char* pchDeCompressed = new char[nInputSize]; //(nCompressedInputSize *2) +8
LZ4_uncompress(pchCompressedInput, pchDeCompressed, nInputSize);
delete[] pchCompressedInput;
pchCompressedInput = 0;
// write decompressed pachUnCompressed to
ofstream outFile("lz4.txt");
outFile.write(pchDeCompressed, nInputSize);
outFile.close();
delete[] pchDeCompressed;
pchDeCompressed = 0;
return 0;
}
I am also working on a a simple CLI csv to binary I/O example here