Naming a log file using date and time in C++ - 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;
}
}

Related

C++ values from struct creating newlines in CSV file

I am very new to C++, and currently am attempting to create a simple user interface which will do the following:
Check if a CSV file already exists with the given name
Create that file if it does not exists, and write the headers
Ask user for information, store in struct
Write data to CSV file when done
The issue I am facing is that when the program ends, and writes the data to the CSV file it creates newlines for each struct variable I am writing. I would like the program to just write all data on one line with comma separated format.
Example code:
struct.h
#ifndef struct_h
#define struct_h
#include "string"
namespace RB
{
struct Values
{
std::string event;
std::string town;
std::string state;
std::string date;
};
}; // namespace
#endif /* struct_h */
create.h
#ifndef create_h
#define create_h
#include <cstdio>
#include <ctime>
#include <iostream>
#include <fstream>
namespace RB
{
int createFile()
{
time_t t = time(nullptr); // the current time
struct tm gmt = *gmtime(&t); // structured time in GMT
const int year = 1900 + gmt.tm_year;
static const char *filename = "results_";
if (std::ifstream((filename + std::to_string(year) + ".csv").c_str()))
{
std::cout << "File Found, appending to file " << (filename + std::to_string(year) + ".csv").c_str() << std::endl;
}
else
{
std::cout << "No file with name " << (filename + std::to_string(year) + ".csv").c_str() << "\ncreating file...\n" << std::endl;
std::ofstream ofile((filename + std::to_string(year) + ".csv").c_str());
ofile << "Event" << ","
<< "Town" << ","
<< "State" << ","
<< "Date" << "\n";
ofile.flush();
ofile.close();
};
return 0;
};
}
#endif /* create_h */
main.cpp
#include <cstdio>
#include <stdlib.h>
#include <iostream>
#include "struct.h"
#include "create.h"
int main()
{
// Run Create before continuing
int c = RB::createFile();
struct RB::Values revent;
// Get Event Name
std::cout << "Starting to enter data for race event...\n" << std::endl;
std::cout << "What was the name of the event: ";
std::cin >> revent.event;
// Get Event Town
std::cout << "What town was the race run in: ";
std::cin >> revent.town;
// Get Event City
std::cout << "What state was the race run in: ";
std::cin >> revent.state;
// Get Event Date
std::cout << "When was the race run: ";
std::cin >> revent.date;
time_t t = time(nullptr); // the current time
struct tm gmt = *gmtime(&t); // structured time in GMT
const int year = 1900 + gmt.tm_year;
static const char *filename = "results_";
if (std::ifstream((filename + std::to_string(year) + ".csv").c_str()))
{
std::ofstream ofile((filename + std::to_string(year) + ".csv").c_str(), std::ofstream::out | std::ofstream::app);
ofile << revent.event << ",";
ofile << revent.town << ",";
ofile << revent.state << ",";
ofile << revent.date;
ofile.close();
};
return 0;
}
Sample Output:
Event,Town,State,Date
CapRock
,Turkey
,Texas
,March 9
I assume this is something simple I am doing wrong, but cannot seem to figure it out on my own.

C++ Save a Struct String into A Text File

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;
}

fixed amount of digits on creating .txt file

