关于系统级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
- 点赞
- 收藏
- 分享
- 文章举报
- 计算机系统的初步学习(持续更新)--关于replace_byte()函数
- 关于PHP fopen函数在windows系统上创建中文命名的文档时乱码的问题
- PHP中关于系统相关函数的应用
- 关于系统函数的学习记录整理
- 关于系统时钟初始化函数“void Stm32_Clock_Init(u8 PLL)
- 关于UCOSIII 系统函数和系统调度
- 关于函数库调用与系统调用--写于2018.9.19 简书
- 关于stat函数和根据st_mode 的值获取目标文件的文件类型和用户权限,及对相关系统宏的一点想法
- 关于大小端的简单介绍以及使用C写一个函数判断当前系统是大端存储还是小端存储
- 关于中文分词系统里的isChineseNumber()函数
- 关于系统函数重载和属性的问题
- 文件、文件系统、关于文件的函数
- 关于c++中字符串的系统函数
- ERROR: Removing 'hello': Device or resource busy //关于使用系统定义的模块加载和卸载函数
- 信号与系统课程中关于各种编码MATLAB仿真的绘图函数
- 关于安装WIN7和Ubuntu14.04双系统后,启动直接引导到Ubuntu系统
- 库函数与系统调用的区别
- python关于for循环的几个函数
- 关于 Kotlin 自定义 View 时,引用系统属性问题
- 一连浪了好几天了,一直没好好的学习,希望在运动会结束后能够好好的认真学习,下面是关于栈的链表形式的有关函数的实现,与上一个实现形式有所差别