Как прочитать дату из файла в c - PullRequest
3 голосов
/ 15 марта 2019

Я читаю из файла в программе с использованием C. В файле у меня есть несколько дат, каждая из которых находится в отдельной строке, в точности так:

20190101
20190304
20180922

Теперь я хочу, чтобы программа считала их как датыи найдите разницу между текущей датой и этими датами.Можно ли преобразовать эти даты в формат, который читается на C?что-то вроде этого: 2019.01.01 В настоящее время я читаю его, используя fgets, и не могу преобразовать его в формат выше.Это мой код:

#include <stdio.h>
#include <stdlib.h>
void FileRead(FILE *pr)
{
    char date [15];
    fgets(date,15,pr);
    printf("date : %s", date);

}
int main()
{
   char x;
   FILE *pr;
   pr=fopen("mytextfile.txt","r");
   if(pr==NULL)
   {
       printf("File can not be opened.");
       return 0;
   }
  while(scanf("%c", &x))
    {
        switch(x)
        {

        case 'v' :
            FileRead(pr);
        break;

        case 'k' :
            return 0;

        }
    }
fclose(pr);
    return 0;
}

Ответы [ 3 ]

1 голос
/ 15 марта 2019

Если у вас есть char* через fgets, используйте atoi для преобразования в целое число.Тогда у вас есть дата в формате ГГГГММДД.Затем вы можете сделать

const int day = dateYYYYMMDD % 100;
const int month = (dateYYYYMMDD % 10000)/100;
const int year = dateYYYYMMDD / 10000;

Вы можете использовать C Функции даты и времени для получения текущей даты.

Чтобы получить разницу между текущей датой и этими датами, один вариантпреобразовать все даты в юлианскую дату , а затем сделать числовую разницу в юлианских датах.

Если получить юлианскую дату сложно, нормализуйте к тому же году (добавление 365 или 366 на основе годаскачок или нет, когда вы переходите от низшего к высшему году).Затем доберитесь до того же месяца и затем сделайте разницу в днях.

0 голосов
/ 15 марта 2019

Самый простой способ приблизиться к разнице отныне - прочитать даты из файла и разобрать их по месяцам, дням и годам (m, d, y).Если вы не собираетесь проводить полную проверку каждой конверсии, то простой способ разделения четырехзначного года и двухзначного месяца и дня заключается в использовании fscanf с соответствующим ширина поля модификаторы для ограничения преобразования до необходимого количества цифр, например

    while (fscanf (fp, "%4d%2d%2d", &y, &m, &d) == 3) {

Тогда все, что нужно в цикле, это заполнить struct tm значениями года, месяца и дня (не забывая вычесть 1900 от года, и установите каждый из часовых, минутных и вторых элементов равным нулю, а элемент летнего времени равен -1).Простая функция может сделать это и вернуть time_t после вызова mktime, например

time_t fill_broken_down_time (int y, int m, int d)
{                   /* initialize struct members */
    struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d, 
                    .tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };

    return mktime(&bdt);    /* return mktime conversion to time_t */
}

Чтобы закончить, все, что вам нужно, это получить значения time_t и вызвать difftime, чтобы получить разницув секундах между текущим временем и временем, считанным из файла как значение double.Продолжая цикл в main(), например,

    while (fscanf (fp, "%4d%2d%2d", &y, &m, &d) == 3) {
        time_t  now = time(NULL),
                then = fill_broken_down_time (y, m, d);
        printf ("date[%d] %d/%d/%d is %.2f seconds from now.\n", 
                n++, m, d, y, difftime (now, then));
    }

В целом, вы можете сделать что-то вроде:

#include <stdio.h>
#include <time.h>

time_t fill_broken_down_time (int y, int m, int d)
{                   /* initialize struct members */
    struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d, 
                    .tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };

    return mktime(&bdt);    /* return mktime conversion to time_t */
}

int main (int argc, char **argv) {
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    int y, m, d, n = 1;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fscanf (fp, "%4d%2d%2d", &y, &m, &d) == 3) {
        time_t  now = time(NULL),
                then = fill_broken_down_time (y, m, d);
        printf ("date[%d] %d/%d/%d is %.2f seconds from now.\n", 
                n++, m, d, y, difftime (now, then));
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    return 0;
}

( note: программа ожидаетимя файла для чтения дат в качестве первого аргумента программы (или программа будет читать из stdin по умолчанию, если аргумент не указан))

Пример входного файла

$ cat dat/3dates.txt
20190101
20190304
20180922

Пример использования / Вывод

$ ./bin/time_from_now dat/3dates.txt
date[1] 1/1/2019 is 6300212.00 seconds from now.
date[2] 3/4/2019 is 943412.00 seconds from now.
date[3] 9/22/2018 is 15030212.00 seconds from now.

Редактировать для комментария Изменение формата входного файла

Если ваш файл данных действительноотличается от трех строк дат, которые вы изначально разместили в своем вопросе, и содержит строки заголовков перед информацией о дате, поэтому вам нужно будет прочитать, идентифицировать и обработать эти строки перед обработкой строки даты.Поскольку вы хотите выводить в днях, а не в секундах, вы просто делите количество секунд на 86400, чтобы получить разницу во времени в днях.

