C语言处理CSV文件的方法
什么是CSV文件
CSV是 Comma-separated values
(逗号分隔值)的首字母缩写,它通常是以逗号且不仅限于逗号分隔各个值,我们都叫他CSV。看下面的例子:
China, Shanghai, Pudong,
Zhang San, 200000, 1234567
BMW; GER; 300000; RMB;
i530
从上面两个例子可以看出,可以用不同的分隔符来分隔数据;数据的类型可以不同;长度任意。
由多行这样的CSV组成的文件叫做CSV文件(逗号分隔值文件)。当然,他们必须用同样的分隔符,对应每一列的数据要有相同的含义,不然这个文件就是无意义的。CSV文件可以直接用Microsoft
Office中的Excel打开,这里不讨论Windows下的操作。
C语言编程处理CSV文件
通常CSV文件中包含大量有用信息,而且有时数据量庞大,一个数据文件会达到1G的大小,一般都是日志等重要信息。对CSV文件的处理也有很多方法,常见的就是用Bash,
Python, Perl
等脚本语言来处理。这里提供一种用C语言处理CSV文件的方法。以下过程都是在Linux环境下进行的,Windows用户请注意移植。
C语言标准库中有一个字符串(string.h)函数 strtok ,它的原型是
char *strtok( char *s,
const char *ct );
它以 ct 中的字符为分界符,将字符串 s 分成许多记号。第一次调用时,它搜索 s ,找到不包含ct的第一个记号,将 s
中的下一个字符替换为 ‘/0’ ,并返回指向记号的指针。随后调用 strtok 函数时(由 s 的值是否为NULL指示),返回下一个不包含 ct
中字符的记号。当 s 中没有这样的记号时,返回NULL 。每次调用时的 ct 可以不同。
注意红色标记的部分,这个函数的使用方法是(假设以逗号为分隔符):
char str[] = “Life is
like, a box of chocolate, you never, know what you’re, gonna
get”;
char delims[] = “,”;
char *result = NULL;
result = strtok( str, delims );
while( result != NULL ) {
printf( “%s /n”, result );
result = strtok( NULL, delims
);
}
OUTPUT:
life is like
a box of chocolate
you never
know what you’re
gonna get
这里只是单纯的把CSV分解成独立的可供后续处理的字符串,下面介绍一个复杂些的例子。
KDD CUP 99 DATASET
Preprocessing KDDCUP99数据集的预处理
关于KDD CUP 99数据集的介绍请看这里。
KDD CUP
99数据集是网络入侵检测(NIDS)的标准测试集,为IDS研究人员提供训练数据集和测试数据集,以期比较不同入侵检测方法的优劣。尽管该数据集是1998年建立的,但仍是现在研究最多的IDS数据集。
该数据集每一行就是由tcpdump采集并处理的一条记录,包含了41个特征值和1个攻击类型说明,每一个特征之间用逗号分隔,最后用逗号分隔攻击类型。训练集的一个1/10子集共有
494,021 条记录,是一个标准CSV文件。下面是其中3条记录:
0,icmp,ecr_i,SF,1032,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,511,511,0.00,0.00,/
0.00,0.00,1.00,0.00,0.00,255,255,1.00,0.00,1.00,0.00,0.00,0.00,0.00,0.00,smurf
0,tcp,http,SF,287,41018,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,15,32,0.00,0.00,/
0.07,0.03,1.00,0.00,0.16,61,255,1.00,0.00,0.02,0.01,0.00,0.00,0.02,0.00,normal
0,icmp,eco_i,SF,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0.00,0.00,0.00,/
0.00,1.00,0.00,0.00,3,15,1.00,0.00,1.00,0.27,0.00,0.00,0.00,0.00,ipsweep
由于数据的类型比较复杂,有离散类型(比如协议类型tcp,
upd…)和连续类型(持续时间,发送包数量等),要分开处理。预处理过程分两步:1. 映射。将符号型的数据(symbolic-valued attribute)映射到数值型数据(numeric-valued
attribute)。2. 归一化。将所有数据都调整到 [0.0 , 1.0]区间内。
由于strtok只能处理字符串类型数据,需要用 atoi , atol, atof
字符串转换函数来将字符串转换为数字,方便归一化处理。
….
while ( fgets( line,
length, fp ) != NULL ) { //read
a single line of dataset
result = strtok(line,
“,”); //read
the first attribute
for ( i = 0; i < 42; i++ )
{
switch (i) { //mapping and scaling the 41 attributs + 1 class respectively
case
0: //duration, continuous, [0, 58329]
printf(“%.2f,”, float(atoi(result))/DURATION);
break;
case
1: //protocal_type, symbolic, 3
printf(“%.2f,”, protocal_type(result));
break;
…
} //switch end
} //for end
result = strtok(NULL,
“,”); //continue reading next attribute
} //while end
每次读入一行数据文件,用strtok分隔出每个特征,再用switch判断是哪一个特征,然后对相应特征进行归一化处理。
总结
C语言对处理这种纯粹文本的数据不太擅长,虽然运行速度没的说,但编起来确实比较麻烦。建议还是用脚本语言配合正则表达式来做这种数据处理。
我程序中使用switch来判断特征值类型,由于一共有41个特征,所以比较麻烦,如果有简单的匹配方法,敬请E-mail我。
参考文献
1. http://www.elook.org/programming/c/strtok.html
2. The C Programming Language. 2nd Edition by
K&R
3. KDDCUP99
http://kdd.ics.uci.edu/databases/kddcup99/kddcup99.html