I need to create file with specific file name format (on windows). the format is:
Name_nodeNum_frequency.txt
nodeNum is int and frequency is float.
those two variables should be written with fixed digits:
if nodeNum is 8 --> 008
if frequency is 4.88421 --> 4.884
this is the function:
create_file(int nodeNum, double frequency)
{
char buffer [50];
//convert int to string
itoa(nodeNum, buffer, 10);
string sNodeNum = string(buffer);
//not sure about the double
//tried to_string but I got:
// more than instance of overloaded function matches the argument list
string fileName = ("Name_" + sNodeNum + "_" + sfreq + "MHZ");
FILE* pFile = OpenFile(fileName);
}
I tried to use %d, but it seems like I should not do that:
string fileName = ("Delay_" + "%3d" + "_" + sfreq + "MHZ" , sNodeNum);
I will be happy for some guidance.
thanks!
You seem to be mixing C and C++ here. A simple way to do this in C would be:
#include <stdio.h>
int main()
{
int sNodeNum = 8;
double sfreq = 4.88421;
char filename[50];
sprintf(filename, "Delay_%03d_%.3fMHZ.txt", sNodeNum, sfreq);
FILE* pFile = fopen(filename, "w");
return 0;
}
If on the other hand, if you want to use C++, you should make a few changes:
#include <iomanip>
#include <fstream>
#include <sstream>
#include <iostream>
int main()
{
int sNodeNum = 8;
double sfreq = 4.88421;
std::ostringstream ss;
ss << "Delay_" << std::setfill('0') << std::setw(3) << sNodeNum
<< "_" << std::setprecision(4) << sfreq << "MHZ.txt";
std::string filename(ss.str());
std::ofstream fout(filename.c_str());
return 0;
}
Each of these two approaches opens a file for writing, with the name Delay_008_4.884MHZ.txt.
Live demo link
#include <string>
#include <iomanip>
#include <iostream>
int nodeNum = 8;
float frequency = 4.88421f;
std::ostream& out = std::cout; // put your std::ofstream file or std::ostringstream
std::ios::fmtflags flags = out.flags();
out.width(3);
out.fill('0');
out.setf(std::ios::right, std::ios::adjustfield);
out << nodeNum << std::endl;
flags = out.flags(flags);
out.precision(3);
out.setf(std::ios::fixed, std::ios::floatfield);
out << frequency;
out.flags(flags);
Or even simpler:
out << std::setw(3) << std::setfill('0') << std::right << nodeNum << std::endl;
out << std::setprecision(3) << std::fixed << frequency;
Output:
008
4.884

Pass system date and time as a filename in C++

