如何从C中的文件读取日期 [英] How to read a date from file in c

查看:63
本文介绍了如何从C中的文件读取日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用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;
文件* pr;
pr = fopen( mytextfile.txt, r);
if(pr == NULL)
{
printf(文件无法打开。);
返回0;
}
while(scanf(%c,& x))
{
开关(x)
{

'v':
FileRead(pr);
休息时间;

情况为 k:
返回0;

}
}
fclose(pr);
返回0;
}


解决方案

最简单的方法从现在到现在的区别是从文件中读取日期并将其解析为月,日和年( m,d,y )。如果您不打算对每个转换进行完整的验证,那么将4位数字年份和2位数字月份和日期分开的简单方法是将 fscanf 与适当的 field-width 修饰符可将转换限制为所需的位数,例如

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

然后,循环内所需的就是用年,月和日的值填充 struct tm (记住要减去<一年中的code> 1900 ,并将小时,分钟和秒成员中的每个成员设置为零,并将夏令时成员设置为 -1 )。一个简单的函数可以做到这一点,并在调用 mktime 之后返回 time_t ,例如

  time_t fill_broken_down_time(int y,int m,int d)
{/ *初始化struct成员* /
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); / *将mktime转换返回到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是从现在开始%.2f秒。\n,
n ++,m,d,y,difftime(现在,然后));
}

将其放在一起,您可以执行以下操作:

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

time_t fill_broken_down_time(int y,int m,int d)
{/ *初始化结构成员* /
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); / *将mktime转换返回到time_t * /
}

int main(int argc,char ** argv){
/ *使用作为第一个参数提供的文件名(默认为stdin )* /
文件* fp = argc> 1个fopen(argv [1], r):stdin;
int y,m,d,n = 1;

if(!fp){/ *验证文件打开以读取* /
错误(文件打开失败);
返回1;
}

而(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是从现在开始%.2f秒。\n,
n ++,m,d,y,difftime(现在,然后));
}
if(fp!= stdin)fclose(fp); / *如果不是标准输入,则关闭文件* /

返回0;
}

注意:,程序希望文件名读取日期,作为程序的第一个参数(或者,如果没有给出参数,则默认情况下程序将从 stdin 读取))



示例输入文件

  $ cat dat / 3dates.txt 
20190101
20190304
20180922

示例用法/输出

  $ ./bin/time_from_now dat / 3dates.txt 
日期[1] 1/1/2019是6300212.00秒从现在开始。
date [2] 3/4/2019现在是943412.00秒。
date [3] 9/22/2018是现在的15030212.00秒。

编辑每条注释修改输入文件格式



如果您的数据文件实际上不同于您最初在问题中发布的三行日期,并且它在日期信息之前包含标题行,那么您将需要阅读,识别和处理那些日期行之前的行。由于您希望以天而不是秒为单位输出,因此只需将秒数除以 86400 即可获得以天为单位的时差。



要读取句柄标题行,只需调整读数即可一次将整行读入足够大小的缓冲区中。声明一个足够大的常量以确保缓冲区足够大,例如

  #define MAXC 1024u / *(如果需要)常数,#定义一个(或多个)* / 
