平台:x86/Debian Linux/gcc
1 题目
编程读写一个文件test.txt,每隔1s向文件中写入一行记录,类似于这样:
1 2009-7-30 15:16:42
2 2009-7-30 15:16:43
该程序应该是无限循环,直到按Ctrl + C终止。下次再启动程序时再test.txt文件末尾追加记录,并且序号能够持续上次的序号,比如:
1 2009-7-30 15:16:42
2 2009-7-30 15:16:43
3 2009-7-30 15:19:02
4 2009-7-30 15:19:03
5 2009-7-30 15:19:04
2 编程实现
(1) C代码
- /* Filename: out_date_and_time.c
- * Brife: Output date and time to time.txt one by one second
- * Date: 2014.8.7 Thursday
- * Author: One fish
- */
- #include <time.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
-
-
- //------------Maro------------------
- #define EPOCH_YEAR 1900
- #define EPOCH_MONTH 1
- #define EPOCH_DAY 1
- #define OUT_FILE "time.txt"
-
-
-
- //------------Function decalre-------
- void get_localtime(unsigned long int file_num);
- unsigned long int find_file_end(const char *file);
-
-
-
- //----------Golbal varibles----------
- FILE *fp = NULL;
-
-
-
-
- int main(void)
- {
- unsigned long int file_num = 0;
-
- file_num = find_file_end(OUT_FILE);
- printf("line number: %d\n", file_num);
-
- while( 1 ){
- get_localtime( file_num + 1 );
- sleep(1);
- }
- return 0;
- }
-
-
-
-
- /*@Brife: Open file and find file end line number
- *@Arg: file is the opened file
- *@Rel: Return the file number
- */
- unsigned long int find_file_end(const char *file)
- {
- char buf[30];
- int file_num = 0;
-
- fp = fopen(file, "a+");
- if(NULL != fp){
-
- //File is empty
- if( NULL == fgets(buf, 30, fp) )
- return 0;
-
- //Move fp to the start of the last line of the file
- fseek(fp, -strlen(buf), SEEK_END);
- fgets(buf, 30, fp);
-
- //Or line number bigger than long long int scope
- if(1 != sscanf(buf, "%d", &file_num) ){
- printf("*.txt format is not correct\n");
- return 0;
- }
-
- return file_num;
- }else{
- printf("Open %s failed\n", OUT_FILE);
- }
- }
-
-
-
- /*@Brife: Get current date and output to time.txt
- * Should be called after find_file_end()
- *@Arg: File_num, the line number should be printed
- */
- void get_localtime(unsigned long int file_num)
- {
-
- time_t *t = NULL;
- static unsigned long int num = 0;
- if(num <= file_num){
- num = file_num;
- }
-
- t = (time_t *)malloc(sizeof(time_t));
-
- if(NULL != t){
- struct tm *ptm = NULL;
-
- //Get the time as the number of seconds since the Epoch, 1970-01-01 00:00 + 0000(UTC)
- //Translate calendar time to broken-down time
- time(t);
- ptm = localtime(t);
-
- if(NULL != fp){
- fprintf(fp, "%d %d-%d-%d\t", num, EPOCH_YEAR + ptm->tm_year, EPOCH_MONTH + ptm->tm_mon, EPOCH_MONTH + ptm->tm_mday);
- fprintf(fp, "%d:%d:%d\n", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
- fflush(fp);
- ++num;
- }else{
- printf("%s Not found\n", OUT_FILE);
- }
- }
- free(t);
- }
(2) 运行结果
编译程序:gcc -o out_date_and_time out_date_and_time.c
第一次运行程序一小会后按Ctrl + C终止程序,隔一小会再运行程序。time.txt文件内容如下:
1 2014-8-9 14:40:41
2 2014-8-9 14:40:42
3 2014-8-9 14:40:43
4 2014-8-9 14:40:44
5 2014-8-9 14:40:48
6 2014-8-9 14:40:49
7 2014-8-9 14:40:50
3 man page + 验证
(1) fgets()
原型:char *fgets(char *s, int size, FILE *stream)
用户定义的缓冲区s的sizeof(s)要大于等于size,如果小于size则在fgets读到size-1字符给s后会继续添加一个’\0’字符。使缓冲区s的使用越界。
fgets读一个新建的文件返回NULL。fgets读一个用”backspace”退隔调所有内容的文件,输出fgets的返回值是一个换行。
(2) fseek()
原型:int fseek(FILE *stream, long offset, int whence)
对以下两个不同文件内容:
Figure1.文件1
Figure2.文件2
文件1只有1行数据(1 2014-8-9 15:15:55)并手动输入回车跳到文件1的第二行。文件2的每行内容是由fprintf输出的,行尾带回车。文件1和文件2每行数据长度相同为len,使fp指向文件1时,fseek(fp, -len, SEEK_END)时fp指向1后面的空格。fp指向文件2时,用fseek(fp, -len,SEEK_END)时fp指向第七行(黄色数字为行号)的数字7。
(3) time()和localtime()
用以上代码中time()和localtime()联用,由后者返回struct tm后,加上起始时间后tm_mday比实际时间多一天。
(4) fflush()
原型:fflush(FILE *stream)
因为fprintf属C标准库I/O库函数,stream指向的文件属常规文件(标准输入输出可能为行缓冲),其缓冲类型为全缓冲类型。故而在缓冲区满或程序正常结束前fprintf输出的内容全在缓冲区,在缓冲区未满时按Ctrl + C 后exit()函数没有得到运行,没有得到flush操作,故而stream指向的文件中无内容输出。所以要在每个fprintf函数后面添加ffush()函数,强制进入内核将内容输出到文件中。