I wanted to make an Attendance system which would take system date and time as file name of the file for ex:
this is how normally it is
int main () {
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
cout << (now->tm_year + 1900) << '-'
<< (now->tm_mon + 1) << '-'
<< now->tm_mday
<< endl;
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}
but i want system date and time in place of example.txt
i have calculated time by including ctime header file in the program above program is just example .
You can use strftime() function to format time to string,It provides much more formatting options as per your need.
int main (int argc, char *argv[])
{
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
char buffer [80];
strftime (buffer,80,"%Y-%m-%d.",now);
std::ofstream myfile;
myfile.open (buffer);
if(myfile.is_open())
{
std::cout<<"Success"<<std::endl;
}
myfile.close();
return 0;
}
#include <algorithm>
#include <iomanip>
#include <sstream>
std::string GetCurrentTimeForFileName()
{
auto time = std::time(nullptr);
std::stringstream ss;
ss << std::put_time(std::localtime(&time), "%F_%T"); // ISO 8601 without timezone information.
auto s = ss.str();
std::replace(s.begin(), s.end(), ':', '-');
return s;
}
Replace std::localtime* with std::gmtime* if you work together abroad.
Usage e.g.:
#include <filesystem> // C++17
#include <fstream>
#include <string>
namespace fs = std::filesystem;
fs::path AppendTimeToFileName(const fs::path& fileName)
{
return fileName.stem().string() + "_" + GetCurrentTimeForFileName() + fileName.extension().string();
}
int main()
{
std::string fileName = "example.txt";
auto filePath = fs::temp_directory_path() / AppendTimeToFileName(fileName); // e.g. MyPrettyFile_2018-06-09_01-42-00.log
std::ofstream file(filePath, std::ios::app);
file << "Writing this to a file.\n";
}
*See here for a thread-safe alternative of those functions.
You could try using ostringstream to create a date string (as you're doing with cout), then use it's str() member function to retrieve the corresponding date string.
You can use stringstream class for this purpose, for example:
int main (int argc, char *argv[])
{
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
stringstream ss;
ss << (now->tm_year + 1900) << '-'
<< (now->tm_mon + 1) << '-'
<< now->tm_mday
<< endl;
ofstream myfile;
myfile.open (ss.str());
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
return(0);
}

Quoting strings in C++

In Pascal Lazarus/Delphi, we have a function QuotedStr() that wraps any string within single quotes.
Here's an example of my current C++ code:
//I need to quote tblCustomers
pqxx::result r = txn.exec( "Select * from \"tblCustomers\" ");
Another one:
//I need to quote cCustomerName
std::cout << "Name: " << r[a]["\"cCustomerName\""];
Similar to the above, I have to frequently double-quote strings. Typing this in is kind of slowing me down. Is there a standard function I can use for this?
BTW, I develop using Ubuntu/Windows with Code::Blocks. The technique used must be compatible across both platforms. If there's no function, this means that I must write one.
C++14 added std::quoted which does exactly that, and more actually: it takes care of escaping quotes and backslashes in output streams, and of unescaping them in input streams. It is efficient, in that it does not create a new string, it's really a IO manipulator. (So you don't get a string, as you'd like.)
#include <iostream>
#include <iomanip>
#include <sstream>
int main()
{
std::string in = "\\Hello \"Wörld\"\\\n";
std::stringstream ss;
ss << std::quoted(in);
std::string out;
ss >> std::quoted(out);
std::cout << '{' << in << "}\n"
<< '{' << ss.str() << "}\n"
<< '{' << out << "}\n";
}
gives
{\Hello "Wörld"\
}
{"\\Hello \"Wörld\"\\
"}
{\Hello "Wörld"\
}
As described in its proposal, it was really designed for round-tripping of strings.
Using C++11 you can create user defined literals like this:
#include <iostream>
#include <string>
#include <cstddef>
// Define user defined literal "_quoted" operator.
std::string operator"" _quoted(const char* text, std::size_t len) {
return "\"" + std::string(text, len) + "\"";
}
int main() {
std::cout << "tblCustomers"_quoted << std::endl;
std::cout << "cCustomerName"_quoted << std::endl;
}
Output:
"tblCustomers"
"cCustomerName"
You can even define the operator with a shorter name if you want, e.g.:
std::string operator"" _q(const char* text, std::size_t len) { /* ... */ }
// ...
std::cout << "tblCustomers"_q << std::endl;
More info on user-defined literals
String str = "tblCustomers";
str = "'" + str + "'";
See more options here
No standard function, unless you count std::basic_string::operator+(), but writing it is trivial.
I'm somewhat confused by what's slowing you down - quoted( "cCustomerName" ) is more characters, no? :>
You could use your own placeholder character to stand for the quote, some ASCII symbol that will never be used, and replace it with " just before you output the strings.
#include <iostream>
#include <string>
struct quoted
{
const char * _text;
quoted( const char * text ) : _text(text) {}
operator std::string () const
{
std::string quotedStr = "\"";
quotedStr += _text;
quotedStr += "\"";
return quotedStr;
}
};
std::ostream & operator<< ( std::ostream & ostr, const quoted & q )
{
ostr << "\"" << q._text << "\"";
return ostr;
}
int main ( int argc, char * argv[] )
{
std::string strq = quoted( "tblCustomers" );
std::cout << strq << std::endl;
std::cout << quoted( "cCustomerName" ) << std::endl;
return 0;
}
With this you get what you want.
What about using some C function and backslash to escape the quotes?
Like sprintf_s:
#define BUF_SIZE 100
void execute_prog() {
//Strings that will be predicted by quotes
string param1 = "C:\\users\\foo\\input file.txt", string param2 = "output.txt";
//Char array with any buffer size
char command[BUF_SIZE];
//Concating my prog call in the C string.
//sprintf_s requires a buffer size for security reasons
sprintf_s(command, BUF_SIZE, "program.exe \"%s\" \"%s\"", param1.c_str(),
param2.c_str());
system(command);
}
Resulting string is:
program.exe "C:\users\foo\input file.txt" "output.txt"
Here is the documentation.