您的位置:首页 > 其它

使用系统调用来处理文件

2015-01-26 17:55 155 查看
以下文字翻译自Beginning Linux Programming的小节Low-Level
File Access

每一个运转的程序——也叫进程——都会拥有一些相关联的文件描述符(file descriptor)。这是些不大的整数,可以用来使用打开了的文件或者设备。有多少个文件描述符可以使用,取决于系统如何配置。当一个程序开始运行时,通常有3个文件描述符已经打开。它们是:

0:标准输入
1:标准输出
2:标准错误流

你可以通过使用系统调用open,关联其他文件指示符到文件以及设备。这些已经被自动打开的文件指示符,允许你用write来创建程序。

write

系统调用write将把指针buf(write方法的参数)所指向的内存中的前nbyte(write方法的参数)个字节写入到文件描述符fildes(write方法的参数)所关联的文件中。返回的值为实际写入的字节数。这个值可能会小于nbyte,如果文件描述符有错,或者底层设备对数据块大小敏感。如果返回0,表示没有写入,如果返回-1,表示有错,错误的信息将从全局变量errno获得。

以下为语法:

#include <unistd.h>
size_t write(int fildes, const void *buf, size_t nbytes);

可以写一个程序, simple_write.c来试试:

#include <unistd.h>
#include <stdlib.h>

int main()
{
if ((write(1, “Here is some data\n”, 18)) != 18)
write(2, “A write error has occurred on file descriptor 1\n”,46);
exit(0);
}

这个程序简单地print一句信息到标准的输出流中。当程序退出时,所有的打开的文件描述符将被自动关闭,所以不需要显式地关闭。然而,当你使用的是缓冲的输出流时,根本就不用考虑这个。

$ ./simple_write
Here is some data
$

值得再次注意的是,write可能返回的字节数小于你指定字节数。这并不一定是错误。在你的程序中,你需要检查errno,然后写入剩余的数据。

read

read方法将从文件描述符fildes关联的文件中,读取nbytes个字节的数据,并放入到指针buf所指向的内存中。返回的值为所读取的真实的字节数,可能少于nbytes。如果返回0,表示没有读到任何数据,已经到达文件的末尾了。如果出错,这返回-1.

[align=left]#include <unistd.h>[/align]
[align=left]size_t read(int fildes, void *buf, size_t nbytes);[/align]

以下程序,simgle_read.c,将128个字节标准输入复制到标准输出中。如果输入的字节少于128,则将全部复制到输出流中。

[align=left]#include <unistd.h>[/align]
[align=left]#include <stdlib.h>[/align]
[align=left]int main()[/align]
[align=left]{[/align]

[align=left]char buffer[128];[/align]
[align=left]int nread;[/align]
[align=left]nread = read(0, buffer, 128);[/align]
[align=left]if (nread == -1)[/align]
[align=left]write(2, “A read error has occurred\n”, 26);[/align]
[align=left]if ((write(1,buffer,nread)) != nread)[/align]
[align=left]write(2, “A write error has occurred\n”,27);[/align]
[align=left]exit(0);[/align]

[align=left]}[/align]

如果执行这个文件,将看到如下输出:

[align=left]$ echo hello there | ./simple_read[/align]
[align=left]hello there[/align]
[align=left]$ ./simple_read < draft1.txt[/align]
[align=left]Files[/align]
[align=left]In this chapter we will be looking at files and directories and how to manipulate[/align]
[align=left]them. We will learn how to create files,$[/align]

在第一次执行中,你通过echo输入了内容到输入流中,然后通过管道符,传到了你的文件中。在第二次执行中,你从一个文件中导入了数据到输入流中,你可以看到输出的只是文件中的前部分内容。

可以注意到shell命令符紧跟在输出文字的最后一位,在这个文件中,128个字符没有产生所有的内容。

open

要产生新的文件描述符,需要使用open方法。

[align=left]#include <fcntl.h>[/align]
[align=left]#include <sys/types.h>[/align]
[align=left]#include <sys/stat.h>[/align]
[align=left]int open(const char *path, int oflags);[/align]
[align=left]int open(const char *path, int oflags, mode_t mode);[/align]

严格上讲,在POSIX标准下,你不需要include sys/types.h、sys/stat.h文件来使用open方法。当在某些UNIX系统下还是需要的。

简单地说,open创建了使用文件或者设备的途径。如果成功,返回文件描述符,然后可以用于read, write, 以及其他系统调用。文件描述符是独一无二的,并且不会与其他进程共享同一个描述符。如果两个程序同时打开了同一个文件,他们使用的是不一样的文件描述符。如果他们都写入数据到文件,则他们会继续写入到之前离开的位置。写入的数据不会交错存取,而是会覆盖掉另一个的数据。两个程序会各自维护自己对文件末尾的记录。你可以通过文件上锁的方式来避免冲突。(第七章将具体描述这些内容)

将被打开的文件的名字——路径——会作为参数传入,oflags参数用来指定打开这个文件需要执行的行为(action)。

oflags参数用来指定文件访问(access)模式或其他相关的模式。open方法必须指定以下表中展示的访问模式中的一个。

Mode Description
O_RDONLY [align=left]Open for read-only[/align]
O_WRONLY Open for write-only
O_RDWR Open for reading and writing
通过组合的方式(用 | OR符)加入以下可选的模式:

[align=left]O_APPEND :将写入的数据放在文件末尾[/align]

[align=left]O_TRUNC :将文件的长度设为0,删除已存在的内容[/align]

[align=left]O_CREAT :创建文件,如果需要,和权限[/align]

[align=left]O_EXCL :和O_CREAT,确保调用者创建文件。open是原子性的(atomic)也就是说,只有一个函数调用。这保护了两个程序同时创建一个文件。如果有一个成功了,另一个将会失败。[/align]

[align=left]oflags的其他取值在用户手册中有文档描述——文档的第二章。[/align]

[align=left]如果打开成功,则open方法返回值是文件描述符,如果失败,则返回-1,具体的错误信息通过查看全局变量errno来获知。最新的文件描述符总是所有未使用的描述符里值最小的,在某些情况下,这种特征很有有。例如,如果程序关闭了标准输出,然后再调一次open,这描述符1将被重用,原来指向标准输出的描述符1,将指向另一个文件或者设备。[/align]

使用create方法也是符合POSIX标准的,但是不常用。create不仅仅创建,而且会打开。它跟调用open并使传入参数oflags的值O_CREAT
| O_WRONLY | O_TRUNC 的效果是一样的。

一个运行中的程序所能打开的最大文件数目是有限的。这个限制,总是会在limit.h头文件中以OPEN_MAX常量来表明,并在不同的系统中值也不同,但是POSIX规定了这个值最小是16。这个限制可能本身还需要服从整个系统的限制,所以并不一定能达到这个数目。在Linux下,限制会在运行时发生改变,所以OPEN_MAX是一个变量。这个值一般从256开始。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