在文件中插入文本只起一次作用 我的目标是: 我试图在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++中编写一个应用程序,用户可以在某个日期范围内请求某个天气参数,这个程序将从因特网上找到信息并将其写入文本文件。因此,用户可以要求在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

我已经获得了网页,将HTML解析成有意义的值,并将这些值写入数据库(txt文件)中。我还写了一个函数

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