C语言.csv编程应用

在有些产品的研发过程中,一般我们都有很多条数据记录在一个LOG文件中。

在查看最新的数据记录都是从最开始保存的那条开始存储,所以,参考了网上一些实现方法,稍微修改了一下即得到了下面的解决方法:

C语言.csv编程应用_第1张图片

C语言.csv编程应用_第2张图片

C语言.csv编程应用_第3张图片

 

假设文件存储如下内容:

2018/10/24 16:28 橙子 水果
2018/10/21 10:16 啤酒 饮料
2018/10/22 10:16 水杯 玻璃瓶
2018/10/23 09:19 硫酸 腐蚀品
2018/10/24 10:17 火药 爆炸物
2018/10/25 09:19 火柴 易燃物
2018/10/26 09:29 可乐 饮料
2018/10/27 10:39 雪碧 饮料
2018/10/28 09:49 益力多 饮料
2018/10/29 09:59 优益C 饮料

由于.csv格式的文件是如下的格式,所以我们知道它是以逗号作为分隔符的,一行的结束符就是\n

2018/10/24 16:28,橙子,水果
2018/10/21 10:16,啤酒,饮料
2018/10/22 10:16,水杯,玻璃瓶
2018/10/23 09:19,硫酸,腐蚀品
2018/10/24 10:17,火药,爆炸物
2018/10/25 09:19,火柴,易燃物
2018/10/26 09:29,可乐,饮料
2018/10/27 10:39,雪碧,饮料
2018/10/28 09:49,益力多,饮料
2018/10/29 09:59,优益C,饮料

运行结果:

C语言.csv编程应用_第4张图片

上面的这种情形可以说在数据量小的情况下可以这么来实现,但数据量一大我们就需要选择更适合的数据结构了,可以用链表来解决这样的问题:

typedef struct links
{
	int size  ; 
	void *ptr ; 
	struct links *next ;
	struct links *pre  ;
}LINKS;

    这是链表的数据结构,ptr就是要存放的数据,pre是前驱指针,next是后继指针,通过这两个指针,即可以方便实现链表的遍历。

    下面定义要实现的函数:

typedef  void (*print_t)(void *Data)  ; 
void print(void *Data);
//打印链表节点
void   print_links(LINKS *Header , print_t  func);
//创建链表头
LINKS  *Create_Links_Header(int size);
//头插
void  top_append(LINKS *Header , void *Data , int size);
//获取文件总行数
int GetTotalLineCount(FILE *file);

整体实现:

#include
#include
#include 
#define  NR(x)   (sizeof(x)/sizeof(x[0]+0))
 
typedef struct links
{
	int size  ; 
	void *ptr ; 
	struct links *next ;
	struct links *pre  ;
}LINKS;
 
typedef  void (*print_t)(void *Data)  ; 
void print(void *Data);
void   print_links(LINKS *Header , print_t  func);
LINKS  *Create_Links_Header(int size);
void  top_append(LINKS *Header , void *Data , int size);
int GetTotalLineCount(FILE *file);
 
 
int main(void)
{
	int line = 0 ;
	int file_all_line = 0 ;
	char line_buffer[50] = {0};
	LINKS *Header = NULL ;
	//1.初始化链表 
	Header =  Create_Links_Header(0);
	if(NULL == Header)
	{
		fprintf(stderr , "malloc  Header fail \n");
		return -1 ; 
	}
	//2.插入数据 
	FILE *fp = NULL ;
	fp = fopen("1.csv","r");
	if(NULL == fp)
	{
		printf("open csv file fail!\n");
		return -1 ;
	}
	//移到文件头 
	fseek(fp,0,SEEK_SET);
	//获取文件的总行数 
	file_all_line = GetTotalLineCount(fp);
	for(line = 0 ; line < file_all_line ; line++)
	{
		if(fgets(line_buffer,50,fp))	
		{
			printf("line_buffer:%s",line_buffer);
			top_append(Header , line_buffer , 100);
		}
	}
	print_links(Header,print);
	fclose(fp);
	free(Header);
	return 0 ;
}
 
void print(void *Data)
{
	printf("%s" ,Data);
	//这里可以进行数据处理...
	
	//这里可以进行数据处理...
}
//打印链表节点
void print_links(LINKS *Header , print_t func)
{
	LINKS *tmp = Header->next ; 
 
	while(tmp != Header)
	{
		func(tmp->ptr);
		tmp = tmp->next ;
        free(tmp->pre);
	}
}
//获取文件的总行数
int GetTotalLineCount(FILE *file)
{   
	int line_num = 0;
	char strLine[50];
	fseek(file,0,SEEK_SET);
	while (fgets(strLine, 50, file))
		line_num++;
	fseek(file,0,SEEK_SET);
	return line_num;
}
//创建表头
LINKS  *Create_Links_Header(int size)
{
	LINKS *New = NULL  ; 
	
	New = malloc(sizeof(LINKS));
	if(NULL == New)
	{
		fprintf(stderr , "malloc LINKS header fail \n");
		return NULL ; 
	}
 
	New->size = size ; 
	New->ptr = NULL ; 
	
	New->next = New ;
	New->pre  = New ; 
 
	return New ;
}
//链表头插
void  top_append(LINKS *Header , void *Data , int size)
{
	LINKS *New = NULL ; 
	
	New = malloc(sizeof(LINKS));
	if(NULL == New)
	{
		fprintf(stderr , "malloc links fail \n");
		return ;
	}
	
	New->ptr=NULL ;
	New->size = size ; 
 
	New->ptr = malloc(size);
	if(NULL == New->ptr)
	{
		fprintf(stderr , "malloc links data fail \n");
		return ; 
	}
	memcpy(New->ptr , Data , size);
	New->next = Header->next ; 
	New->pre  = Header ; 
	New->next->pre = New ;  
	New->pre->next = New ; 
}

