曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5891|回复: 3
打印 上一主题 下一主题

[文件I/O] open()

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2008-11-16 23:06:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
open() 函数用来打开和创建一个文件或设备,属于系统调用。这个系统调用在进程和文件之间建立一条连接,这个连接被称为文件描述符

文件描述符就像一条由进程通向内核的管道:

Quote:
[blockquote]
文件------>内核------>系统调用(使用了文件描述符)------>进程
[/blockquote]




open 的基本用法

目标:     打开一个文件

头文件:   #include <fcntl.h>; #include <sys/stat.h>; #include <sys/types.h>;
(严格的说,在遵从 POSIX 标准的系统里使用 open 并不需要包含 sys/types.h 和 sys/stat.h,但在一些 UNIX 系统里是必须)

函数原型: int fd = open(char *name,int how)
           int open(const char *pathname, int flags, mode_t mode)

参数:     name   文件名
           how    (以下几种打开类型)

O_RDONLY  只读方式打开文件 

O_WRONLY  只写方式打开文件

O_RDWR    读写方式打开文件

O_CREAT   如果该文件不存在,就创建一个新文件,并用第三个参数(mode)为其设定权限

O_EXCL    如果 O_CREAT 文件存在,则可返回错误消息。这个参数可测试文件是否存在

O_NOCTTY  如果文件为终端,那么终端不可以作为调用 open()系统函数的那个进程的控制终端

0_TRUNC   如果文件已经存在,并且以只读或只写成功打开,那么会先删除文件中原有数据

0_APPEND  以添加方式打开文件,在打开文件的同时,文件指针指向文件的末尾

返回值:   -1      遇到错误
           int      成功返回(返回文件描述符)

在 open() 函数中,how 参数可通过 "|" 组合构成,但前 3 个参数不能互相组合。

在 /usr/include/bits/fcntl.h 中有定义上面的 how 参数,如下所示:
Quote:

/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
   located on an ext2 file system */
#define O_ACCMODE       0003
#define O_RDONLY         00
#define O_WRONLY         01
#define O_RDWR             02
#define O_CREAT           0100    /* not fcntl */
#define O_EXCL           0200    /* not fcntl */
#define O_NOCTTY       0400    /* not fcntl */
#define O_TRUNC          01000    /* not fcntl */
#define O_APPEND      02000
#define O_NONBLOCK      04000
#define O_NDELAY    O_NONBLOCK
#define O_SYNC         010000
#define O_FSYNC         O_SYNC
#define O_ASYNC         020000

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
沙发
 楼主| 发表于 2009-2-6 22:26:20 | 只看该作者
如果打开成功,open 就返回新的文件描述符(总是一个非负整数);如果失败则返回 -1,这时 open 也会设置全局变量 errno 以说明读取失败的原因。

新的文件描述符,总是一个未被使用的最低的描述符--这个特性在一些环境里相当有用。例如,如果一个程序关闭了它的标准输出,然后再次调用 open ,那么文件描述符 1 将被再次使用,并且标准输出也有效地重定向到一个不同的文件和设备。

POSIX 标准化的还有一个 creat 调用,但这并不是经常使用。creat 不仅创建文件,并且还打开它。这相当于调用设置了
O_CREAT | O_WRONLY | O_TRUNCoflags

任何一个运行的程序一次性打开的文件数是有限制的。这个限制是常数 OPEN_MAX,通常定义在 limits.h 中。这个常数根据系统的不同也会有所不一样。但 POSIX 要求这个数至少是 16 。在 linux ,这个限制可能在运行时被改变,所以 OPEN_MAX 不是一个常数,典型的一般从 256 起。

文件锁
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

