This implementation of ofstream works :
bool LinuxSysCall::addNewUser(std::string const &login, std::string const &password) {
std::ofstream out;
out.open(DATABASEPATH, std::ios::app);
if (out.is_open())
{
std::string str = login + ":" + password + "\n";
std::cout << "writing " << str << std::endl;
out << str;
return true;
}
return false;
}
//The new line is written in the file
But when I put my std::ofstream out as an attribute of LinuxSysCall, it doesn't work anymore (without trowing any exceptions):
bool LinuxSysCall::addNewUser(std::string const &login, std::string const &password) {
this->out.open(DATABASEPATH, std::ios::app);
if (this->out.is_open())
{
std::string str = login + ":" + password + "\n";
std::cout << "writing " << str << std::endl;
this->out << str;
return true;
}
return false;
}
//The new line is not written in the file
Why ?
The destructor of std::ofstream calls close. This will flush the text to the file.
If you want to use a member variable (not "attribute") you would need:
bool LinuxSysCall::addNewUser(std::string const &login,
std::string const &password) {
this->out.open(DATABASEPATH, std::ios::app);
if (this->out.is_open())
{
std::string str = login + ":" + password + "\n";
std::cout << "writing " << str << std::endl;
this->out << str;
this->out.close();
return true;
}
return false;
}
As it stands, using a member variable is much worse than using the local - however, I suspect you actually want to pass the open file around amongst many member functions. If so, you can flush the output with:
this->out << std::flush;
without closing it.
Related
I am coding an ADTF recording file reader in C++. I have already read the header using the structure specified here
https://support.digitalwerk.net/adtf_libraries/adtf-streaming-library/v2/DATFileFormatSpecification.pdf
typedef struct tagFileHeader {
int ui32FileId;
int ui32VersionId;
int ui32Flags;
int ui32ExtensionCount;
long long ui64ExtensionOffset;
long long ui64DataOffset;
long long ui64DataSize;
long long ui64ChunkCount;
long long ui64MaxChunkSize;
long long ui64Duration;
long long ui64FileTime;
char ui8HeaderByteOrder;
long long ui64TimeOffset;
char ui8PatchNumber;
char _reserved[54];
char strDescription[1912];
} tFileHeader; // size is 2048 Bytes
I read the heder
ifstream file("myfile.dat", std::ifstream::binary);
char buffer[2048];
file.read(buffer, 2048);
const tagFileHeader* header = reinterpret_cast<const tagFileHeader*>(buffer);
And now I need to read the chunks. This is the chunks header, extracted from the same document
typedef struct tagChunkHeader {
long long ui64TimeStamp;
int ui32RefMasterTableIndex;
int ui32OffsetToLast;
int ui32Size;
short ui16StreamId;
short ui16Flags;
long long ui64StreamIndex;
} tChunkHeader; // size is 32 Bytes
Reading the chunks
for (int c = 0; c < header->ui64ChunkCount; ++c)
{
char chunkHeaderBuffer[32];
file.read(chunkHeaderBuffer, 32);
const tChunkHeader* chunk = reinterpret_cast<const tChunkHeader*>(chunkHeaderBuffer);
//Skeep chunk data
file.seekg(chunk->ui32Size, ios_base::cur);
}
I don't know how to interpret the chunk data. Is this specified in another document that I am missing?
Thanks
For the sake of completeness:
The chunk data layout depends on the original sample data and the used serialization. So there is not one single data layout. You have to deserialize the chunk data with the correct deserialization implementation and can then interpret the deserialized data with the correct struct definition. The information about the used serialization is stored within the index extension of a stream.
As C-3PFLO has already stated, the adtf_file library does all this for you, but you need all required deserializer plugins.
Here is a example (based on upcoming ADTF File Library 0.5.0) how to access dat files and extend the reader with additional adtffileplugins. Use this read dat files which contains e.g. flexray data recorded with ADTF 2.x:
/**
* #file
* ADTF File Access example
*
* #copyright
* #verbatim
Copyright # 2017 Audi Electronics Venture GmbH. All rights reserved.
This Source Code Form is subject to the terms of the Mozilla
Public License, v. 2.0. If a copy of the MPL was not distributed
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular file, then
You may include the notice in a location (such as a LICENSE file in a
relevant directory) where a recipient would be likely to look for such a notice.
You may add additional accurate notices of copyright ownership.
#endverbatim
*/
#include <adtf_file/standard_adtf_file_reader.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <map>
// initalize ADTF File and Plugin Mechanism
static adtf_file::Objects oObjects;
static adtf_file::PluginInitializer oInitializer([]
{
adtf_file::add_standard_objects();
});
void query_file_info(adtf_file::Reader& reader)
{
using namespace adtf_file;
//setup file version
uint32_t ifhd_version = reader.getFileVersion();
std::string adtf_version("ADTF 3 and higher");
if (ifhd_version < ifhd::v400::version_id)
{
adtf_version = "below ADTF 3";
}
//begin print
std::cout << std::endl << "File Header" << std::endl;
std::cout << "------------------------------------------------------------------------------" << std::endl;
std::cout << "File version : " << reader.getFileVersion() << " - " << adtf_version << std::endl;
std::cout << "Date : " << reader.getDateTime().format("%d.%m.%y - %H:%M:%S") << std::endl;
std::cout << "Duration : " << reader.getDuration().count() << std::endl;
std::cout << "Short description : " << getShortDescription(reader.getDescription()) << std::endl;
std::cout << "Long description : " << getLongDescription(reader.getDescription()) << std::endl;
std::cout << "Chunk count : " << reader.getItemCount() << std::endl;
std::cout << "Extension count : " << reader.getExtensions().size() << std::endl;
std::cout << "Stream count : " << reader.getStreams().size() << std::endl;
std::cout << std::endl << "Streams" << std::endl;
std::cout << "------------------------------------------------------------------------------" << std::endl;
auto streams = reader.getStreams();
for (const auto& current_stream : streams)
{
auto property_stream_type = std::dynamic_pointer_cast<const PropertyStreamType>(current_stream.initial_type);
if (property_stream_type)
{
std::string stream_meta_type = property_stream_type->getMetaType();
std::cout << "Stream #" << current_stream.stream_id << " : " << current_stream.name << std::endl;
std::cout << " MetaType : " << stream_meta_type << std::endl;
property_stream_type->iterateProperties(
[&](const char* name,
const char* type,
const char* value) -> void
{
std::cout << " " << name << " - " << value << std::endl;
});
}
}
}
class StreamsInfo
{
typedef std::map<uint16_t, std::chrono::microseconds> LastTimesMap;
typedef std::map<uint16_t, std::string> StreamNameMap;
public:
StreamsInfo(adtf_file::Reader& reader)
{
auto streams = reader.getStreams();
for (auto current_stream : streams)
{
_map_stream_name[current_stream.stream_id] = current_stream.name;
UpdateType(current_stream.stream_id, current_stream.initial_type);
}
}
~StreamsInfo() = default;
std::string GetDiffToLastChunkTime(const uint16_t& stream_id, const std::chrono::microseconds& current_time)
{
return GetLastTimeStamp(_map_last_chunk_time, stream_id, current_time);
}
std::string GetDiffToLastSampleStreamTime(const uint16_t& stream_id, const std::chrono::microseconds& current_time)
{
return GetLastTimeStamp(_map_last_stream_time, stream_id, current_time);
}
std::string GetStreamName(const uint16_t& stream_id)
{
return _map_stream_name[stream_id];
}
void UpdateType(const uint16_t& stream_id, const std::shared_ptr<const adtf_file::StreamType>& type)
{
auto property_stream_type = std::dynamic_pointer_cast<const adtf_file::PropertyStreamType>(type);
if (property_stream_type)
{
_map_stream_meta_type[stream_id] = property_stream_type->getMetaType();
}
}
std::string GetLastStreamMetaType(const uint16_t& stream_id)
{
return _map_stream_meta_type[stream_id];
}
private:
std::string GetLastTimeStamp(LastTimesMap& map_last_times,
const uint16_t& stream_id,
const std::chrono::microseconds& current_time)
{
std::chrono::microseconds result(-1);
LastTimesMap::iterator it = map_last_times.find(stream_id);
if (it != map_last_times.end())
{
result = current_time - it->second;
it->second = current_time;
}
else
{
if (current_time.count() != -1)
{
map_last_times[stream_id] = current_time;
}
}
if (result.count() >= 0)
{
return a_util::strings::format("%lld", result.count());
}
else
{
return "";
}
}
LastTimesMap _map_last_chunk_time;
LastTimesMap _map_last_stream_time;
StreamNameMap _map_stream_name;
StreamNameMap _map_stream_meta_type;
};
void access_file_data(adtf_file::Reader& reader, const std::string& csv_file_path)
{
using namespace adtf_file;
//load stream information
StreamsInfo stream_info(reader);
std::cout << std::endl << "File data" << std::endl;
std::cout << "------------------------------------------------------------------------------" << std::endl;
utils5ext::File csv_file;
csv_file.open(csv_file_path, utils5ext::File::om_append | utils5ext::File::om_write);
//set the labels
csv_file.writeLine("stream;stream_name;chunk_type;stream_type;chunk_time;samplestream_time;chunk_time_delta_to_lastofstream;samplestream_time_delta_to_lastofstream");
size_t item_count = 0;
for (;; ++item_count)
{
try
{
auto item = reader.getNextItem();
std::chrono::microseconds chunk_time = item.time_stamp;
std::string chunk_type;
auto type = std::dynamic_pointer_cast<const StreamType>(item.stream_item);
auto data = std::dynamic_pointer_cast<const Sample>(item.stream_item);
auto trigger = std::dynamic_pointer_cast<const Trigger>(item.stream_item);
std::chrono::microseconds sample_time(-1);
std::string sample_time_string("");
if (type)
{
//the type change is part of the
chunk_type = "stream_type";
stream_info.UpdateType(item.stream_id,
type);
}
else if (data)
{
chunk_type = "sample";
auto sample_data = std::dynamic_pointer_cast<const DefaultSample>(data);
if (sample_data)
{
sample_time = sample_data->getTimeStamp();
sample_time_string = a_util::strings::format("%lld", sample_time.count());
}
}
else if (trigger)
{
chunk_type = "trigger";
}
csv_file.writeLine(a_util::strings::format("%d;%s;%s;%s;%lld;%s;%s;%s",
static_cast<int>(item.stream_id),
stream_info.GetStreamName(item.stream_id).c_str(),
chunk_type.c_str(),
stream_info.GetLastStreamMetaType(item.stream_id).c_str(),
chunk_time.count(),
sample_time_string.c_str(),
stream_info.GetDiffToLastChunkTime(item.stream_id, chunk_time).c_str(),
stream_info.GetDiffToLastSampleStreamTime(item.stream_id, sample_time).c_str()
));
}
catch (const exceptions::EndOfFile&)
{
break;
}
}
csv_file.close();
}
adtf_file::Reader create_reader(const a_util::filesystem::Path& adtfdat_file_path)
{
//open file -> create reader from former added settings
adtf_file::Reader reader(adtfdat_file_path,
adtf_file::getFactories<adtf_file::StreamTypeDeserializers,
adtf_file::StreamTypeDeserializer>(),
adtf_file::getFactories<adtf_file::SampleDeserializerFactories,
adtf_file::SampleDeserializerFactory>(),
std::make_shared<adtf_file::sample_factory<adtf_file::DefaultSample>>(),
std::make_shared<adtf_file::stream_type_factory<adtf_file::DefaultStreamType>>());
return reader;
}
int main(int argc, char* argv[])
{
if (argc < 3 || argv[1] == NULL || argv[2] == NULL)
{
std::cerr << "usage: " << argv[0] << " <adtfdat> <csv> [<adtffileplugin> ...]" << std::endl;
return -1;
}
//set path for adtfdat|dat and csv file
a_util::filesystem::Path adtfdat_file = argv[1];
a_util::filesystem::Path csv_file = argv[2];
try
{
//verify adtf|dat file
if (("adtfdat" != adtfdat_file.getExtension())
&& ("dat" != adtfdat_file.getExtension()))
{
throw std::runtime_error(adtfdat_file + " is not valid, please use .adtfdat (ADTF 3.x) or .dat (ADTF 2.x).");
}
//verify csv file
if ("csv" != csv_file.getExtension())
{
throw std::runtime_error(csv_file + " is not valid, please use .csv for sample data export.");
}
//check for additional adtffileplugins
for (int i = 3; i < argc; i++)
{
a_util::filesystem::Path adtffileplugin = argv[i];
if ("adtffileplugin" == adtffileplugin.getExtension())
{
adtf_file::loadPlugin(adtffileplugin);
}
}
//setup reader
auto reader = create_reader(adtfdat_file);
//print information about adtfdat|dat file
query_file_info(reader);
//export sample data
access_file_data(reader, csv_file);
}
catch (const std::exception& ex)
{
std::cerr << ex.what() << std::endl;
return -2;
}
return 0;
}
Is there any reason why you try to reimplement an ADTF DAT File Reader ? It will be provided by the ADTF Streaming Library and should provide to access any data stored in a dat file. See the File Access Example (https://support.digitalwerk.net/adtf_libraries/adtf-streaming-library/v2/api/page_fileaccess.html) how to use the reader as well as the API itself and all other examples.
Hint: You can also use the successor - ADTF File Library with the same possibilities but with two more benefits: Complete Open Source to see how the (adtf)dat file handling works and also support for files created with ADTF 3.x. See https://support.digitalwerk.net/adtf_libraries/adtf-file-library/v0/html/index.html
For those interested in downloading the streaming Library, here follows the link
https://support.digitalwerk.net/projects/download-center/repository/show/adtf-libraries/adtf-streaming-library/release-2.9.0
I have a class User with two std::string attributes. When i try to read it from file i got exception from uxitility from line 222:
(*_Pnext)->_Myproxy = nullptr;
It happens after function isUserInFile()
Some peaces of my code:
Class User {
protected:
std::string login;
std::string password;
public:
friend std::istream&operator>>(std::istream&in, User &obj) {
//std::cout << "Логин: "; //"Login: "
in >> obj.login;
//std::cout << "Пароль: "; //"Password: "
in >> obj.password;
return in;
}
friend std::ostream&operator<<(std::ostream&out, User&obj) {
out << obj.login << " " << obj.password;
return out;
}
void encrypt() {
char key[3] = { 'K','E','Y' };
std::string buf = password;
for (int i = 0; i < buf.size(); i++)
buf[i] = password[i] ^ key[i % (sizeof(key) / sizeof(char))];
password = buf;
//buf.clear();
}
bool isUserInFile() {
User user;
std::ifstream file;
file.open("Users.txt");
while (!file.eof() && file.read((char*)&user, sizeof(User)))
if (login == user.login) {
file.close();
return true;
}
file.close();
return false;
}
};
bool registration() {
User user;
std::fstream file;
file.open("Users.txt", std::ios::in | std::ios::out | std::ios::app);
std::cout << "Регистрация:\n"; //"Registration:\n"
std::cin >> user;
user.encrypt();
if (!user.isUserInFile()) {
file.write((char*)&user, sizeof(User));
file.close();
return true;
}
std::cout << "Пользователь с данным логином уже существует\n"; //"User with this login already exists\n"
file.close();
system("pause");
return false;
}
Comments went in the correct direction to show where the problem is. But the solution is much simpler, you already have your stream operators, so just use them!
To write into the file you can use:
file << user << std::endl;
and then to read you simply:
file >> user;
For this to keep working you will need some things:
A user should never enter a white-space anywhere in their password.
You need to ensure that the writing and reading is always done in the same order.
Alternatively you can create a conversion from string and to string along the lines of:
static const char SEP1 = ' ', SEP2 = '\r';
friend std::string to_string(const User& u)
{
std::string result = u.login + SEP1 + u.password + SEP2;
return result;
}
explicit User(std::string line)
{
size_t pos1 = s.find(SEP1);
size_t pos2 = s.find(SEP2, pos1);
login = s.substr(0, pos1);
password = s.substr(pos1+1, pos2-pos1);
}
Then you can in your main you can read a block of data and simply construct a user from it, alternatively you can convert a user into a string before writing. A beauty of this approach is that you select the separators and they are stable between functions.
So I got this assignment and I have everything working perfectly except calling this one function that is supposed to format the email string. If not calling this function, I can print it exactly the way the professor says it is supposed to be. However, with calling this function, I can't seem to get it to return the information and print it. Can anyone help me out with this? I have spent an unfortunate amount of hours trying to get this one thing worked out.
//Function Prototypes
std::string FormatEmailString(std::string from, std::string to, std::string subject, std::string msg);
std::string GetInboxFile(std::string username);
std::string GetLine(std::istream & sin);
int main()
{
std::string email;
std::string from;
std::string to;
std::string subject;
std::string msg;
std::ifstream fin;
std::ofstream fout;
std::string user1;
fin.open(user1 + "-inbox.txt", std::ios::in);
while (fin.eof() == false) // I know fin.eof is not a good method to use.
{ // I tried while(fin) but it lets extra "From:" "To"...
email = GetLine(fin); //GetLine is a function call to getline.
from = GetLine(fin);
to = GetLine(fin);
subject = GetLine(fin);
msg = GetLine(fin);
std::string formatted = FormatEmailString(from, to, subject, msg);
fout << formatted;
}
std::cout << std::endl;
fin.close();
std::cin.get();
return 0;
}
std::string FormatEmailString(std::string from, std::string to, std::string subject, std::string msg)
{
std::ostringstream out;
std::ifstream fin;
std::string user1;
fin.open(user1 + "-inbox.txt", std::ios::in);
out << std::endl;
out << "From: " << from << std::endl;
out << "To: " << to << std::endl;
out << "Subject: " << subject << std::endl;
out << "Message: " << msg << std::endl;
fin.close();
return out.str();
}//END FormatEmailString
std::string GetLine(std::istream & sin)
{
std::string s;
std::getline(sin, s);
return s;
}//END GetLine
//FROM user1-inbox.txt TEXT FILE:
#email //This Line not printed
abc //FROM
user1 //TO
hello //Subject
How about lunch? //Message
#email //This line not printed
abc //From
user1 //To
Join the Dark Side //Subject
We have cookies! //Message
//END TEXT FILE
you are not opening file which you want to write into.
your fout is used only in two places... in declaration and then u are writing into it.
I'm writing some code which handles a lot of data. When an error occures, it usually happens that the error will occur many times, so I want to report it only once. The problem I have is, that I want to have individual error messages. In C I would use a method with variadic arguments, bit of course this is not really typesafe, so I wonder how I can achieve the same in C++ with typesafe output. I know that I can stringstream and create the indvidual string, but that would mean that I have to create the full error message, even if it is discarded, because it was already printed, and stringstream is not exactly fast either.
So currently I use code like this:
std::string key = "BT:EMPTY";
if(mErrorReport.find(key) == mErrorReport.end())
{
std::cerr << "ERROR [" << Name<< "] Type is empty! " << std::endl;
mErrorReport.insert(key);
}
std::string key = "UI:"+Unitcode;
if(mErrorReport.find(key) == mErrorReport.end())
{
std::cerr << "ERROR [" << Name<< "] Room with the id " << Unitcode << " doesn't exist! " << std::endl;
mErrorReport.insert(key);
}
...
In C I would have written a variadic function like this:
void ErrorLog(const char *key, int nLogLevel, const char fmt, ...)
{
// Check if this error was already reported before.
if(mErrorLog.find(key) == mErrorLog.end())
{
fprintf(stderr, fmt, ...);
mErrorLog.insert(key);
}
}
So I wonder if there is some best practice for something like that.
Why don't you just use
void ErrorLog(const std::string& key, const std::string& name, const std::string& what)
{
if (mErrorLog.find(key) == mErrorLog.end())
{
std::cerr << "ERROR[" << name << "]" << what << std::endl;
mErrorLog.insert(key);
}
}
and call it like
ErrorLog("BT:EMPTY", Name, "Type is empty!");
ErrorLog("UI:" + Unitcode, Name, std::string("Room with the id ") + Unitcode + " doesn't exist!");
If Name doesn't change you could remove the parameter and just add it to the std::err call.
Update: Alternative solution
class ErrorLogWriter
{
public:
ErrorLogWriter(const std::string& name, const std::string& key, std::set<std::string>& log)
:m_name(name)
, m_key(key)
, m_log(log)
{}
ErrorLogWriter& operator<<(const std::string& msg)
{
if (m_log.find(m_key) == m_log.end())
{
std::cerr << "ERROR[" << m_name << "]" << msg << std::endl;
m_log.insert(m_key);
}
return *this;
}
private:
std::string m_name;
std::string m_key;
std::set<std::string>& m_log;
};
class ErrorLog
{
public:
ErrorLog(const std::string& name, std::set<std::string>& log)
:m_name(name)
,m_log(log)
{}
ErrorLogWriter operator()(const std::string& key)
{
return ErrorLogWriter(m_name, key, m_log);
}
private:
std::string m_name;
std::set<std::string>& m_log;
};
int main()
{
std::string Name = "NAME";
std::string Unitcode = "UNITCODE";
std::set<std::string> mErrorLog;
ErrorLog log(Name, mErrorLog);
log("BT:EMPTY") << "Type is empty!";
log("UI:" + Unitcode) << "Room with the id " << Unitcode << " doesn't exist!";
}
here is my problem. i have some two dimensional data with changing dimensionality, that i want to read into an 2d-array of doubles. Furthermore, there are at some points not number in the file but "NaN"s, that i want to be replaced by a zero. I made my code working so far, but i only managed to read integers. Maybe you could help me out to read it as doubles?
Here is what i got so far:
void READER(char filepath [], int target [129][128])
{
//---------------------------- header double & int
int rowA = 0;
int colA = 0;
std::string line;
std::string x;
std::cout << "reading file: " << filepath << "\n";
std::cout << std::endl;
std::ifstream fileIN;
fileIN.open(filepath);
if (!fileIN.good())
std::cerr << "READING ERROR IN FILE: " << filepath << std::endl;
while (fileIN.good())
{
while (getline(fileIN, line))
{
std::istringstream streamA(line);
colA = 0;
while (streamA >> x)
{
boost::algorithm::replace_all(x, "NaN", "0");
boost::algorithm::replace_all(x, ",", ""); //. rein
// std::cout << string_to_int(x) << std::endl;
target [rowA][colA] = string_to_int(x);
colA++;
}
rowA++;
if(rowA%5 ==0)
{
std::cout << "*";
}
}
}
std::cout << " done." <<std::endl;
}
this writes the files into 'target'. The function string to int looks the following:
int string_to_int (const std::string& s)
{
std::istringstream i(s);
int x;
if(!(i >> x))
return 0;
return x;
}
here you find some example data:
"exactly, thats what i thought about doing with the line boost::algorithm::replace_all(x, ",", ""); by replacing , by ."
Use following function to convert to any type, say double :-
template <typename T>
T StringToNumber ( const std::string &Text )
{
std::istringstream ss(Text);
T result;
return ss >> result ? result : 0;
}
Call using :
boost::algorithm::replace_all(x, ",", "."); // Change , to .
std::cout << StringToNumber<double>(x) << std::endl;
Or
you can simply use boost::lexical_cast
std::cout<<boost::lexical_cast<double>( x )<<std::endl;
Make sure you have a double 2D array