1.文件IO函数练习及注意事项
来源:互联网 发布:java解压包的后缀 编辑:程序博客网 时间:2024/05/01 19:27
Demo 1 open.c 创建文件
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> int main(void) { int fd; fd = open("hello", O_CREAT | O_RDWR, 0644); printf("fd = %d\n", fd); close(fd); return 0;}--------------------------------------------------$ ./a.out fd = 3
O_CREAT | O_RDWR: 按位或
O_CREAT 八进制:00000100 二进制 001 000 000
O_RDWR 八进制: 00000002 二进制 000 000 010
按位或 前面零省略 001 000 010
注意:
- 如果创建一个新文件的时候没有mode位,系统会自动填充乱码,但不会报错;当打开一个已有文件的时候,不用mode参数.
Demo 2 error.c 出错码
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> extern int errno; //外部变量引用 int main(int argc, char *argv[]) { int fd; if(argc < 2) { printf("./a.out filename\n"); return -1; } printf("begin errno = %d\n", errno); fd = open(argv[1], O_RDWR); if(fd < 0) { printf("after errno = %d\n", errno); perror("open"); exit(0); } printf("fd = %d\n", fd); close(fd); return 0; } ---------------------------------------$ ./a.out ./a.out filename$ ./a.out nullbegin errno = 0after errno = 2open: No such file or directory$ ./a.out hello begin errno = 0fd = 3
注意:
- errno这个出错时设置相应的值,但是成功是不会置为0,所以要注意:
fd1 = open("hello", O_RDWR); fd2 = open("world", O_RDWR); if(fd < 0) { printf("errno = %d\n", errno); perror("open"); exit(0); }
在上面的函数中,如果hello打开失败,world打开成功,打印出来的是errno是打开”hello”出错时对应的值,而不会因为打开”world”成功置为0;所以在使用perror的时候一定要紧跟要你想打印出错原因的函数,中间不要有其他可以设置errno的函数;
Demo 3 输出重定向 re_printf.c
#include <sys/stat.h> #include <sys/types.h> #include <sys/fcntl.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main(void) { int fd; close(STDOUT_FILENO); fd = open("hello", O_CREAT|O_RDWR, 0644); if(fd < 0){ perror("open"); exit(0); } printf("Nice to meet you!\n"); fflush(stdout); close(fd); return 0; } -----------------------------------------$ ./a.out $ lsa.out hello re_printf.c$ cat hello Nice to meet you!
程序运行流程:开始把stdout(标准输出)这个文件关掉了,打开了“hello”,那这个时候“hello”的文件描述符就是1,fd = 1;但是printf不知道1这个文件描述符对应的文件改变了,他还是把“Nice to meet you\n”写到了C标准库的缓冲区,然后等缓冲区刷新的时候写到1这个文件描述符对应的磁盘文件当中去
注意:
- fflush的作用:如果不使用fflush,文件缓冲区不刷新,但是close(fd)已经把1这个文件描述符关闭掉了,那数据就写不到1所对应的磁盘文件当中了
- 如果把fflush和close都去掉,那当程序运行到return 0的时候,系统还是会刷新缓冲区,把文件写到磁盘当中去,exit(0)也是可以的,或者main没有返回值,return和什么都不写也都是可以的。
Demo 4 测试文件描述符的最大值 maxfile_no.c
#include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> int main(void) { int fd, i = 3; char filename[100]; while(1) { printf("i = %d\n", i); sprintf(filename, "file%d", i); fd = open(filename, O_CREAT|O_RDWR, 0644); if(fd < 0){ perror("open"); exit(-1); } i++; } }
Demo 5 mycp.c 复制文件
#include <stdlib.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #define BUFFER_SIZE 4096 void sys_err(const char *buf, int status) { perror(buf); exit(status); } int main(int argc, char *argv[]) { int fdsrc, fddest, len; char buf[BUFFER_SIZE] = "0"; if(argc < 3) { printf("./a.out fdsrc fddest\n"); exit(0); } fdsrc = open(argv[1], O_RDONLY); if(fdsrc < 0) sys_err("open fdsrc", 1); fddest = open(argv[2], O_CREAT | O_WRONLY, 0664); if(fddest < 0) sys_err("open fdsrc", 2); while((len = read(fdsrc, buf, sizeof(buf))) > 0) { if(write(fddest, buf, len) < 0) sys_err("write", 3); } if(len < 0) sys_err("read", 4); close(fdsrc); close(fddest); return 0; } -----------------------------$ ./a.out hello world
注意:在write的时候count一定要写read的返回值,而不是buf的大小;避免如果读的文件长度小于buf的长度的时候,把垃圾数据写入到文件中,read的返回值就是每次读到数据的大小
Demo 6 block.c 阻塞的情况
#include <sys/stat.h> #include <sys/types.h> #include <unistd.h> int main(void) { int len; char buf[10]; len = read(STDIN_FILENO, buf, 10); write(STDOUT_FILENO, buf, len); return 0; }
Demo 7 noblock.c 非阻塞情况
#include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <string.h> #define MSG_TRY "try again\n" int main(void) { int len; char buf[10]; int fd = open("/dev/tty", O_RDWR|O_NONBLOCK); //int fd = open(STDIN_FILENO, O_RDWR|O_NONBLOCK); if(fd < 0) { perror("open /dev/tty"); exit(0); } tryagain: len = read(fd, buf, 10); if(len < 0) { if(errno == EAGAIN) { write(STDOUT_FILENO, MSG_TRY,strlen(MSG_TRY)); sleep(1); goto tryagain; } perror("read"); exit(1); } if(write(STDOUT_FILENO, buf, len) < 0) { perror("write"); exit(2); } close(fd); return 0; }
注意:
- 这次调用的不是STDIN_FILENO这个文件了,而是“/dev/tty”这个文件,因为我们要给文件重新修改flags属性,但是STDIN_FILENO已经打开过了,没有办法在修改flags,“/dev/tty”这个文件是当前终端,也可以接收终端的输入;
- 当文件是非阻塞文件的时候,去读这个文件,读不到值的出错码就是EAGAIN,所以当errno等于EAGAIN的时候,就需要再次去读这个文件,知道读到内容或出现其他出错码
- 阻塞和非阻塞属性是跟文件属性绑定的。
Demo 7 noblock_timeout.c 非阻塞读终端加上等待超时
#include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #define MSG_TRY "try again\n" #define MSG_TIMEOUT "timeout\n" void sys_err(const char *buf, int status) { perror(buf); exit(status); } int main(void) { int fd, i, len; char buf[10]; fd = open("/dev/tty", O_RDWR|O_NONBLOCK); if(fd < 0) sys_err("open", 1); for(i = 0; i < 5; i++) { len = read(fd, buf, 10); if(len >= 0) break; if(errno == EAGAIN) { write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY)); sleep(1); continue; } sys_err("read", 2); } if(i == 5) { write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT)); } else write(STDOUT_FILENO, buf, len); close(fd); return 0; }
注意:
- 一定要把判断len>=0;放到判断errno == EAGAIN前面;因为errno的值不会因为read返回一个大于0的值而重置,会一直是上一次的错误值;因为errno的值不会因为read返回一个大于0的值而重置,会一直是上一次的错误值;因为errno的值不会因为read返回一个大于0的值而重置;
重要事情说三遍!!!
Demo 8 lseek.c 指针调用
#include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #define BUFFER "hello world\n" void sys_err(const char *buf, int status) { perror(buf); exit(status); } int main(void) { int fd, len; char buf[100]; fd = open("hello", O_CREAT|O_RDWR, 0644); //打开文件 if(fd < 0) sys_err("open", 0); if(write(fd, BUFFER, strlen(BUFFER)) < 0) //把数据写入文件 sys_err("write1", 1); if(lseek(fd, 0, SEEK_SET) < 0) //把文件指针重新直到文件开头 sys_err("lseek", 0); len = read(fd, buf, sizeof(buf)); //读文件 if(len < 0) sys_err("read", 2); if(write(STDOUT_FILENO, buf, len) < 0) sys_err("write2", 3); return 0; }
Demo 9 ex_lseek.c 生成大文件
#include <sys/stat.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int fd; if(argc < 2) { printf("./a.out file"); return 0; } fd = open(argv[1], O_CREAT|O_RDWR, 0644); if(fd < 0) { perror("open"); exit(0); } lseek(fd, 1024*10, SEEK_SET); // 向后值1yi024*10个Byte write(fd, "a", 1); //然后写一个数据 close(fd); return 0; }
注意:
- 指针向后指完之后,一定要写入一个数据,这样文件才会保存成相应大小,如果不写数据,文件还是为空。
Demo 10 ex2_lseek.c 得到文件的大小
#include <sys/stat.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char *argv[]) { int fd, len; if(argc < 2) { printf("./a.out file"); return 0; } fd = open(argv[1], O_CREAT|O_RDWR, 0644); if(fd < 0) { perror("open"); exit(0); } len = lseek(fd, 0, SEEK_END); printf("len = %d\n", len); close(fd); return 0; }
lseek的返回值是移动后指针距离文件开头多少个Byte,由此可以得出文件的大小
Demo 10 fcntl.c 用fcntl重新实现非阻塞
#include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <stdio.h> #include <string.h> #define MSG_TRY "try again\n" #define MSG_TIMEOUT "timeout\n" extern int errno; void sys_err(const char *buf, int status) { perror(buf); exit(status); } int main(void) { int fd, len, flags, i; char buf[100]; flags = fcntl(STDIN_FILENO, F_GETFL); flags |= O_NONBLOCK; if(fcntl(STDIN_FILENO, F_SETFL, flags) < 0) sys_err("fcntl", 1); for (i = 0; i < 5; i++) { len = read(STDIN_FILENO, buf, sizeof(buf)); if(len >= 0) break; if(errno == EAGAIN) { write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY)); sleep(1); continue; } sys_err("read", 1); } if(i == 5) write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT)); else write(STDOUT_FILENO, buf, len); return 0; }
注意:
- 读取文件的flags用F_GETFL,写入用F_SETFL,修改flags用位或操作
0 0
- 1.文件IO函数练习及注意事项
- IO流一:概述、IO异常处理、文件续写、文件读取、文件拷贝及练习
- IO文件读取路径注意事项
- strcpy函数及注意事项
- IO小练习 ---- 文件拷贝
- 文件及IO流
- 函数总结及函数练习
- memset函数用法及注意事项
- memset函数用法及注意事项
- memset函数用法及注意事项
- VLOOKUP函数使用及注意事项
- JAVA文件结构及注意事项
- servlet 文件下载及注意事项
- strut2文件下载及注意事项
- AjaxFileUpload文件上传 及注意事项
- 七、Linux系统编程-文件和IO(五)fcntl函数及常用操作、文件锁
- 《libc 中的文件IO函数》
- 文件相关函数<io.h>
- recommend
- 哈工大操作系统实验6—内存管理
- POJ 3322 Bloxorz I
- C# Action和Func
- 03-NSTimer的简单使用
- 1.文件IO函数练习及注意事项
- HDU 1159 Common Subsequence
- HDU 1243 反恐训练营
- 自动取款机中的秘钥介绍
- 学生反馈
- 1087 1 10 100 1000
- java static关键字
- HDU 1080 Human Gene Functions
- MiniTwitter记住密码功能实现