在文件中插入文本只起一次作用 我的目标是: 我试图在C++中编写一个应用程序,用户可以在某个日期范围内请求某个天气参数,这个程序将从因特网上找到信息并将其写入文本文件。因此,用户可以要求在2009年8月2日至2009年8月10日期间每天进行类似高温的活动。然后,应用程序将弹出一个如下所示的文本文件: Month, Date, Year, High 8 2 2009 80.3 8 3 2009 76.9 ... 8 10 2009 68.4 1 1 2000 1 2 2000 1 2 2000 1 2 2000 1 2 2000 1 2 2000 1 4 2000
我已经获得了网页,将HTML解析成有意义的值,并将这些值写入数据库(txt文件)中。我还写了一个函数在文件中插入文本只起一次作用 我的目标是: 我试图在C++中编写一个应用程序,用户可以在某个日期范围内请求某个天气参数,这个程序将从因特网上找到信息并将其写入文本文件。因此,用户可以要求在2009年8月2日至2009年8月10日期间每天进行类似高温的活动。然后,应用程序将弹出一个如下所示的文本文件: Month, Date, Year, High 8 2 2009 80.3 8 3 2009 76.9 ... 8 10 2009 68.4 1 1 2000 1 2 2000 1 2 2000 1 2 2000 1 2 2000 1 2 2000 1 4 2000,c++,database,bash,file-io,ifstream,C++,Database,Bash,File Io,Ifstream,我已经获得了网页,将HTML解析成有意义的值,并将这些值写入数据库(txt文件)中。我还写了一个函数 insert(std::iostream& database, Day day); //Day is a class I defined that contains all the weather information 这将找到这一天应该呆在哪里,并将其插入中间。我已经测试了这个函数,它的工作原理和它应该的完全一样 我的问题是: 我现在正试图编写一个函数来实现以下功能: void u
insert(std::iostream& database, Day day); //Day is a class I defined that contains all the weather information
这将找到这一天应该呆在哪里,并将其插入中间。我已经测试了这个函数,它的工作原理和它应该的完全一样
我的问题是:
我现在正试图编写一个函数来实现以下功能:
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();
}
}
但不幸的是,insert()函数只有在每个程序调用一次时才能正常工作。如果我连续两次(或三次、四次或五次)尝试调用insert(),则只有最后一天才会显示在文本文件中
这里是尽可能少的代码量,它再现了我的问题,但仍然运行
#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;
}
这是在按下enter键/移动到cin之前的数据库。get()
这是我经过cin.get()并退出程序后的数据库:
1 1 2000
1 3 2000
1 4 2000
在运行程序之前,我已经更改了插入的日期、插入的日期数、两个日期之间的距离以及数据库的初始大小,但我总是得到相同的结果。在每次调用insert()之后,数据库的行为就好像这是唯一一次调用insert一样。但是,如果我多次运行该程序,文本文件将继续增长。只有在每次编译/运行时多次调用insert时,我才会遇到此问题。如果我运行这个程序5次:
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;
}
我怀疑这可能是fstream.clear()、fstream.seekg()和fstream.eof()的问题,也可能是关于关闭/重新打开文件的问题。但我所做的一切都没有起到任何作用
另外,值得注意的是,这不会在windows计算机上运行。在linux上应该可以,但我只在Mac上测试过,所以我可能错了。它使用bash创建/删除/重命名/移动文件
我们非常感谢您的任何帮助(即使只是朝着正确的方向轻推)。我已经为这件事紧张了一段时间了。另外,我知道有很多人不喜欢代码转储,所以我已经大大简化了这个问题。我的完整程序是700多行和10个不同的文件,这是我在理解这个想法的同时所能做到的最短的部分。这里的问题与处理文件的方式有关:当你
mv
一个文件时,旧文件本身不会被覆盖;相反,它被取消链接(“删除”),并在原地创建一个新文件
在类似Unix的操作系统上,您仍然可以保留未链接文件的句柄:使用路径无法访问该文件。这就是为什么在Unix上删除仍处于打开状态的文件是完全可以的,这与在Windows上不同:。这意味着数据库
根本没有改变:它仍然指向您的旧文件,并且包含相同的内容
一个简单的解决方法是关闭并重新打开文件。(从实际的角度来看,最好只使用一个现成的解决方案,例如。)噢,所以内存中的fstream对象没有改变,但我的目录中的文件被删除了?它仍然指向同一个旧文件。该文件仍然存在于硬盘上,尽管已被“删除”(即不再使用路径访问)。只有当文件的所有文件句柄都关闭时,文件才会真正被删除。好的。有没有更有效的方法?如果我需要更新30多个日期,如果它必须下载一个文件,解析它,将数据插入数据库,发送bash命令,然后关闭并重新打开该文件,似乎需要一段时间。好的,你可以缓存它并批量执行,而不是一次一个日期,但下载的开销可能比重新打开文件要大得多。(或者使用库来实现这一点:编写可靠、快速的数据库绝非易事。更不用说,插入算法的成本是线性的,因此插入日期的成本将是二次的,这并不理想。)
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;
}
1 1 2000
1 2 2000
1 2 2000
1 2 2000
1 2 2000
1 2 2000
1 4 2000