1.0中,已经基本把C语言的很多语言上的特性,以及常见的问题浏览了一遍了。2.0开始就是一些具体的实际应用。不过实话说,C语言要完成图形化程序是 非常麻烦的,现在用C语言的地方很多就是嵌入式,或者服务器程序。首先将如何操作文件。这篇的大部分内容再以前的一篇特别篇讲过。
C 语言是为了写Unix诞生的,所以C语言的I/O系统遵循了Unix的I/O体系,或者说Unix遵循了C的,这就是一个鸡和弹的问题。Unix的I/O 将一切外部设备视为文件,有5个基本的I/O函数open, close, read, write和ioctl。其中ioctl是一个控制设备用的函数,对于文件基本不需要这个函数,其他的对应与C语言中的文件函数就是fopen, fclose, fread, fwrite。Unix将文件视为一个字节流,windows也采用了这种方式。
对一个文件进行I/O 时,首先需要fopen, 这个函数返回一个文件指针,其他文件I/O函数都要使用这个指针,fopen函数有两个参数,第一个是文件名字,第二个是打开方式。文件名字好理解,符合 前面讲到的文件树的规则就可以了,容易引起困惑的是文本方式打开文件和二进制方式打开文件有什么区别?我个人认为由于文件本身是无差别的字节流,所以两种 方式没有区别,但有一次在读取设备采集的原始数据时出了个错误。在windows平台下,以文本方式打开文件时,读取到一个0x1D字节时,就认为文件结 束了,feof函数返回真了,而实际上文件后面还有好大一块,而以二进制方式打开则一直读到实际的文件尾。这个估计就是文本方式和二进制方式打开文件的区 别。
举个例子,一个32位数字0x0000200十进制数512,可以以两种方式存在文件中。第一种是人易读的方式"512",存储3个 字符,每个字符按ASCII码存放,这样用一个文本编辑器打开,人可以容易的读到这个数是512。 第二种方式是以机器易读的方式直接存储4个字节一个32位的00 00 02 00,这样机器容易读取这个数是512,直接内存拷贝就可以。 否则机器就要首先将"512"读每一个字符, 然后将"5"这个字符的ASCII码转换成5, 最后执行一个5*100+1*10+2才能得到512这个数。fwrite和fread都是机器易读的方式。 从文件中将00 00 02 00读入一个int类型变量,用fread写就是
fread(&a, sizeof(int), 1, fp);
即从文件中读取一个大小为sizeof(int)的内容到内存地址&a。
相应的fwrite形式是
fwrite(&a, sizeof(int), 1, fp);
若文件中存储的是人易读的形式比如 “512 ”,那么要处理就最好使用fscanf和fprintf。
可能你熟悉scanf和printf,实际上这两个函数是用fscanf和fprintf实现的。scanf和printf是操作的标准输入输出设备,stdin和stdout。由于一切都是文件这两个设备也被当作是文件,scanf实际上是
fscanf(stdin, "....", ......),
而printf实际是
fprintf(stdout, "...", ...);
这样碰到全是用文本书写的数据就好读取了, 和从命令行读和写是一样的。比如有一种试验生成的数据文件格式是: (没有文件头,为了清晰加上时间等标签)
名字 电压 速度 转速
A20 12.8 38.9 2000
那么读取这种数据文件的代码类似与
是不是和scanf的用法很类似。 有时可能不是这么简单的数据格式 需要稍微做点改动。现在大量的试验数据都是这种格式的数据,因为Matlab可以简单的用一句话把它载入到内存的一个矩阵变量中。
上 面的例子是读的, 把fscanf换成fprintf就实现了格式化写文件,和你用printf输出一模一样,需要注意的是写完一定要记得 fclose 。 因为f这一组的文件I/O函数是缓冲式读写,如果你不fclose文件,程序结束的时候系统会帮你调用fclose。但是如果程序中途崩溃了,你打开文件 一看,可能什么也没有。或者你先写了一个文件,没有fclose, 后面马上又读了这个文件,也很有可能因为还在内存的缓冲区没有写到磁盘上去导致你后面什么也读不出来。
这是个特别篇,更详细的文件I/O,后面会详细给出。
C 语言是为了写Unix诞生的,所以C语言的I/O系统遵循了Unix的I/O体系,或者说Unix遵循了C的,这就是一个鸡和弹的问题。Unix的I/O 将一切外部设备视为文件,有5个基本的I/O函数open, close, read, write和ioctl。其中ioctl是一个控制设备用的函数,对于文件基本不需要这个函数,其他的对应与C语言中的文件函数就是fopen, fclose, fread, fwrite。Unix将文件视为一个字节流,windows也采用了这种方式。
对一个文件进行I/O 时,首先需要fopen, 这个函数返回一个文件指针,其他文件I/O函数都要使用这个指针,fopen函数有两个参数,第一个是文件名字,第二个是打开方式。文件名字好理解,符合 前面讲到的文件树的规则就可以了,容易引起困惑的是文本方式打开文件和二进制方式打开文件有什么区别?我个人认为由于文件本身是无差别的字节流,所以两种 方式没有区别,但有一次在读取设备采集的原始数据时出了个错误。在windows平台下,以文本方式打开文件时,读取到一个0x1D字节时,就认为文件结 束了,feof函数返回真了,而实际上文件后面还有好大一块,而以二进制方式打开则一直读到实际的文件尾。这个估计就是文本方式和二进制方式打开文件的区 别。
举个例子,一个32位数字0x0000200十进制数512,可以以两种方式存在文件中。第一种是人易读的方式"512",存储3个 字符,每个字符按ASCII码存放,这样用一个文本编辑器打开,人可以容易的读到这个数是512。 第二种方式是以机器易读的方式直接存储4个字节一个32位的00 00 02 00,这样机器容易读取这个数是512,直接内存拷贝就可以。 否则机器就要首先将"512"读每一个字符, 然后将"5"这个字符的ASCII码转换成5, 最后执行一个5*100+1*10+2才能得到512这个数。fwrite和fread都是机器易读的方式。 从文件中将00 00 02 00读入一个int类型变量,用fread写就是
fread(&a, sizeof(int), 1, fp);
即从文件中读取一个大小为sizeof(int)的内容到内存地址&a。
相应的fwrite形式是
fwrite(&a, sizeof(int), 1, fp);
若文件中存储的是人易读的形式比如 “512 ”,那么要处理就最好使用fscanf和fprintf。
可能你熟悉scanf和printf,实际上这两个函数是用fscanf和fprintf实现的。scanf和printf是操作的标准输入输出设备,stdin和stdout。由于一切都是文件这两个设备也被当作是文件,scanf实际上是
fscanf(stdin, "....", ......),
而printf实际是
fprintf(stdout, "...", ...);
这样碰到全是用文本书写的数据就好读取了, 和从命令行读和写是一样的。比如有一种试验生成的数据文件格式是: (没有文件头,为了清晰加上时间等标签)
名字 电压 速度 转速
A20 12.8 38.9 2000
那么读取这种数据文件的代码类似与
FILE* fpin, *fpout;
if((fpin=fopen(argv[1],"r"))==NULL)
{
printf("Can't open Input file %s/n", argv[1]);
return -1;
}
while(!feof(fpin))
{
fscanf(fpin, "%s %f %f %d",Name, &V, &S, &M);
}
是不是和scanf的用法很类似。 有时可能不是这么简单的数据格式 需要稍微做点改动。现在大量的试验数据都是这种格式的数据,因为Matlab可以简单的用一句话把它载入到内存的一个矩阵变量中。
上 面的例子是读的, 把fscanf换成fprintf就实现了格式化写文件,和你用printf输出一模一样,需要注意的是写完一定要记得 fclose 。 因为f这一组的文件I/O函数是缓冲式读写,如果你不fclose文件,程序结束的时候系统会帮你调用fclose。但是如果程序中途崩溃了,你打开文件 一看,可能什么也没有。或者你先写了一个文件,没有fclose, 后面马上又读了这个文件,也很有可能因为还在内存的缓冲区没有写到磁盘上去导致你后面什么也读不出来。
这是个特别篇,更详细的文件I/O,后面会详细给出。