Variable filename with ifstream and ofstream - c++

I want to use the system date I have from the computer and use it as the name of the .txt file. Here's what I have so far:
void idle_time()
{
LASTINPUTINFO last_info;
last_info.cbSize = sizeof(LASTINPUTINFO);
int tickCount = 0;
int minutes = 0;
int count = 0;
SYSTEMTIME a;
while(true)
{
GetLastInputInfo(&last_info);
tickCount = GetTickCount();
int minutes = (tickCount - last_info.dwTime) / 60000;
count++;
string date;
date += a.wMonth;
date += "/";
date += a.wDay;
date += "/";
date += a.wYear;
if((minutes >= 1) && (count%3000==0))
{
//std::string filename = date;
//filename += ".txt";
ifstream in(string(date + ."txt").c_str());
float sum;
in >> sum;
sum++;
in.close();
ofstream out(string(date + ".txt").c_str());
out << sum;
out.flush();
out.close();
}
I'm sorry for the terrible indentation. This editor doesn't do it justice. But anyway, how would I use the date as the filename?

The date string you are using contains / characters which are used to separate directories in path. You simply need to replace them with another (not forbidden) character.
I'd also suggest you not to use m/d/Y date format for filenames. They do not sort well. Y-m-d is usually better because the files will be sorted from oldest to newest.
Edit: ah, and for my last statement to be true, you'd also need to pad month and day with zero to two digits, i.e. have something like 2011-08-05.
Ah, I see that the time appending is also done incorrectly. You can't append integers to strings like that. #hmjd already posted you one method of solving this; but I think it will be better to just use a dedicated time->string conversion method.
I'm not a Windows programmer, so I won't help you much with this SYSTEMTIME thing. You'll probably need to use GetTimeFormat(). But here's a simple example how to solve it with standard C/C++ strftime():
char date_buf[11];
time_t a = time(0);
strftime(date_buf, sizeof(buf), "%Y-%m-%d", gmtime(&t));
date += buf;
If you want the date in local time zone rather than UTC, use localtime() instead of gmtime().
Hope it helps someone. I believe GetTimeFormat() works similarly, so maybe this can guide you a bit.

Related

C++ cannot name txt file after current sytem time and date

Hi im having issue with this code i have made. It will compile but once i hit enter in the program it says this:
Unhandled exception at 0x008E8641 in Log Test.exe: 0xC0000005: Access violation reading location 0x566D846A.
Here is the code:
#include <iostream>
#include <time.h>
#include <fstream>
using namespace std;
int main() {
cin.get();
time_t Time;
Time = time(0);
string Date = __DATE__;
string LOG = Time + "_" + Date;
ofstream TEST;
TEST.open(LOG);
TEST << "This Text Should Appear Inside Of File.";
TEST.close();
cout << "Log has been Made.";
cin.get();
return 0;
}
I beleive that the problem is the time and how i tried putting it into a string but i dont see what i did doesn't work.
I would think that Time is an integer type so this:
Time + "_"
results in pointer addition so that what gets added to the string is a bad pointer to some location beyond the beginning of "_".
You see string literals like "_" actually resolve to an address (pointer). Adding an integer like Time to it simple makes it point elsewhere in memory.
First you need to convert your Time to a string.
I happen to have this code laying around that may work for you:
std::string get_stamp()
{
time_t t = std::time(0);
char buf[sizeof("YYYY-MM-DD HH-MM-SS")];
return {buf, std::strftime(buf, sizeof(buf), "%F %H-%M-%S", std::localtime(&t))};
}
Note: Using std::localtime is not threas-safe.
If you enabled compiler warnings, it should have screamed at you about this line:
string LOG = Time + "_" + Date;
Here, Time is being converted to a pointer, and you're getting undefined behaviour. For a not completely C++ solution, I recommend this simple approach:
time_t t = time(0);
struct tm ttm;
localtime_r( &t, &ttm );
char timestamp[20]; // actually only need 17 chars plus terminator.
sprintf_s( timestamp, sizeof(timestamp), "%04d-%02d-%02d_%02d%02d%02d",
ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_day, ttm.tm_hour, ttm.tm_min, ttm.tm_sec );
string logfilename = string(timestamp) + ".log";
ofstream logfile( logfilename.c_str() );
Note that localtime_r is not completely portable. On windows, use localtime_s, which unfortunately also reverses the order of the arguments.

Inserting text into a file only works once

My Goal:
I am trying to write an application in C++ where the user can ask for a a certain weather parameter over a certain date range and this program will find that information from the internet and write it out to a text file. So the user can ask for something like high temperature for every day between August 2, 2009 and August 10, 2009. The application will then spit out a text file something like this:
Month, Date, Year, High
8 2 2009 80.3
8 3 2009 76.9
...
8 10 2009 68.4
I already have getting the webpages, parsing the HTML into meaningful values, and writing these values into a database (txt file) working. I also wrote a function
insert(std::iostream& database, Day day); //Day is a class I defined that contains all the weather information
that will find where this day belongs to stay in order, and insert it into the middle. I have tested this function and it works exactly like it should.
My Problem:
I am now trying to write a function that does this:
void updateDatabase(std::iostream& database, Day start, Day end)
{
Day currentDay = start;
while (currentDay.comesBefore(end))
{
if (currentDay.notInDatabase(database))
insert(database, currentDay);
currentDay = currentDay.nextDay();
}
}
But unfortunately, the insert() function only works correctly if I call it once per program. If I try to call insert() twice in a row, (or three, or four, or five) only the last day will show up on my text file.
Here is the smallest possible amount of code that reproduces my problem but still runs.
#include <iostream>
#include <fstream>
#include <string>
const std::string FOLDER = "/Users/Jimmy/Desktop/WeatherApp/";
const std::string DATABASE_NAME = FOLDER + "database.txt";
class day
{
public:
int date;
int month;
int year;
bool comesBefore(int month, int date, int year);
day(int month, int date, int year)
{
this->month = month;
this->date = date;
this->year = year;
}
};
void writeToDatabase(std::iostream& file, day today, bool end = true);
void insertDay(std::iostream& file, day today);
int main()
{
std::fstream database;
database.open(DATABASE_NAME);
if (database.fail())
{
std::cout << "Cannot find database.\n";
exit(1);
}
day second(1, 2, 2000);
insertDay(database, second);
std::cout << "First day inserted. Press enter to insert second day.\n";
std::cin.get();
day third(1, 3, 2000);
insertDay(database, third);
std::cout << "Done!\n";
return 0;
}
bool day::comesBefore(int month, int day, int year)
{
if (this->year < year)
return true;
if (this->year > year)
return false;
//We can assume this->year == year.
if (this->month < month)
return true;
if (this->month > month)
return false;
//We can also assume this->month == month
return (this->date < day);
}
void writeToDatabase(std::iostream& file, day today, bool end)
{
if (end) //Are we writing at the current cursor position or the end of the file?
file.seekg(0, std::ios::end);
file << today.month << '\t' << today.date << '\t' << today.year << '\n';
return;
}
void insertDay(std::iostream& file, day today)
{
//Clear flags, and set cursor at beggining
file.clear();
file.seekg(0, std::ios::beg);
int date, month, year;
long long positionToInsert = 0;
while (!file.eof())
{
file >> month >> date >> year;
//std::cout << month << date << year << '\n';
if (today.comesBefore(month, date, year))
{
//We found the first day that comes after the day we are inserting
//Now read backwards until we hit a newline character
file.unget();
char c = '\0';
while (c != '\n')
{
file.unget();
c = file.get();
file.unget();
}
positionToInsert = file.tellg();
break;
}
}
if (file.eof())
{
//We hit the end of the file. The day we are inserting is after every day we have. Write at the end.
file.clear();
writeToDatabase(file, today);
return;
}
file.clear();
file.seekg(0, std::ios::beg);
std::fstream tempFile;
std::string tempFileName = FOLDER + "tempfile.txt";
std::string terminalCommand = "> " + tempFileName;
//Send the command "> /Users/Jimmy/Desktop/WeatherApp/tempfile.txt" to the terminal.
//This will empty the file if it exists, and create it if it does not.
system(terminalCommand.c_str());
tempFile.open(tempFileName);
if (tempFile.fail())
{
std::cout << "Failure!\n";
exit(1);
}
int cursorPos = 0;
while (cursorPos++ < positionToInsert)
{
char c = file.get();
tempFile.put(c);
}
tempFile.put('\n'); //To keep the alignment right.
writeToDatabase(tempFile, today, false);
file.get();
char c = file.get();
while (!file.eof())
{
tempFile.put(c);
c = file.get();
}
terminalCommand = "mv " + tempFileName + " " + DATABASE_NAME;
//Sends the command "mv <tempFileName> <databaseName>" to the terminal.
//This command will move the contents of the first file (tempfile) into the second file (database)
//and then delete the old first file (tempfile)
system(terminalCommand.c_str());
return;
}
I added that the cin.get() part in main so I could look at my database before and after each insert() call. Here is the database before compiling/running:
1 1 2000
1 4 2000
Here is the database before hitting enter/moving on past cin.get():
1 1 2000
1 2 2000
1 4 2000
And here is the database after I move on past cin.get() and my program exits:
1 1 2000
1 3 2000
1 4 2000
I have changed the dates that are being inserted, how many dates are being inserted, how far apart the two dates are and the initial size of the database before running the program, but I always get the same result. After every call to insert(), the database acts as if that was the only call to insert that was ever made. However, if I run the program many times, the text file continues to grow. I only get this problem if I try to call insert more than once per compiling/running. So If I were to run this program 5 times:
int main()
{
std::fstream database;
database.open(DATABASE_NAME);
if (database.fail())
{
std::cout << "Cannot find database.\n";
exit(1);
}
day today(1, 2, 2000);
insertDay(database, today);
std::cout << "Done!\n";
return 0;
}
My database would end up looking like this:
1 1 2000
1 2 2000
1 2 2000
1 2 2000
1 2 2000
1 2 2000
1 4 2000
I suspect it's a problem either with fstream.clear(), fstream.seekg() and fstream.eof(), or maybe about closing/reopening the file. But nothing that I have done to fix it has helped.
Also, it is worth noting that this will not run on a windows computer. It should be fine on linux, but I have only tested it on Mac, so I could be wrong. It uses bash for creating/deleting/renaming/moving files.
Any help (even just a nudge in the right direction) is HUGELY appreciated. I've been pulling my hair out over this one for a while. Also, I know SO dislikes code dumps, so I have massively simplified the problem. My full program is 700+ lines and 10 different files, and this is about as short as I could get it while still getting the idea across.
The problem you have here has to do with the way you handle the file: when you mv a file, the old file is not overwritten per se; instead it is unlinked ("deleted") and a new file is created in is place.
On Unix-like operating systems, you can still retain a handle to an unlinked file: it's just not accessible using a path. This is why on Unix it's perfectly okay to delete a file that's still open, unlike on Windows: the file still exists after you have unlinked it, at least until all the file descriptors have been closed. This means that database has not changed at all: it is still pointing to your old file and contains the same contents.
A simple workaround would be to close and reopen the file. (From a practical perspective, it's probably much better to just use a readily available solution such as Sqlite.)

Displaying a date with a leading zero in the input C++

I am currently trying to create a header file that takes information from a user and displays information in a form.
For the most part, I have had no problem, however, I need the user to input their date of birth in the format MMDDYYYY, and then convert it to MM/DD/YYYY and display it in the form.
My problem is that if the user inputs the month '01-09', what displayed was nowhere near correct. I still need to display the month the exact way the user input it, so it has to be displayed as (i.e. 01/01/1967).
The variable for the patient's date of birth is called int patientDateOfBirth.
This data type cannot be changed, it has to be an int.
The method in the header file that I am using is as follows:
void PatientDemographicInformation::printPatientDateOfBirth( )
{
int userMonth, userDay, userYear;
String birthDate = String(itoa(patientDateOfBirth));
// Calculation to determine month, day, and year from the MMDDYYYY format.
userMonth = scanf ("%d", &userMonth);
// this was another method I used, however the leading zero messed it up.
// userMonth = patientDateOfBirth / 1000000;
userDay = patientDateOfBirth / 10000 % 100;
userYear = patientDateOfBirth % 10000;
cout << userMonth << "/";
cout << setfill('0') << setw(2) << userDay << "/";
cout << userYear;
}
Also, this is the first time I am using this forum, so if my formatting is off, please forgive me. I also have little experience with this language, so if the answer is simple, please go easy on me!
Thank you.
EDIT: I've just noticed that there is the variable String birthDate that is not used in the calculation. I was not sure if converting the int into a String would work, but I gave it a shot regardless, but it did not work and I forgot to remove that variable. If that could work, however, please let me know.
EDIT: Sorry if I wasn't as clear as I had hoped to be. I want the user to input a date of birth in the format MMDDYYYY and output it as MM/DD/YYYY, meaning I have to separate the month, day, and year into seperate variables and then put them into a cout statement.
The problem that I am having is if the user puts a 01 thru 09 as the month (i.e. 01141967),
When the method tries to do the calculation, I get some strange number in the output (i.e. 112230056/00004814/5599932) or the like. I am completely stumped by this dilemma. I've searched forever trying to find some kind of answer and I have tried several methods, all not working.
The impression you gave is that you have a patientDateOfBirth integer, in one the following formats: mmddyyyy OR mddyyyy, is that correct? If it is, the original
int month = patientDateOfBirth / 1000000;
int day = patientDateOfBirth / 10000 % 100;
int year = patientDateOfBirth % 10000;
should work ok, regardless of leading zeroes on some original input. An alternative would be using C++11's <chrono> classes or Boost's <boost/date_time.hpp> for your conversions...

Generating a short string containing the time with strange results

I have a function which creates a std::string with the time in it in cpp as follows:
#include "msattime.h"
#include <QTime>
#include <stdio.h>
#include <iostream>
std::string msattime::getTime(){
QTime t = QTime::currentTime();
std::string s;
char hours[5];
char minutes[5];
int min = t.minute();
itoa(t.hour(), hours, 10);
itoa(min, minutes, 10);
if(min < 10){
minutes[1] = minutes[0];
minutes[0] = '0';
minutes[2] = '\0';
}
s.clear();
s = s.append(hours).append(":").append(minutes);
return s;
}
This works just fine is the time in the minutes field does not contain a zero in the tens position. I changed my system time to many different values and used cout to print the string that resulted from this function. This table shows the input on the left and the output on the right.
9:19 AM || 9:19
11:20 AM || 11:20
10:20 PM || 22:20
5:24 PM || 17:24
5:00 PM || 17:00[
7:03 PM || 19:03┐
11:04 PM || 23:04!! (This is supposed to be a single character double bang)
12:09 AM || 0:09┌
The values for the hour are all correct. At some point there will be an option for the user to change the display format to 12h but for now there are no errors in those results. The only error is in the minutes place where there is an extra character added after the string. I don't get any errors when I print the string to the terminal so that suggests that it is null terminated at some point.
I have a display routine for a low resolution black and white lcd display that will print a value with center alignment. If I print this string with that alignment it gets forced to left alignment. The center printing function calculates a starting position based off of string length and then begins printing from that position. Because this string is forced to left alignment when printing using this method there is reason to believe that it is very very long.
Does anyone have any ideas about why this might be happening to me or have a suggestion for another get time function that with the same or similar output?
Environment:
Window 7 Pro w/ SP1 64bit
QT Creator IDE
QT 5.1.1
MinGW 32bit compiler with C++11 compliance turned on
I'd use strftime to do the formatting. Code would be something like this:
std::string getTime(){
time_t now = time(NULL);
struct tm *t = localtime(&now);
char buffer[16];
strftime(buffer, sizeof(buffer), "%H:%M", t);
return std::string(buffer);
}
If you're using multiple threads, you may want switch to from localtime to localtime_r instead.
The QTime class provides toString. This should be enough:
return QTime::currentTime().toString("h:mm").toStdString();
I also would recommend to use QString until you really need std::string.

Getting a unix timestamp as a string in C++

I'm using the function time() in order to get a timestamp in C++, but, after doing so, I need to convert it to a string. I can't use ctime, as I need the timestamp itself (in its 10 character format). Trouble is, I have no idea what form a time_t variable takes, so I don't know what I'm converting it from. cout handles it, so it must be a string of some description, but I have no idea what.
If anyone could help me with this it'd be much appreciated, I'm completely stumped.
Alternately, can you provide the output of ctime to a MySQL datetime field and have it interpreted correctly? I'd still appreciate an answer to the first part of my question for understanding's sake, but this would solve my problem.
time_t is some kind of integer. If cout handles it in the way you want, you can use a std::stringstream to convert it to a string:
std::string timestr(time_t t) {
std::stringstream strm;
strm << t;
return strm.str();
}
I had the same problem. I solved it as follows:
char arcString [32];
std::string strTmp;
// add start-date/start-time
if (strftime (&(arcString [0]), 20, "%Y-%m-%d_%H-%M-%S", (const tm*) (gmtime ((const time_t*) &(sMeasDocName.sStartTime)))) != 0)
{
strTmp = (char*) &(arcString [0]);
}
else
{
strTmp = "1970-01-01_00:00:00";
}
Try sprintf(string_variable, "%d", time) or std::string(itoa(time))?
http://www.codeguru.com/forum/showthread.php?t=231056
In the end time_t is just an integer.