Linux文件IO-open,write,read,lseek,close
在linux编程中,经常用到open,write,read,lseek,close这几个函数。这里系统总结一下。
在linux编程中,经常用到open,write,read,lseek,close这几个函数。这里系统总结一下。
一、函数open
参考:https://linux.die.net/man/2/open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname,int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
返回值:若成功,返回一个文件描述符fd;若失败,返回-1
函数参数:
- pathname :打开文件的路径名
- flags:用来控制打开文件的模式
- mode:用来设置创建文件的权限(rwx)。当flags中带有 O_CREAT 时,也就是创建新文件时才有效。
函数creat只是用于创建新文件,这样对比看来open的功能更加强大。
由于open函数完全可以替代creat函数,所以现在基本上不用creat函数了。
下面对各个参数进行详细的说明:
flags参数说明:
- O_RDONLY:只读模式
- O_WRONLY:只写模式
- O_RDWR:可读可写模式
flags参数必须包括以上3个参数之一,并且只能选择一个。
还有一些flags参数是可选的,如下:
- O_APPEND 以追加的方式打开文件
- O_CREAT 创建一个文件
- O_EXEC 如果使用了O_CREAT而且文件已经存在,就会发生一个错误
- O_NOBLOCK 以非阻塞的方式打开一个文件
- O_TRUNC 如果文件已经存在,则删除文件的内容
我们可以用符号“|”分隔开,例如,flags为O_RDWR | O_APPEND,表示以可读可写的模式打开文件并且追加到文件后面。
如果flags中使用了O_CREAT标志,则调用open函数的时候需要加上打开文件的模式,设置文件的用户权限。也就是说使用O_CREAT标志时,open的原型应该是这样的:int open(const char *pathname, int flags, mode_t mode);
用过chmod命令的就知道这个怎么用了,可以用八进制数据表示,
其中4:读权限,2:写权限,1:可执行权限,0:无权限。
下面是mode可取的一些值,都是八进制的值,使用这些值的时候需要包含头文件:sys/types.h,sys/stat.h
- S_IRWXU 00700 用户可以读
- S_IRUSR 00400 用户可以写
- S_IWUSR 00200 用户可以执行
- S_IXUSR 00100 用户可以读、写、
- S_IRWXG 00070 组可以读
- S_IRGRP 00040 组可以写
- S_IWGRP 00020 组可以执行
- S_IXGRP 00010 组可以读写执行
- S_IRWXO 00007 其他人可以读
- S_IROTH 00004 其他人可以写
- S_IWOTH 00002 其他人可以执行
- S_IXOTH 00001 其他人可以读、写
- S_ISUID 04000 设置用户执行ID
- S_ISGID 02000 设置组的执行ID
实际生成的文件的权限还要受到进程的权限掩码的影响的
如果生成的文件权限跟自己设置的不相符合,请看看是否是root模式下执行的
二、函数write
参考:https://linux.die.net/man/2/write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
返回值:若成功,返回已写的字节数;若出错,返回-1
功能:write 函数把buf指针指向的内容写入count 字节数据到文件描述符为fd的文件 。返回值一般总是等于 count,否则就是出错了。
常见的出错原因是磁盘空间满了或者超过了文件大小限制。如果打开文件时使用了 O_APPEND ,则每次写操作都将数据写入文件末尾。
三、函数read
参考:https://linux.die.net/man/2/read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
返回值:返回所读取的字节数;0(读到EOF);-1(出错)。
功能:read 函数会从文件描述符fd的文件中读取count字节到从buf地址开始的缓存中。
参数:
- fd: 要读取数据的文件描述符。
- buf:存放读取的数据缓冲区。
- count: 一次read操作,读多少数量的字节。
以下几种情况会导致读取到的字节数小于 count :
1. 读取普通文件时,读到文件末尾还不够 count 字节。
2. 从终端设备读取时,一般情况下每次只能读取一行。
3. 从网络读取时,网络缓存可能导致读取的字节数小于 count字节。
4. 读取 pipe 或者 FIFO 时,pipe 或 FIFO 里的字节数可能小于 count 。
5. 在读取了部分数据时被信号中断。
总结:读取到的字节数小于想要读取的字节count,说明了源头没有那么多数据可读。
四、函数lseek
参考:https://linux.die.net/man/2/lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
返回值:若成功则返回目前的读写位置,也就是距离文件开头多少个字节。若错误则返回-1。
所有打开的文件都有一个当前文件偏移量(current file offset),以下简称为 cfo。cfo 通常是一个非负整数,用于表明文件开始处到文件当前位置的字节数。读写操作通常开始于 cfo,并且使 cfo 增大,增量为读写的字节数。文件被打开时,cfo 会被初始化为 0,除非使用了 O_APPEND 。使用 lseek 函数可以改变文件的 cfo 。
参数说明:
Offset:偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)。
whence为下列其中一种:(SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2)
- SEEK_SET 将读写位置指向文件头后再增加offset个位移量。
- SEEK_CUR 以目前的读写位置往后增加offset个位移量。
- SEEK_END 将读写位置指向文件尾后再增加offset个位移量。
当whence 值为SEEK_CUR 或SEEK_END时,参数offet允许负值的出现。
举几个例子:
- 将读写位置移到文件开头:
lseek(fd,0,SEEK_SET) - 将读写位置移到文件尾:
lseek(fd,0,SEEK_END) - 取得目前文件位置:
lseek(fd,0,SEEK_CUR)
五、函数close
参考:https://linux.die.net/man/2/close
#include <unistd.h>
int close(int fd);
返回值:若成功,返回0;若出错,返回-1
关闭一个文件时还会释放该进程加在该文件上的所有记录锁。
当一个进程终止时,内核自动关闭它所有的打开文件。很多程序利用了这一功能而不显示地用close关闭打开的文件。
六、示例程序
//open.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FILENAME "hello"
int main()
{
//实际生成的文件的权限还要受到进程的权限掩码的影响的
//如果生成的文件权限跟自己设置的不相符合,请看看是否是root模式下执行的
int fd = open(FILENAME,O_RDWR | O_CREAT,0777);
if(fd < 0)
{
perror("open");
}
printf("open success!\n");
char write_buf[] = "helloworld!\n";
if (write(fd,write_buf,sizeof(write_buf)))
{
perror("write");
}
printf("write success !\n");
//将文件偏移指针重新指向开头
if(lseek(fd,0,SEEK_SET) < 0)
{
perror("lseek");
}
printf("lseek success !\n");
char read_buf[20] = {0};
if (read(fd , read_buf , 20) < 0)
{
perror("read");
}
printf("read success !\n");
printf("read_buf = %s\n",read_buf);
return 0;
}
实验结果:
ubuntu:~/test/170809-IO/open$ gcc open.c -o open
ubuntu:~/test/170809-IO/open$ ./open
open success!
write: Success
write success !
lseek success !
read success !
read_buf = helloworld!
ubuntu:~/test/170809-IO/open$ ls
hello open open.c
ubuntu:~/test/170809-IO/open$ cat hello
helloworld!
更多推荐
所有评论(0)