文件IO(1)--creat和open
今天开始学习unix/linux系统下的文件I/O函数—打开文件、读文件、写文件等。大多数文件I/O只需要用到5个函数:open,read,write,lseek已经close,这5个函数都直接调用同名的系统调用,所以是不带缓冲的,本节,主要介绍open和creat函数。
1.open函数
1)函数原型:
#include <fcntl.h>
int open(const char* pathname,int flags)
int open(const char* pathname,int flags,mode_t mode);
2)函数功能:
打开或建立一个文件。对于open函数,仅当创建文件时,才用到第三个参数
3)参数说明:
pathname:打开或创建的文件名
flags:用下列一个或多个常量进行“或”运算构成flags参数(这些常量定义在<fcntl.h>
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读写打开
以上三个常量只能选一个,下面的则可以多选:
O_APPEND 每次写时都追加到文件的尾端。
O_CREAT 若此文件不存在,则创建它。使用此选项时,需要第三个参数mode,用其
指定新文件的访问权限。
O_EXCL 如果同时制定了O_CREAT,而文件已经存在,则会报错。因此可以测试一个
文件是否存在,如果不存在,则创建此文件,这使测试和创建两者成为一个
原子操作。
O_TRUNC 如果此文件存在,而且为只读或读写成功打开,则将其长度截短为0。
O_NOCTTY 如果pathname指的是终端设备,则不将该设备分配作为此进程的控制终端。
O_NONBLOCK 如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,
则此选项为文件的本次打开操作和后续的I/O操作设置非阻塞模式。
mode:用下列一个或多个常量进行“或”运算构成mode参数(这些常量定义在sys/stat.h)
S_IRWXU:00700 拥有者读写执行权限
S_IRUSR: 00400 拥有者读权限
S_IWUSR:00200 拥有者写权限
S_IXUSR: 00100 拥有者执行权限
S_IRWXG:00070 组内成员读写执行权限
S_IRGRP: 00040 组内成员读权限
S_IWGRP:00020 组内成员写权限
S_IXGRP: 00010 组内成员执行权限
S_IRWXO:00007 其他成员读写执行权限
S_IROTH: 00004 其他成员读权限
S_IWOTH:00002 其他成员写权限
S_IXOTH: 00001 其他成员执行权限
也可以直接指定mode的值,如0777,0541等
注意:此处设定的mode的值并不是文件最终的权限,文件最终的权限是按照mode & ~umask得到的,而默认的umask是0022,所以如果想按照mode的值设置文件权限,需要在建立文件之前将umask的值设置为0000
4)实例程序:
以下程序当不存在test.txt时创建一个test.txt文件,并给予最大权限
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> int main() { int fd; umask(0000); //if((fd = open("test.txt",O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,0777)) == -1) if((fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,S_IRWXU | S_IRWXG | S_IRWXO)) == -1) { //printf("open:%s with errno:%d\n",strerror(errno),errno); perror("open"); perror(“open”); exit(1); } else { printf("success"); } close(fd); return 0; }
执行结果:
[hb@localhost unixadvance]$ gcc -g -o testOpen testOpen.c
[hb@localhost unixadvance]$ ./testOpen
success
[hb@localhost unixadvance]$ ls -al
总计 76
drwxrwxr-x 2 hb hb 4096 08-02 11:19 .
drwxrwxrwx 5 root root 4096 08-01 23:49 ..
-rwxrwxr-x 1 hb hb 5476 08-02 11:17 a.out
-rw-rw-r-- 1 hb hb 529 08-02 11:03 testCreat.c
-rwxrwxr-x 1 hb hb 6696 08-02 11:19 testOpen
-rw-rw-r-- 1 hb hb 529 08-02 11:17 testOpen.c
-rw-r--r-- 1 root root 12288 08-02 11:17 .testOpen.c.swp
-rwxrwxrwx 1 hb hb 0 08-02 11:19 test.txt
可以看到test.txt的权限确实是777,而如果去掉程序中umask(0000)一句,则创建出来的文件权限为:
[root@localhost unixadvance]# ls -al
总计 76
drwxrwxr-x 2 hb hb 4096 08-02 11:25 .
drwxrwxrwx 5 root root 4096 08-01 23:49 ..
-rwxrwxr-x 1 hb hb 5476 08-02 11:17 a.out
-rw-rw-r-- 1 hb hb 529 08-02 11:03 testCreat.c
-rwxr-xr-x 1 root root 6595 08-02 11:25 testOpen
-rw-rw-r-- 1 hb hb 531 08-02 11:21 testOpen.c
-rw-r--r-- 1 root root 12288 08-02 11:21 .testOpen.c.swp
-rwxr-xr-x 1 root root 0 08-02 11:25 test.txt
这是因为默认的umask是022,所以默认的文件权限就为0755。
当我们第二次执行此程序:
[root@localhost unixadvance]# ./testOpen
open: File exists
File exists这个错误是由perror("open")报出来的,它定义在<stdio.h>中
perror (const char *s)用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 设备 (stderr) 。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。
在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。perror函数只是将你输入的一些信息和现在的errno所对应的错误一起输出。
如果想看到errno的值,则将perror()替换为
printf("open:%s with errno:%d\n",strerror(errno),errno); perror("open");
此时的执行结果为:
[root@localhost unixadvance]# ./testOpen
open:File exists with errno:17
errno定义在<errno.h>中
2.creat函数
1)函数原型:
#include <fcntl.h>
int creat(const char *pathname ,mode_t mode);
2)函数功能:
创建一个新文件。
creat函数等效于如下函数:
open(pathname,O_WRONLY | O_CREAT | O_TRUNC, mode)
注意:creat只能以只写方式打开,不能读,读出的将是乱码!
3)参数说明:
pathname:创建的文件名
mode:与open的mode相同
4)程序实例:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> int main() { int fd; umask(0000); if((fd = creat("test.txt",0777)) == -1) { //perror("open"); printf("open:%s with errno:%d\n",strerror(errno),errno); exit(1); } else { printf("success\n"); } close(fd); return 0; }
运行结果:
[root@localhost unixadvance]# gcc testCreat.c
[root@localhost unixadvance]# ./a.out
success
[root@localhost unixadvance]# ls -al
总计 76
drwxrwxr-x 2 hb hb 4096 08-02 15:02 .
drwxrwxrwx 5 root root 4096 08-01 23:49 ..
-rwxr-xr-x 1 root root 5462 08-02 15:02 a.out
-rw-rw-r-- 1 hb hb 529 08-02 15:02 testCreat.c
-rw-r--r-- 1 root root 12288 08-02 15:02 .testCreat.c.swp
-rwxr-xr-x 1 root root 6907 08-02 11:39 testOpen
-rw-rw-r-- 1 hb hb 611 08-02 11:39 testOpen.c
-rwxrwxrwx 1 root root 0 08-02 15:02 test.txt
当我们第二次运行程序:
[root@localhost unixadvance]# ./a.out
success
仍然是success,说明creat函数不管原来有没有同名文件都会返回成功,那是否覆盖了呢?我们继续试验:
在已经生成的test.txt里加入一句话:This is the old one!
然后将原程序中fd = creat("test.txt",0777) 改为 fd = creat("test.txt",0700),结果如下:
[root@localhost unixadvance]# ./a.out
success
[root@localhost unixadvance]# ls -al
总计 76
drwxrwxr-x 2 hb hb 4096 08-02 15:08 .
drwxrwxrwx 5 root root 4096 08-01 23:49 ..
-rwxr-xr-x 1 root root 5462 08-02 15:08 a.out
-rw-rw-r-- 1 hb hb 530 08-02 15:08 testCreat.c
-rw-r--r-- 1 root root 12288 08-02 15:08 .testCreat.c.swp
-rwxr-xr-x 1 root root 6907 08-02 11:39 testOpen
-rw-rw-r-- 1 hb hb 611 08-02 11:39 testOpen.c
-rwxrwxrwx 1 root root 0 08-02 15:08 test.txt
说明:如果创建的文件与现有文件重名,则creat函数会将重名文件内容清零(这其实是由O_TRUNC标志位决定的),但原文件的权限却不会被改变!!