Чтобы прочитать строки заголовка дескриптора, просто настройте чтение на чтениеВся строка за раз в буфер соответствующего размера.Объявленная константа достаточного размера, чтобы гарантировать, что ваш буфер будет достаточно большим, например,

#define MAXC 1024u  /* if you need a constant, #define one (or more) */
...
int main (int argc, char **argv) {
...
    char buf[MAXC];     /* buffer to hold each line read from file */

Тогда вы просто будете использовать sscanf вместо fscanf, чтобы выполнить точно такой же анализ информации из каждой строки.Если формат строки не удовлетворяет формату yyyymmdd, вы знаете, что это не строка даты - обрабатывайте эти строки любым удобным способом (они просто выводятся в приведенном ниже примере с префиксом "non-date line: ".

В сочетании с делением количества секунд с момента времени в файле на 86400 секунд в день ваш новый цикл чтения будет выглядеть следующим образом:

    while (fgets (buf, MAXC, fp)) {     /* read each line in file */
        /* if line isn't a date line, just output line as non-date line */
        if (sscanf (buf, "%4d%2d%2d", &y, &m, &d) != 3) {
            printf ("non-date line: %s", buf);
            continue;
        }
        time_t  now = time(NULL),
                then = fill_broken_down_time (y, m, d);
        double secs = difftime (now, then); /* get seconds between dates */
        printf ("date[%d] %02d/%02d/%04d is %11.2f sec (%g days) from now.\n", 
                n++, m, d, y, secs, secs / 86400.0);
    }

Вы говорите:

"I am not able to open the file"

Программа ожидает, что вы предоставите имя файла для чтения в качестве первого аргумента программы, в противном случае программа будет читать из stdin по умолчанию. Это означает, что вы должны указать имя файла для программы,например,

./yourprogram your_date_file

, или вы должны предоставить эти данные в stdin, либо передав эту информацию в программу из вывода какой-либо другой программы, либо просто перенаправив файл в качестве ввода в stdin, например

some_utility_making_dates | ./yourprogram

или

./yourprogram < your_date_file

С учетом всех изменений ваша программа будет выглядеть следующим образом:

#include <stdio.h>
#include <time.h>

#define MAXC 1024u  /* if you need a constant, #define one (or more) */

time_t fill_broken_down_time (int y, int m, int d)
{                   /* initialize struct members */
    struct tm bdt = { .tm_sec=0, .tm_min=0, .tm_hour=0, .tm_mday=d, 
                    .tm_mon=m>0?m-1:0, .tm_year=y-1900, .tm_isdst=-1 };

    return mktime(&bdt);    /* return mktime conversion to time_t */
}

int main (int argc, char **argv) {
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    int y, m, d, n = 1;
    char buf[MAXC];     /* buffer to hold each line read from file */

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {     /* read each line in file */
        /* if line isn't a date line, just output line as non-date line */
        if (sscanf (buf, "%4d%2d%2d", &y, &m, &d) != 3) {
            printf ("non-date line: %s", buf);
            continue;
        }
        time_t  now = time(NULL),
                then = fill_broken_down_time (y, m, d);
        double secs = difftime (now, then); /* get seconds between dates */
        printf ("date[%d] %02d/%02d/%04d is %11.2f sec (%g days) from now.\n", 
                n++, m, d, y, secs, secs / 86400.0);
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    return 0;
}

Пример входного файла с заголовками

$ cat dat/3dates-w-headers.txt
This file contains dates to read and convert to days.
The file also contains this description and dates in the format:

yyyymmdd
20190101
20190304
20180922

Пример использования / вывода

$ ./bin/time_from_now2 dat/3dates-w-headers.txt
non-date line: This file contains dates to read and convert to days.
non-date line: The file also contains this description and dates in the format:
non-date line:
non-date line: yyyymmdd
date[1] 01/01/2019 is  6348645.00 sec (73.4797 days) from now.
date[2] 03/04/2019 is   991845.00 sec (11.4797 days) from now.
date[3] 09/22/2018 is 15078645.00 sec (174.521 days) from now.

Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 15 марта 2019

Вывод: вы просто зацикливаете строки файла и устанавливаете в нем условие if

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

int main(void)
{
    char buff[20];
    time_t now = time(NULL);

    strftime(buff, 20, "%Y%m%d\n", localtime(&now));
    printf("Today : %s \n\n", buff);

    static const char filename[] = "file.txt";
    FILE *file = fopen(filename, "r");

    if (file != NULL)
    {
        char line[128]; /* or other suitable maximum line size */
        while (fgets(line, sizeof line, file) != NULL) /* read a line */
        {
            fputs(line, stdout); /* write the line */

            if (strcmp(line, buff) == 0)
                printf("\nThis line of date equal to current date\n");

        }
        fclose(file);
    }
    else
    {
        perror(filename); /* why didn't the file open? */
    }
    return 0;
}

file.txt

20190315
20190304
20180922
...