文件IO操作1. 文件io通用函数1. 实例一个通用的 IO 模型通常包括打开文件、读写文件、关闭文件这些基本操作, 主要涉及到 4 个函数: open()、 read()、 write()以及 close()。 首先来看一个简单的应用例子,源码如下: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdio.h> int main(int argc, char **argv) { int fd; if(argc != 3) { printf("Usage: %s <target file> <String>\n", argv[1]); } fd = open(argv[1], O_RDWR | O_CREAT, 0644); if(fd < 0) { printf("open %s failed!\n", argv[1]); } write(fd, argv[2], strlen(argv[2])); write(fd, "\r\n", 2); close(fd); } 编译: gcc 00_demo.c -o 00_demo 执行: $./00_demo test.txt helloworld $ cat test.txt helloworld 2. 文件描述符调用 open 函数会有一个int 类型的返回值,在 open函数执行成功的情况下,会返回一个非负整数, 该返回值就是一个文件描述符(file descriptor) ,如果返回值是负数,说明打开文件失败。 3. open/close/read/write函数首先介绍一下man命令,它可以查看命令或者函数的用法及详细介绍,共包含9种类型如下: 1 Executable programs or shell commands // 命令 2 System calls (functions provided by the kernel) // 系统调用,比如 man 2 open 3 Library calls (functions within program libraries) // 函数库调用 4 Special files (usually found in /dev) // 特殊文件, 比如 man 4 tty 5 File formats and conventions eg /etc/passwd // 文件格式和约定, 比如 man 5 passwd 6 Games // 游戏 7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) / /杂项 8 System administration commands (usually only for root) // 系统管理命令 9 Kernel routines [Non standard] // 内核例程 以open为例,可以查看open的原型和头文件 OPEN(2) Linux Programmer's Manual OPEN(2) NAME open, openat, creat - open and possibly create a file SYNOPSIS #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); 其他函数的用法也可以使用man查看。 2. 应用操作excel实例1. 新建文件新建一个excel表格,并保存为csv格式,为避免由于编码格式导致的问题,文件内容全部使用ascii字符,如下:
 
使用notepad++查看文件内容如下: ,Chinese,Math,English,Sum,level Tom,90,80,88,, Bob,76,89,90,, Lucy,84,88,74,, 可以看出,表格内容由逗号分隔,上传至Ubuntu,使用hexdump查看,文件内容如下:

