文件I/O函数(open,read,write,lseek,close)

时间:2021-08-08 07:50:26
大多数unix文件I/O只需要用到5个函数:open,read,write,lseek,close。这些函数都为不带缓存的I/O,不带缓存指的是每个read和write都调用内核中的一个系统调用。这些函数使用时要用到三个头文件:sys/types.h,sys/stat.h,fcntl.h
#include<fcntl.h> 
#include<types.h>
#include<sys/stat.h>/*此头文件里面定义了mode标志*/
open函数:int open(const char path *name, int oflag,...);
返回:若成功为只写打开的文件描述符,若错误为-1。
调用open函数可以打开或创建一个文件,仅当创建新文件时才使用第三个参数,由open函数返回的文件描述符一定是最小的未用的描述符数字。
第一个参数为路径名
第二个参数为文件状态标志:
O_RDONLY或0:可读
O_WRONLY或1:可写
O_RDWR或2:可执行
O_APPEND:每次写时都加到文件的尾部
O_CREAT:若此文件不存在则创建它,使用此选项时,需同时说明第三个参数mode,用其说明该新文件的存取许可权位
O_EXCL:如果同时指定了O_CREAT,而文件已经存在,则出错,这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作
O_TRUNC:如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0
O_NOCTTY:如果pathname指的是终端设备,则不将此设备分配作为此进程的控制终端
O_NONBLOCK:如果pathname指的是一个FIFO,一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式
O_SYNC:使每次write都等到物理I/O操作完成
第三个参数一般为文件权限:
S_IRWXU,0700:代表该文件所有者具有可读,可写,可指向的权限
S_IRUSR或S_IREAD,0400:代表该文件所有者具有可读取的权限
S_IWUSR或S_IWRITE,0200:代表该文件所有者具有可写入的权限
S_IXUSR或S_IEXEC,0100:代表该文件所有者具有可指向的权限
S_IRWXG,0070:代表该文件用户组具有可读,可写,可执行的权限
S_IRGRP,0040:代表该文件用户组具有可读的权限
S_IWGRP,0020:代表该文件用户组具有可写的权限
S_IXGRP,0010:代表该文件用户组具有可执行的权限
S_IRWXO,0007:代表其他用户具有可读,可写,可执行的权限
S_IROTH,0004:代表其他用户具有可读的权限
S_IWOTH,0002:代表其他用户具有可写的权限
S_IXOTH,0001:代表其他用户具有可执行的权限
creat函数:int creat(const char *pathname, mode_t mode);
返回:若成功为只写打开的文件描述符,若出错为-1
该函数等效于:open(pathname,O_WRONLY|O_CREAT|O_TRUNC,mode);
用于创建一个新文件
注: 第三个参数是在第二个参数中有O_CREAT时才用作用。若没有,则第三个参数可以忽略

open函数与fopen函数的差别:creat open,close,read,write,lseek等系统调用是使用底层文件描述符来标识文件,而文件描述符特定的存在于unix/linux中,不方便移植。fopen,fclose,fread,fseek属于c语言I/O标准库中的函数。编写跨平台程序时,用标准库函数比较方便移植。

read函数:ssize_t read(int filedes, void *buff, size_t nbytes);
返回:读到的字节数,若已到文件尾为0,若出错为-1
有多种情况可使实际读到的字节数少于要求读字节数:
(1)读普通文件时,在读到要求字节数之前已到达了文件尾端,如,若在到达文件尾端之前还有 30个字节,而要求读100个字节,则read返回30,下一次在调用read时,它将返回0。
(2)当从终端设备读时,通常一次最多读一行
(3)当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
(4)某些面向记录的设备,如磁带一次最多返回一个记录
读操作从文件的当前位移量处开始,在成功返回之前,该位移量增加实际读得的字节数
write函数:ssize_t write(int filedes, const void *buff,size_t nbytes);
返回:若成功为已写的字节数,若出错为-1
close函数:int close(int filedes);
返回:若成功为0,若出错为-1
关闭一个文件时也释放该进程加在该文件上的所有记录锁,当一个进程终止时,它所有的打开文件都由内核自动关闭。
lseek函数:off_t lseek(int filedes, off_t offset, int whence);
返回:若成功为新的文件位移,若出错为-1
每个打开文件都有一个与其相关联的”当前文件位移量”,它是一个非负整数,用以度量从文件开始处计算的字节数。按系统默认,当打开一个文件时,除非指定O_APPEND选项时,否则该位移量被设置为0。通常读,写操作都从当前文件位移量处开始,并使位移量增加所读或写的字节数。可以调用lseek显式地定位一个打开的文件。
对参数offset的解释与参数whence的值有关。
若whence是SEEK_SET,则将该文件的位移量设置为距文件开始处offset个字节
若whence是SEEK_CUR,则将该文件的位移量设置为其当前值加offset,offset可为正或负
若whence是SEEK_END,则将该文件的位移量设置为文件长度加offset,offset可为正或负
早期用0,1,2代铁SEEK_SET,SEEK_CUR,SEEK_END。
某些设备也可能允许负的位移量,但对于普通文件,则其位移量必须是非负值
          范例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
     int fd, size;
     char buf1[]="Hello, world";
     char buf2[50];
     if((fd=open("/home/sam/helloworld",O_CREAT|O_TRUNC|O_RDWR,0666))==-1)
     {
         printf("Open or create file named \"helloworld\" failed.\n");
         exit(1);
     }
     write(fd,buf1,sizeof(buf1));
     close(fd);
     if((fd=open("/home/sam/helloworld",O_RDONLY))==-1)
     {
         printf("Open file named \"helloworld\" failed.\n");
         exit(1);
     }
     size=read(fd,buf2,sizeof(buf2));
     close(fd);
     printf("%s\n",buf2);
     if((fd=open("/home/sam/helloworld",O_RDONLY))==-1)
     {
         printf("Open file named \"helloworld\" failed.\n");
         exit(1);
     }
     lseek(fd,6,SEEK_SET);
     size=read(fd,buf2,sizeof(buf2));
     printf("%s\n",buf2);
     close(fd);
     return 0;
}