关于系统级I/O函数

Unix I/O模型是在操作系统内核中实现的。应用程序可以通过 open()、read()、write()、lseek()、stat()、close() 函数来访问Unix I/O。

在Unix I/O函数上层,C应用程序对其进行了封装,产生了标准I/O函数和RIO函数。

1.open()函数

进程通过调用open函数来打开一个已存在的文件或者创建一个新文件

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

int open(char *filename, int flags, mode_t mode);
        /*返回:若成功则为新的文件描述符,若出错则为-1*/

参数说明:
open函数将filename转换为一个文件描述符,并返回描述符数字,数值为当前进程中未打开的最小描述符;
flags参数指明进程打算如何访问这个文件,可以是一个或者更多位掩码的或;
mode参数制定了新文件的访问权限位,只在创建新文件时有用。
创建新文件:
open(pathname, O_WRONLY|O_CREAT|O_TRUNC, mode)

2.read()函数

应用程序通过调用read函数执行输入功能

#include<unistd.h>

ssize_t read(int fd, void *buf, size_t n);
        /*返回:若成功则为读的字节数,若EOF则为0,若出错为-1*/

read函数从文件描述符为fd的当前文件位置赋值最多n个字节到内存位置buf。

ssize_t和size_t:
size_t被定义为unsigned long,而ssize_t被定义为long,是无符号数与有符号数的区别。read函数返回一个有符号的大小而不是一个无符号大小,这是因为出错时它必须返回-1。若返回值为无符号数,-1就会变成一个无符号的最大值,与我们要求的不相符

3.write()函数

应用程序通过调用write函数执行输出功能

#include<unistd.h>

ssize_t write(int fd, void *buf, size_t n);
        /*返回:若成功则为写的字节数,若出错则为-1*/

write函数从内存位置buf复制至多n个字节到描述符fd的当前文件位置。

在某些情况下,read和write传送的字节比应用程序要求的要少。但这些不足值不表示有错误,出现这样情况的原因有:

- 读时遇到EOF
- 从终端读文本行
- 读和写网络套接字

4.lseek()函数

应用程序通过调用lseek函数来显示地修改当前文件的位置

#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fd, off_t offset, int whence);
        /*返回:若成功则为新的偏移量,若出错则为-1*/

参数说明:
offset为偏移量,该值可正可负;
whence为定位的模式:

  • SEEK_SET:基于文件开头定位,新光标位置=文件开头+offset(此时offset>0)
  • SEEK_CUR:基于当前光标位置定位,新光标位置=当前光标位置+offset(可正可负)
  • SEEK_END:基于文件末尾定位,新光标位置=文件末尾+offset(可正可负)

5.stat()函数

应用程序通过调用stat函数来检索到关于文件的信息(也称文件的元数据)

#include<unistd.h>
#include<sys/stat.h>

int stat(const *filename, struct stat *buf);
        /*返回:若成功则为0,若出错则为-1*/

stat函数以一个文件名作为输入,并填写以下的一个stat数据结构中的各个成员:

struct stat{
	dev_t         st_dev;       /* Device */
	ino_t         st_ino;       /* inode */
	mode_t        st_mode;      /* Protection and file type */
	nlink_t       st_nlink;     /* Number of hard links */
	uid_t         st_uid;       /* User ID of owner */
	gid_t         st_gid;       /* Group ID of owner */
	dev_t         st_rdev;      /* Device type(if inode device) */
	off_t         st_size;      /* Total size,in bytes */
	unsigned long st_blksize;   /* Block size for filesystem I/O */
	unsigned long st_blocks;    /* Number of blocks allocated */
	time_t        st_atime;     /* Time of last access */
	time_t        st_mtime;     /* Time of last modification */
	time_t        st_ctime;     /* Time of last change */

6.close()函数

进程通过调用close函数来关闭一个已经打开的文件

#include<unistd.h>

int close(int fd);
        /*返回:若成功则为0,若出错则为-1*/

以上就是Unix中的6个基础函数。
在实际使用时,一定要考虑出错时的输出情况,因此可自己将基础函数进行封装,在封装后的函数内部处理出错的情况,在使用时就直接调用封装后的函数。但注意,由于新的函数不是系统自带的处理函数,在调用前一定要对其进行链接,否则会报错。

以open函数为例,在调用时,可直接选择Open函数来打开或创建文件:

int Open(const char *pathname, int flags, mode_t mode)
{
	int rc;
	if((rc = open(pathname, flags, mode)) < 0)
		unix_error("Open error");
	return rc;
}

还有一个比较重要的函数,即dup2函数,以实现I/O重定向功能。

#include<unistd.h>

int dup2(int oldfd, int new fd);
        /*返回:若成功则为非负的描述符,若出错则为-1*/

dup2函数赋值描述符表表项oldfd到描述符表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd已经打开了,dup2会在复制oldfd之前关闭newfd。

有关用法举例(foobar.txt文件由6个ASCII码字符“foobar”组成):

#include"csapp.h" 
/*csapp.h为自定义的头文件,里面封装了Unix中的I/O函数*/

int main()
{
	int fd1, fd2;
	char c;
	
	fd1 = Open("foobar.txt", O_RDONLY, 0);
	fd2 = Open("foobar.txt", O_RDINLY, 0);
	Read(fd2, &c, 1);
	Dup2(fd2, fd1);
	Read(fd1, &c, 1);
	printf("c=%c\n", c);
	exit(0);
}

在上述程序中,首先将foobar.txt文件同时打开两份。
由于系统自带的标准输入、标准输出、标准错误文件占用了0、1、2三个描述符,因此最新打开的文件描述符从3开始。则fd1=3,fd2=4。
在fd2中读取1个字符,即“f”,此时fd2的光标位置移动到了第二个字符处。
调用封装后的dup2函数,把fd2的内容覆盖到fd1上,此时对fd1操作也同时操作了fd2。因此在fd1中的光标位置也位于第二个字符处。
再从fd1中读取一个字符,即“o”。
因此该程序的输出结果为 c=o

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉浮sy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值