2. 应用处理接下来写一个应用读取源文件数据,处理后写入新的文件。要求如下: 1.实现打开和关闭我们只需要调用open即可实现对源文件的打开和对目标文件的创建。 #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <errno.h> int main(int argc, char **argv) { int fd_data, fd_result; if(argc != 3) { printf("Usage: %s <data.csv> <result.csv>\n", argv[0]); return -1; } fd_data = open(argv[1], O_RDONLY); if(fd_data < 0) { printf("open %s failed!\n", argv[1]); perror("open"); return -1; } else { printf("data file fd = %d\n", fd_data); } fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644); if(fd_result < 0) { printf("create %s failed!\n", argv[2]); perror("create"); return -1; } else { printf("result file fd = %d\n", fd_result); } close(fd_data); close(fd_result); } 其中有几个点需要提一下: 2. 实现按行读取read的返回值分为三种类型: 1、如果读取成功,则返回实际读到的字节数。这里又有两种情况:一是如果在读完count要求字节之前已经到达文件的末尾,那么实际返回的字节数将小于count值,但是仍然大于0;二是在读完count要求字节之前,仍然没有到达文件的末尾,这是实际返回的字节数等于要求的count值。 2、如果读取时已经到达文件的末尾,则返回0。 3、如果出错,则返回-1。 判断是否读完一行可以通过读换行符确定,即'\r' 和'\n' 主函数内容如下: int main(int argc, char **argv) { int fd_data, fd_result; int i, len; unsigned char data_buf[1000]; unsigned char c; if(argc != 3) { printf("Usage: %s <data.csv> <result.csv>\n", argv[0]); return -1; } fd_data = open(argv[1], O_RDONLY); if(fd_data < 0) { printf("open %s failed!\n", argv[1]); perror("open"); return -1; } else { printf("data file fd = %d\n", fd_data); } fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644); if(fd_result < 0) { printf("create %s failed!\n", argv[2]); perror("create"); return -1; } else { printf("result file fd = %d\n", fd_result); } while(1) { /*read a line*/ len = read_line(fd_data, data_buf); if(len == -1) { break; } if(len != 0) { printf("%s\r\n", data_buf); } } close(fd_data); close(fd_result); } read_line函数内容如下: /* return value: n表示读到了一行数据的数据个数 * -1表示读到文件尾部或出错 */ static int read_line(int fd, unsigned char *buf) { unsigned char Char; int len; int i = 0; int err = 0; while(1) { len = read(fd, &Char, 1); if(len <= 0) { err = -1; break; } else { if(Char != '\r' && Char != '\n') { buf[i] = Char; i++; } else { err = 0; break; } } } buf[i] = '\0'; if(err && i == 0) return -1; return i; } 注意,执行需要两个参数; taylor@ubuntu:~/tmp$ ./demo2 excel.csv result.csv data file fd = 3 result file fd = 4 ,Chinese,Math,English,Sum,level Tom,90,94,92,, Bob,88,89,81,, Lucy,69,77,74,, 3. 实现处理数据其中,主函数只需要在读取到一行时对这一行数据进行处理。 int main(int argc, char **argv) { int fd_data, fd_result; int i, len; unsigned char data_buf[1000]; unsigned char result_buf[1000]; unsigned char c; if(argc != 3) { printf("Usage: %s <data.csv> <result.csv>\n", argv[0]); return -1; } fd_data = open(argv[1], O_RDONLY); if(fd_data < 0) { printf("open %s failed!\n", argv[1]); perror("open"); return -1; } else { printf("data file fd = %d\n", fd_data); } fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644); if(fd_result < 0) { printf("create %s failed!\n", argv[2]); perror("create"); return -1; } else { printf("result file fd = %d\n", fd_result); } while(1) { /*read a line*/ len = read_line(fd_data, data_buf); if(len == -1) { break; } if(len != 0) { // printf("%s\r\n", data_buf); process_data(data_buf, result_buf); } } close(fd_data); close(fd_result); } 对于首行和后面的数据,需要用不同的处理方式,从上述文件可以看出,首行的第一个字符是',' 对应的ascii码为0x2c,因此可以通过判断该行的第一个字符来确定是否为首行。 如果是首行,不需要进行处理,直接拷贝到目标文件; 如果不是首行,则需要进行数据分割和处理; static void process_data(unsigned char *data_buf, unsigned char *result_buf) { unsigned char name[100]; int scores[3]; int sum; int i; unsigned char *levels[] = {"A+", "A", "B"}; int level; if(data_buf[0] == ',') { strcpy(result_buf, data_buf); } else { sscanf(data_buf, "%[^,],%d,%d,%d", name, &scores[0], &scores[1], &scores[2]); #if 0 printf("%s\n", name); for(i = 0; i < sizeof(scores) / sizeof(scores[0]); i++) printf("%d\n", scores[i]); #endif sum = scores[0] + scores[1] + scores[2]; if(sum >= 270) level = 0; else if(sum >= 270) level = 1; else level = 2; sprintf(result_buf, "%s,%d,%d,%d,%d,%s", name, scores[0], scores[1], scores[2], sum, levels[level]); } printf("result: %s\n", result_buf); } 编译执行: taylor@ubuntu:~/tmp$ ./demo3 excel.csv result.csv data file fd = 3 result file fd = 4 result: ,Chinese,Math,English,Sum,level result: Tom,90,94,92,276,A+ result: Bob,88,89,81,258,B result: Lucy,69,77,74,220,B 4. 写入目标文件直接在主函数当中调用write写入目标文件即可,因代码简单,不再单独介绍,后面附上完整源码。 write(fd_result, result_buf, strlen(result_buf)); write(fd_result, "\r\n", 2); 编译执行后,目标文件内容如下: taylor@ubuntu:~/tmp$ cat result.csv ,Chinese,Math,English,Sum,level Tom,90,94,92,276,A+ Bob,88,89,81,258,B Lucy,69,77,74,220,B 使用excel打开:

完整例程源码如下: #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <errno.h> static int read_line(int fd, unsigned char *buf) { unsigned char Char; int len; int i = 0; int err = 0; while(1) { len = read(fd, &Char, 1); if(len <= 0) { err = -1; break; } else { if(Char != '\r' && Char != '\n') { buf[i] = Char; i++; } else { err = 0; break; } } } buf[i] = '\0'; if(err && i == 0) return -1; return i; } static void process_data(unsigned char *data_buf, unsigned char *result_buf) { unsigned char name[100]; int scores[3]; int sum; int i; unsigned char *levels[] = {"A+", "A", "B"}; int level; if(data_buf[0] == ',') { strcpy(result_buf, data_buf); } else { sscanf(data_buf, "%[^,],%d,%d,%d", name, &scores[0], &scores[1], &scores[2]); #if 0 printf("%s\n", name); for(i = 0; i < sizeof(scores) / sizeof(scores[0]); i++) printf("%d\n", scores[i]); #endif sum = scores[0] + scores[1] + scores[2]; if(sum >= 270) level = 0; else if(sum >= 270) level = 1; else level = 2; sprintf(result_buf, "%s,%d,%d,%d,%d,%s", name, scores[0], scores[1], scores[2], sum, levels[level]); } // printf("result: %s\n", result_buf); } int main(int argc, char **argv) { int fd_data, fd_result; int i, len; unsigned char data_buf[1000]; unsigned char result_buf[1000]; unsigned char c; if(argc != 3) { printf("Usage: %s <data.csv> <result.csv>\n", argv[0]); return -1; } fd_data = open(argv[1], O_RDONLY); if(fd_data < 0) { printf("open %s failed!\n", argv[1]); perror("open"); return -1; } else { printf("data file fd = %d\n", fd_data); } fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644); if(fd_result < 0) { printf("create %s failed!\n", argv[2]); perror("create"); return -1; } else { printf("result file fd = %d\n", fd_result); } while(1) { /*read a line*/ len = read_line(fd_data, data_buf); if(len == -1) { break; } if(len != 0) { // printf("%s\r\n", data_buf); process_data(data_buf, result_buf); write(fd_result, result_buf, strlen(result_buf)); write(fd_result, "\r\n", 2); } } close(fd_data); close(fd_result); }
|