使用系统调用来处理文件


以下文字翻译自 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.

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

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

#include <unistd.h>
#include <stdlib.h>
int main()
{
char buffer[128];
int nread;
nread = read(0, buffer, 128);
if (nread == -1)
write(2, “A read error has occurred\n”, 26);
if ((write(1,buffer,nread)) != nread)
write(2, “A write error has occurred\n”,27);
exit(0);
}

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

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

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

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

  • open

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

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


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

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

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

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

Mode Description
O_RDONLY 
Open for read-only
O_WRONLY  Open for write-only
O_RDWR Open for reading and writing

通过组合的方式(用 | OR符)加入以下可选的模式:

O_APPEND   :将写入的数据放在文件末尾
O_TRUNC   :将文件的长度设为0,删除已存在的内容
O_CREAT   :创建文件,如果需要,和权限
O_EXCL   :和O_CREAT,确保调用者创建文件。open是原子性的(atomic)也就是说,只有一个函数调用。这保护了两个程序同时创建一个文件。如果有一个成功了,另一个将会失败。

oflags的其他取值在用户手册中有文档描述——文档的第二章。

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

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

一个运行中的程序所能打开的最大文件数目是有限的。这个限制,总是会在limit.h头文件中以OPEN_MAX常量来表明,并在不同的系统中值也不同,但是POSIX规定了这个值最小是16。这个限制可能本身还需要服从整个系统的限制,所以并不一定能达到这个数目。在Linux下,限制会在运行时发生改变,所以OPEN_MAX是一个变量。这个值一般从256开始。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值