运行结果:

如下图所示为excel文件的数据:

C语言.csv编程应用_第5张图片

运行程序得到:

C语言.csv编程应用_第6张图片

从这里看到,整个程序就是利用了栈的思想,先进后出,这样的实现既简单,也高效。我们再来看一个案例---C语言读取CSV文件任意一行并拆分该行获取数据:

void Display_Record_Data(int line) 

当line等于0时,表示读取CSV文件的第0行数据,等于100时,表示读取CSV文件的第100行数据,依次类推。

以下是我们要获取的数据,数据格式为:序号,时间,阈值,气雾,灵敏度

我们要做的事情就是,当传入为1时,则获取为当前CSV文件的第一行数据,并拆分出来。

源码实现:
 

#include 
#include 
#include 
#include 
 
#define SERIAL_NUMBER 0
#define DATE_TIME 1
#define DETECT_VALUE 2
#define SENSOR_STATU 3
#define SENSIVITY_STATU 4
 
struct Record_Page_Data
{
	 int serial_number ; 			
	 char date_time[20]  ;		
	 int detect_result ;			
	 int sensor_status ;			
	 int sensivity_status ;		
	
	 int year ; 
	 int month ; 
	 int day ;
	 int hour ; 
	 int minute ;
	 char _year[10]   ;
	 char _month[10]  ;
	 char _day[10]    ;
	 char _hour[10]   ;
	 char _minute[10] ;
};
struct Record_Page_Data csv_file_record ;
 
//根据逗号拆分字符串 
static int splitStr(char *str,char separator, char strs[][40]) 
{
    int i = 0,j = 0,n = 0;
    for(i = 0; str[i]; ++i) {
        if(str[i] == separator) {
            strs[n++][j] = 0;
            j = 0;
        }
        else strs[n][j++] = str[i];
    }
    strs[n++][j] = 0;
    return n;
}
 
//显示记录数据 
void Display_Record_Data(int line) 
{ 
     FILE *fp; 
     int para = 0 ;
     int item = 0 ;					
     int which_line = line;             //指定要读取哪一行
     if(which_line == 0 || which_line < 0)
     	return ;
     if(which_line > 0)
     	which_line-= 1 ; 
     int current_index=0;               //当前读取的行
     char strs[5][40] = {0};
     char strLine[50];                  //每行最大读取的字符数,可根据实际情况扩大
     
     if((fp = fopen("file.csv","r")) == NULL) //判断文件是否存在及可读
     { 
         printf("error!"); 
         return ; 
     } 
     while (!feof(fp)) 
     { 
        if(current_index == which_line)
        {
        	fgets(strLine,50,fp);  //读取一行
            printf("CSV文件原始数据:%s", strLine); //输出
            item = splitStr(strLine,',',strs);
			for(para = 0 ; para < item ; para++)
			{
				switch(para)
				{
					case SERIAL_NUMBER:
					 csv_file_record.serial_number 	  = atoi(strs[para]);
						break ;
					case DATE_TIME :
						memcpy(csv_file_record.date_time,strs[para],strlen(strs[para]));
						memcpy(csv_file_record._year,csv_file_record.date_time,4);
						memcpy(csv_file_record._month,csv_file_record.date_time+5,2);
						memcpy(csv_file_record._day,csv_file_record.date_time+8,2);
						memcpy(csv_file_record._hour,csv_file_record.date_time+11,2);
						memcpy(csv_file_record._minute,csv_file_record.date_time+14,2);
						csv_file_record.year   = atoi(csv_file_record._year);
						csv_file_record.month  = atoi(csv_file_record._month);
						csv_file_record.day    = atoi(csv_file_record._day);
						csv_file_record.hour   = atoi(csv_file_record._hour);
						csv_file_record.minute = atoi(csv_file_record._minute);
						break ;
					case DETECT_VALUE :
						csv_file_record.detect_result    = atoi(strs[para]);
						break ;
					case SENSOR_STATU :
						csv_file_record.sensor_status    = atoi(strs[para]);
						break ;
					case SENSIVITY_STATU:
						csv_file_record.sensivity_status = atoi(strs[para]);	
						break ;
				}
			 }    
			  
         }
         fgets(strLine,50,fp);  //读取一行,并定位到下一行
         current_index++;
     } 
     printf("序号:%d  时间:%d年%d月%d日 %d时%d分   阈值显示:%d   气雾状态:%d%%   灵敏度状态:%d\n",csv_file_record.serial_number,csv_file_record.year,csv_file_record.month, \
			 csv_file_record.day,csv_file_record.hour,csv_file_record.minute,csv_file_record.detect_result,csv_file_record.sensor_status,csv_file_record.sensivity_status);       
     fclose(fp);                     //关闭文件
     return ; 
}
 
 
 
int main(void)
{
	int i ; 
	for(i = 1 ; i < 8 ; i++)
		Display_Record_Data(i);
	return 0 ;	
}

运行结果:

C语言.csv编程应用_第7张图片

在单片机fatfs上,我们一样也可以实现这样的功能,根据不同的实现可以组合出多种多样的应用。

参考资料:

https://blog.csdn.net/moqj_123/article/details/45897877

你可能感兴趣的:(C语言-算法与数据结构编程,C语言在开发中的应用)