int main()
{
    int file_desc;
    int save_errno;

    file_desc = open("/tmp/LCK.test", O_RDWR | O_CREAT | O_EXCL, 0444);
    if(file_desc == -1) {
        save_errno = errno;
        printf("Open failed with error %d\\n", save_errno);
    }
    else {
        printf("Open succeeded\\n");
    }
    exit(EXIT_SUCCESS);
}
说明
第一次运行这个程序时,成功创建了文件:/tmp/LCK.test 。
第二次运行程序时,失败,并返回错误代码 17,它指的是 EEXIST,表示要创建的文件已经存在了。错误号定义在 errno.h 中。
两次的运行输出:
beyes@linux-beyes:~/C> ./lock1.exe
Open succeeded
beyes@linux-beyes:~/C> ./lock1.exe
Open failed with error 17
beyes@linux-beyes:~/C> cat lock1.c

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
板凳
 楼主| 发表于 2009-2-6 18:08:23 | 只看该作者
int open(const char *path, int oflags, mode_t mode);

open 建立一个访问文件或者设备的路径。如果成功,则返回文件的描述符,这个描述符可以被其后的 read write中以及起他的系统 call中使用。这个文件描述符是独一无二的,它不能被其它运行着的进程分享。如果两个程序同时打开一个文件,他们则各自维护自己的文件描述符。如果它们两个都写这个文件,他们将在各自停止的地方继续写。它们的数据不会穿插,但其中的一个会覆盖掉另外一个--但从读或写这个文件时,每一个程序都会保持自己的读写状态到自己退出读写状态。(比如写,两个都同时写,一个写完了保存退出后,另一个还没退出,直到退出时,会有类似“文件已经被改变,是否覆盖”的提示。)当然,如果希望没有不希望的冲突,那么可以使用文件锁来进行保护。

要打开的文件或者设备名被当作参数(path)进行传递; oflags 参数用来说明在打开文件时所要采取的动作。

oflags 被指定为一个强制文件访问模式和其它可选模式的连接标志。open 调用必须指定一个文件访问模式!(见上帖)

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
地板
 楼主| 发表于 2009-4-21 20:51:32 | 只看该作者

关于返回值

open() 返回的文件描述符一定是最小的未用的文件描述符。

由于一个进程在启动时自动打开了0,1,2三个文件描述符,因此,一般的运行一个程序去打开一个文件返回的文件描述符就为 3。

对于正常的一个简单的输入输出的程序
#include <stdio.h>
int main()
{
    int input;
    printf("input a integer: ");
    scanf("%d", &input);
    printf("%d\\n", input);
    return 0;
}
输入输出
beyes@linux-beyes:~/C> ./open2.exe
input a integer: 88
88
---------------------------------------------------------------
如果在程序中一开始就关闭了 0 文件描述符会怎么样呢
#include <stdio.h>
int main()
{
    int input;
        close(0);   /* 关闭标准输入 */
    printf("input a integer: ");
    scanf("%d", &input);
    printf("%d\\n", input);
    return 0;
}
程序输出
beyes@linux-beyes:~/C> ./open2.exe
input a integer: -1208172000
由此可见,已经无法正常输入!
---------------------------------------------------------------
如果关闭标准输出
#include <stdio.h>
int main()
{
    int input;
        close(1);   /* 关闭标准输入 */
    printf("input a integer: ");
    scanf("%d", &input);
    printf("%d\\n", input);
    return 0;
}
那么容易看到,printf()  函数已经无法打印内容到屏幕了
---------------------------------------------------------------
那么在应用 open() 例子中,先关闭掉标准输入( 关闭 0 文件描述符),看看怎么样
#include <stdio.h>
#include <fcntl.h>
int main()
{
    int file_desc;
    close(0);
    file_desc = open("test.txt", O_RDWR | O_CREAT, 0666);
   
    printf("The file descriptor is: %d\\n", file_desc);   

    return 0;
}
程序输出
beyes@linux-beyes:~/C> ./open2.exe
The file descriptor is: 0
有此可见,创建新文件后,返回了 0 文件描述符,因为 0 这里被关闭后变成未用的当然也是最小的。
---------------------------------------------------------------
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-3 23:18 , Processed in 0.084441 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表