Linux下解析.csv⽂件实例(结构体存储字符串,中⽂乱码
ANSI编码问题解决)
⼀、问题描述
NAME;CLASE;GRADE
⼩惠 ;04;91
⼩明 ;01;55
科科 ;03;86
⽼罗 ;01;77
⽼⼤哥 ;01;96
⽼郭 ;07;86
娇娇 ;01;75
振宇 ;05;79
阿来 ;04;88
CICI ;03;99
假设有这么⼀个.csv⽂件,有三个字段(NAME,CLASE,GRADE),且数据间通过分号“;”分隔。现在要取⽤其中的数据,⽤C语⾔,在Linux下。
⼆、分析下
⾸先,这个.csv⽂件中有中⽂,可能涉及到编码转换的问题,可以使⽤notepad++查看⼀下格式,或者在Linux下执⾏file -i查看。由于Linux下⼀般是以UTF-8为默认编码的,所以如果⽂件是iso-8859-1(ANSI),在Linux中处理时就要考虑转码。
其次,⽤什么结构存储这个数据,⼀般最可能想到的是⼆维数组,但是这⾥有字符串(NAME、CLASE)数据,所以除⾮把GRADE也转变为字符串数据,才能定义⼀个存储字符串的⼆维数组,⼆维数组还要存储字符串,那不就是需要使⽤三维指针进⾏操作了么?不是不⾏,但是有点⿇烦。所以,考虑结构体是⽐较好的选择。⽤结构体指针,指向⼀个结构体数组,结构体数组中,每⼀个结构体存储⼀个记录(⼀⾏)。
typedef struct list_log
{
char NAME[15]; /*实际测试数据,得到40个左右字节(含有⽆效空格,为节省内存,不存储)*/
char CLASE[3]; /*实际测试数据,得到2字节*/
char GRADE[3]; /*实际测试数据,得到2字节*/
} stru_list_record;
然后,考虑.csv⽂件的字段标题(NAME;CLASE;GRADE)没有什么⽤,为了处理⽅便,可以直接除去。
最后,考虑下基本的功能函数应该主要包括:获取.csv数据的⾏数、列数,解析数据,打印数据。当然,严谨⼀点,在⼀开始可以增加⼀个.csv⽂件的正确性检查、字符编码转换、备份⽂件等预备⼯作的检查函数。
三、代码
代码如下:
/*************************************************************************
> File Name: csv_prase_V1.0.c
> Author: hank
> Mail: 34392195@qq
> 使⽤:
> 可执⾏⽂件 csv⽂件
> eg:./main textfile.csv
> 说明:
> 1.为保护原.csv⽂件,程序会复制原.csv⽂件,⽣成临时⼯作⽂件:"temp_file.csv".程序结束后,⾃动删除. > 2.根据记录个数,动态分配结构体数组存储记录,并使⽤结构体指针p_list_rec指向数组的⾸地址
> 3.结构体数组中,姓名(NAME)不存储后边的⽆效空格符.
> Created Time: 2020年07⽉31⽇星期五 05时16分11秒
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
/*该处宏定义需要⼈⼯对⽂件核实确定!!*/
/*.csv⽂件是否需要转换编码(ANSI转换为UTF-8)*/
#define _FILETRAN_ANSI2UTF_
/*⽂件是否含有字段名*/
#define _HAVE_FIELD_HEADING_
/*读取⼀⾏长度上限*/
#define LINE_LENGTH 128
typedef struct list_log
{
char NAME[20]; /*实际测试数据,得到101个字节(含有⽆效空格,为节省内存,不存储空格)*/
char CLASE[3]; /*实际测试数据,得到2字节*/
char GRADE[3]; /*实际测试数据,得到2字节*/
} stru_list_record;
/*获取⾏数*/
int get_row(char *filename);
/*获取列数*/
int get_col(char *filename);
/*解析*/
int get_record(char *line, char *filename, stru_list_record *p_list_rec);
/*打印*/
void print_record(const stru_list_record const *p_list_rec, const int row, const int col);
/*.csv⽂件可读性检查, 转换字符编码, 备份⽂件*/
void *check_file(char *filename, const char *p_backup_filename);
int main(int argc, char* argv[])
{
/*程序参数检查*/
if(2 != argc)
{
printf("-->argument input error!\n");
printf("-->Usage:./main [file path/]filename\n");
exit(-1);
}
/*.csv⽂件可读检查, 转换字符编码, 备份⽂件*/
char *filename = argv[1];
char backup_filename[] = "temp_file.csv";
filename = (char *)check_file(filename, backup_filename);
/*获取记录的⾏列数*/
/*获取记录的⾏列数*/
#ifdef _HAVE_FIELD_HEADING_
int row = get_row(filename) - 1; /*不计算第⼀⾏字段标题*/
#else
int row = get_row(filename);
#endif
int col = get_col(filename);
/
/ printf("row = %d\tcol = %d\n", row, col); /*---debug printf for check---*/
/*动态申请row个结构体 --> p_list_rec[i]访问第i个记录*/
stru_list_record *p_list_rec = NULL;
p_list_rec = (stru_list_record *)malloc(sizeof(stru_list_record) * row);
if(NULL == p_list_rec)
{
printf("[%s:%s] line:%d\n", __FILE__, __func__, __LINE__);
perror("malloc() error");
return -1;
}
memset(p_list_rec, 0, sizeof(stru_list_record) * row);
/
*获取数据*/
char line[LINE_LENGTH];
int ret = get_record(line, filename, p_list_rec);
/*-------------do something with data by "p_list_rec"----------------*/
/*打印数据*/
print_record(p_list_rec, row, col);
/*----------------------------end---------------------------------------*/
/*清理*/
free(p_list_rec);
p_list_rec = NULL;
system("rm temp_file.csv");
return 0;
}
/*.csv⽂件可读性检查, 转换字符编码, 备份⽂件*/
void *check_file(char *filename, const char *p_backup_filename)
{
FILE *stream;
if(NULL == (stream = fopen(filename, "rt")))
{
printf("[%s:%s] line:%d\n", __FILE__, __func__, __LINE__);
perror("fopen error");
exit(-1);
}
else //转换格式:GB2312->UTF-8, 跟新⽂件
{
char sys_str[100];
#ifdef _FILETRAN_ANSI2UTF_
sprintf(sys_str,"%s %s %s %s", "iconv -f GB2312 -t UTF-8", filename, "-o", p_backup_filename); #else
sprintf(sys_str,"%s %s %s", "cp", filename, p_backup_filename);
#endif
puts(sys_str);
system(sys_str);
//filename = p_backup_filename;
}
return (void *)p_backup_filename;
}
/*获取⾏数*/
int get_row(char *filename)
{
char line[LINE_LENGTH];
int row = 0;
FILE *stream;
if(NULL == (stream = fopen(filename, "rt")))
{
printf("[%s:%s] line:%d\n", __FILE__, __func__, __LINE__);
perror("fopen error");
exit(-1);
}
while(fgets(line, LINE_LENGTH, stream))
{
row++;
}
fclose(stream);
return row;
}
/
*获取列数*/
int get_col(char *filename)
{
char line[LINE_LENGTH];
int col = 0;
FILE *stream; /*rt*/
if(NULL == (stream = fopen(filename, "rt")))
{
printf("[%s:%s] line:%d\n", __FILE__, __func__, __LINE__);
perror("fopen error");
exit(-1);
record是什么意思中文}
fgets(line, LINE_LENGTH, stream);/*读取⼀⾏*/
char *token = strtok(line, ";");
while(token)
{
// printf("%s(strlen:%ld) ", token, strlen(token)); /*---debug printf for check---*/ token = strtok(NULL, ";");
col++;
}
// printf("\n");
fclose(stream);
return col;
}
/*解析*/
int get_record(char *line, char *filename, stru_list_record *p_list_rec)
{
FILE *stream = fopen(filename, "rt");
int row_i = 0; //⾏变量-⾏数记录
int col_j = 0;
int strlen_NAME = 0; //获取NAME字符串的实际长度
char *token;
#ifdef _HAVE_FIELD_HEADING_
fgets(line, LINE_LENGTH, stream); //丢掉字段标题⾏
#endif
while (fgets(line, LINE_LENGTH, stream))//逐⾏读取
while (fgets(line, LINE_LENGTH, stream))//逐⾏读取
{
col_j = 0; //列变量
for (token = strtok(line, ";"); token && *token; col_j++, token = strtok(NULL, ";\r\n"))/*以;或者\r或者\n结尾*/ {
// printf("[%d,%d]:%s n!\n", row_i , col_j, token); /*---debug printf for check---*/
switch(col_j)
{
case 0:
strlen_NAME = 0;//车牌(NAME)不计⼊空格符
while(token[strlen_NAME++] != ' ');
strlen_NAME--;
strncpy(p_list_rec[row_i].NAME, token, strlen_NAME);
break;
case 1:
strncpy(p_list_rec[row_i].CLASE, token, strlen(token));
break;
case 2:
strncpy(p_list_rec[row_i].GRADE, token, strlen(token));
break;
default:
break;
}
}
// printf("\n"); /*---debug printf for check---*/
row_i++;
}
fclose(stream);
return 0;
}
/*打印*/
void print_record(const stru_list_record const *p_list_rec, const int row, const int col)
{
int row_i; //⾏变量
int col_j; //列变量
for(row_i = 0; row_i < row; row_i++)
{
for(col_j = 0; col_j < col; col_j++)
{
switch(col_j)
{
case 0:
printf("[%d,%d]:%s\t", row_i, col_j, p_list_rec[row_i].NAME);
break;
case 1:
printf("[%d,%d]:%s\t", row_i, col_j, p_list_rec[row_i].CLASE);
break;
case 2:
printf("[%d,%d]:%s\n", row_i, col_j, p_list_rec[row_i].GRADE);
break;
default:
break;
}
}
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论