平台: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)
对以下两个不同文件内容:
文件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()函数,强制进入内核将内容输出到文件中。[2014.8.8 -- 14.40 - 15.47]
CBNote Over.