...
int main(int argc,char ** argv){
...
char buf [MAXC] ; / *缓冲区来保存从文件中读取的每一行* /

然后,您只需使用 sscanf 而不是 fscanf 对每一行进行完全相同的信息解析。如果行格式不符合 yyyymmdd 格式,则说明它不是日期行-可以任意方式处理这些行(它们仅在下面的示例中以前缀非日期行:



结合除以自文件中时间以来的秒数每天 86400 秒,您的新读取循环将类似于:

  while(fgets(buf,MAXC,fp)){/ *读取文件中的每一行* / 
/ *如果该行不是日期行,则仅将其输出为非日期行* /
if(sscanf(buf,%4d%2d%2d,& y,& m,& d)!= 3){
printf(非日期行:%s ,buf);
继续;
}
time_t现在= time(NULL),
然后= fill_broken_down_time(y,m,d);
double secs = difftime (现在,然后); / *获取日期之间的秒数* /
printf( date [%d]%02d /%02d /%04d是%11.2f秒(%g天),从now.\n,
n ++,m,d,y,secs,secs / 86400.0);
}

您说:



< blockquote>

 我无法打开文件 


程序希望您提供文件名作为程序的第一个参数读取,否则程序将从 stdin 默认情况下。这意味着您必须向程序提供文件名,例如

 。/您的程序your_date_file 

,或者您必须通过将该信息通过管道传输到程序来提供 stdin 上的数据从其他程序的输出,或者只是将文件重定向为 stdin 上的输入,例如

  some_utility_making_dates | ./您的程序

 。/您的程序< your_date_file 

结合所有更改,您的程序将如下所示:

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

#define MAXC 1024u / *如果需要常量,#define一个(或多个)* /

time_t fill_broken_down_time(int y,int m,int d)
{/ *初始化结构成员* /
结构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); / *将mktime转换返回到time_t * /
}

int main(int argc,char ** argv){
/ *使用作为第一个参数提供的文件名(默认为stdin )* /
文件* fp = argc> 1个fopen(argv [1], r):stdin;
int y,m,d,n = 1;
char buf [MAXC]; / *缓冲区,用于保存从文件读取的每一行* /

if(!fp){/ *验证文件已打开以进行读取* /
错误(文件打开失败);
返回1;
}

而(fgets(buf,MAXC,fp)){/ *读取文件中的每一行* /
/ *如果该行不是日期行,输出行作为非日期行* /
if(sscanf(buf,%4d%2d%2d,& y,& m,& d)!= 3){
printf (非日期行:%s,buf);
继续;
}
time_t now = time(NULL),
then = fill_broken_down_time(y,m,d);
double secs = difftime(现在,然后); / *获取日期之间的秒数* /
printf( date [%d]%02d /%02d /%04d是从现在开始的%11.2f sec(%g天)。\n,
n ++,m,d,y,秒,秒/ 86400.0);
}
if(fp!= stdin)fclose(fp); / *如果不是标准输入,则关闭文件* /

返回0;
}

带有标题的示例输入文件

  $ cat dat / 3dates-w-headers.txt 
此文件包含要读取并转换为日期的日期。
该文件还包含以下描述和日期,格式为:

yyyymmdd
20190101
20190304
20180922

示例使用/输出

  $ ./bin/time_from_now2 dat / 3dates-w-headers.txt 
非日期行:此文件包含要读取并转换为日期的日期。
非日期行:该文件还包含以下说明和日期,格式为:
非日期行:
非日期行:yyyymmdd
date [1] 01 /从现在开始01/2019是6348645.00秒(73.4797天)。
date [2] 03/04/2019是从现在开始的991845.00秒(11.4797天)。
date [3] 09/22/2018是现在的15078645.00秒(174.521天)。

仔细检查一下,如果您还有其他疑问,请告诉我。


I am reading from a file in a program using C. in the file I have some dates each in a separate line exactly like this:

20190101
20190304
20180922

Now I want the program to read these as dates and find the difference between the current date and these dates. is it possible to convert these dates into a format which is readable by C? something like this: 2019.01.01 Currently, I read it using fgets and I am not able to convert it to the format above. This is my code:

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

解决方案

The easiest way to approach the difference from now to then is to read the dates from the file and parse them into month, day and year (m, d, y). If you are not going to do a complete validation of each conversion, then a simple way to separate the 4-digit year and 2-digit month and day is to use fscanf with the appropriate field-width modifiers to limit the conversion to the required number of digits, e.g.

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

Then all that is needed within the loop is to populate the struct tm with the year, month and day values (remembering to subtract 1900 from the year, and set each of the hour, minute and second members zero and the daylight savings time member to -1). A simple function can do this and return time_t after calling mktime, e.g.

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 */
}

To finish, all you need is to get the time_t values and call difftime to get the difference in seconds between the current time and time read from the file as a double value. Continuing the loop in main(), e.g.

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

Putting it altogether, you could do something like:

#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: the program expects the filename to read dates from as the first argument to the program (or the program will read from stdin by default if no argument is given))

Example Input File

$ cat dat/3dates.txt
20190101
20190304
20180922

Example Use/Output

$ ./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.

Edit Per-Comment Modifying Input File Format

If your data file is actually different than the three-lines of dates you originally posted with your question and it contains heading rows before the date information, then you will need to read, identify and handle those lines before handle the date line. Since you want output in days as opposed to seconds, you simply divide the number of seconds by 86400 to obtain the time difference in days.

To read an handle heading lines, simply adjust your read to read an entire line at a time into an adequately sized buffer. Declared a constant of sufficient size to ensure your buffer will be large enough, e.g.

#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 */

Then you will simply use sscanf instead of fscanf to do the exact same parse of information from each line. If the line format does not satisfy the yyyymmdd format, you know it's not a date line - handle those lines any way you want (they are just output in the example below with the prefix "non-date line: ".

Combined with dividing the number of seconds since the time in the file with 86400 seconds per-day, your new read loop would be similar to:

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

You say:

"I am not able to open the file"

The program expects you to provide the filename to read as the first argument to the program, otherwise the program will read from stdin by default. The means you have to provide the filename to the program, e.g.

./yourprogram your_date_file

or you have to provide that data on stdin by either piping that information to the program from the output of some other program, or simply redirecting the file as input on stdin, e.g.

some_utility_making_dates | ./yourprogram

or

./yourprogram < your_date_file

Incorporating all the changes, your program would look like:

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

Example Input File w/Headings

$ 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

Example Use/Output

$ ./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.

Look things over and let me know if you have further questions.

这篇关于如何从C中的文件读取日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