Linux中有关文件的操作

目录

文件IO

文件描述符

open函数和close函数

    open函数

        close函数

read函数和write函数

        read函数

        write函数

lseek函数

fcntl函数

dup和dup2函数

dup函数

dup2函数

perror和strerror函数

perror函数

strerror函数

stat/lstat/fstat函数


文件IO

文件描述符

        以文件描述符指代打开的文件,非负整数。一个进程启动之后,会默认打开三个文件描述符:0-标准输入,1-标准输出,2-标准错误

        #define STDIN_FILENO     0

        #define STDOUT_FILENO  1

        #define STDERR_FILENO  2

        操作系统为每个进程维护一个文件描述符表,新打开返回文件描述符表中未使用的最小文件描述符,调用open函数可以打开或创建一个文件,得到一个文件描述符。

open函数和close函数

    open函数

        函数描述:

                打开或创建一个文件

        函数原型:

                int open(const char* pathname,int flags);

                int open(const char* pathname,int flags,mode_t mode);

        函数参数:

                pathname:要打开或创建的文件路径

                flags:文件访问方式 ,有一些常数值可供选择,可以同时选择多个,用按位或(|)连接起来

                        必选项:以下三个常数中必须指定一个,且只允许指定一个

                                O_RDONLY:只读打开

                                O_WRONLY:只写打开

                                O_RDWR:可读可写打开

                        常用选项:可以同时指定0个或多个,和必选项按位或起来使用

                                O_APPEND:追加,如果文件已经有内容了,这次打开文件所写的数据附加到文件的末尾,而不是覆盖原来的内容。

                                O_CREAT:若文件不存在则创建它,使用此选项需要提供第三个参数mode,表示该文件的访问权限。

                                O_EXCL:如果同时指定了O_CREAT,并且文件存在,则返回出错

                                O_TRYNC:如果文件已经存在,将其长度截断为0字节。

                                O_NONBLOCK:设置非阻塞模式

                                        普通文件默认是不会发生阻塞的,内核缓存区保证了普通文件I?O不会阻塞,打开普通文件一般会忽略此参数。

                                        设备、管道和套接字默认是阻塞的,以O_NONBLOCK方式打开可以做非阻塞I/O(Nonblock I/O)

                函数返回值:

                        成功:返回一个最小且未被占用的文件描述符

                        失败:返回-1,并设置errno值

        close函数

                函数描述:

                        关闭文件

                函数原型:

                        int close(int fd)

                函数参数:

                        fd:文件描述符

                函数返回值:

                        成功:返回0

                        失败:返回-1,并设置errno值

        当一个进程终止时,内核对该进程所有尚为关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在终止时内核也会自动关闭它打开的所有文件。但是对于一个长年累月运行的程序(比如说网络服务器),打开的文件描述符一定记得要关闭,否则随着打开的文件越多,会占用大量的文件描述符和系统资源。

例如用open函数来创建一个文件

其中io.c的代码如下:

#include<stdio.h>                                                                     #include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
int main(int argc, char* argv[])
{
   int fd=open("./a.txt",O_RDWR | O_CREAT,0664);
   printf("fd = %d",fd);
   close(fd);
   return 0;
}

执行这段代码,可以看到得到这个文件的文件描述符等于3,同时在当前目录下生成了一个a.txt文件。

read函数和write函数

        read函数

                函数描述:
                        从打开的设备或文件中读取数据

                函数原型:

                        ssize_t read(int fd,void *buf,size_t count);

                函数参数:

                        fd:文件描述符

                        buf:读取的数据保存在缓冲区buf中

                        count:buf缓冲区存放的最大字节数

                函数返回值:

                        >0:读取到的字节数

                        =0:读取文件完毕

                        -1:读取出错,并设置errno

        例如先向a.txt中写入hello word中间有换行,在read函数里面读取,运行结果如下图

     read.c的代码如下:
 

#include<stdio.h>                                                                     
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h> 
int main(int argc, char* argv[])
{
    int fd=open("./a.txt",O_RDONLY);
    char buf[1024];
    int ret=read(fd,buf,sizeof(buf));
    buf[ret]='\0';
    printf("buf = %s",buf);
    close(fd);
    return 0;
}

        write函数

                函数描述:

                        向打开的设备或文件中写入数据

                 函数原型:

                        ssize_t write(int fd,const void* buf,size_t count);

                函数参数:

                        fd:文件描述符

                        buf:缓冲区,要写人文件或设备的数据

                        count:buf中数据的长度

                函数返回值:

                        成功:返回写入的字节数

                        失败:返回-1并设置errno

例如向a.txt中写入一个字符串,这里以追加的形式写入,然后查看a.txt中的内容,发现成功写入到a.txt中

write.c的代码如下

#include<stdio.h>                                                                     
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>

int main(int argc, char* argv[])
{
    int fd=open("a.txt",O_RDWR | O_APPEND);
    char buf[1024]="write sucessful";
    int ret=write(fd,buf,sizeof(buf));
    return 0;
}

   

lseek函数

        所有打开的文件都有一个文件偏移量(current file offset),也叫读写偏移量和指针。文件偏移量通常是一个非负整数,用于文件开始出到文件当前位置的字节数(下一个read()和write()操作的文件起始位置)。文件的第一个字节的偏移量为0。

        文件打开时,会将文件偏移量设置为指向文件开始(使用O_APPEND除外),以后每次read()和write()会自动对其调整,以指向已读或已写数据的下一个字节。因此连续的read()和write()将按顺序递进,对文件进行操作。

        使用lseek函数可以改变文件的偏移量。

        函数描述:

                移动文件指针

        头文件:

                #include<sys/type.h>

                #include<unistd.h>

        函数原型

                off_t lseek(int fd,off_t offset,int whence);

        函数参数:

                fd:文件描述符

                offset:字节数,以whence参数为基点解释offset

                whence:解释offset的基点

                        SEEK_SET:文件偏移量设置为offset

                        SEEK_CUR:文件偏移量设置当前文件偏移量加上offset,offset可以为负数

                        SEEK_END:文件偏移量设置为文件长度加上offset,offset可以为负数

        函数返回值

                若lseek成功执行,则返回新的偏移量

                若失败返回-1,并设置errno

lseek函数常用操作:

        文件移动到头部:

                lseek(fd,0,SEEK_SET);

        获取文件指针当前的位置

                int len=lseek(fd,0,SEEK_CUR);

        获取文件的长度

                int len=lseek(fd,0,SEEK_END);

        实现文件扩展:

                lseek(fd,n,SEEK_END);//扩展n个字节

                write();//扩展后需要执行一次写操作才能扩展成功

下面是一段对lseek函数应用的代码

int fd=open("./a.txt",O_RDWR);
char buf[1024];
int read_count=read(fd,buf,sizeof(buf));
//获取当前偏移量
int offset=lseek(fd,0,SEEK_CUR);
printf("current file offset=%d\n",offset);
//获取文件长度
int len=lseek(fd,0,SEEK_END);
printf("current file length=%d\n",len);
//文件指向头部
lseek(fd,0,SEEK_SET);
//从文件尾部开始向后扩展1000个字节
lseek(fd,1000,SEEK_END);
write(fd," ",1);//为了扩展成功,随便写入一个数据
len=lseek(fd,0,SEEK_END);
printf("current file length=%d\n",len);

fcntl函数

        函数描述:

                对打开的文件描述符进行控制,如获取或修改打开文件的状态的标志(对应open函数的的flags参数)

        函数原型:

                int fcntl(int fd,int cmd,.../*ar*/);

        函数参数:        

                fd:要控制的文件描述符

                cmd:不同值对应不同的操作

                        cmd为F_GETFL:获取文件描述符的flag值

                        cmd为F_SETFL:设置文件描述符的flag值

                        cmd为F_DUPFD:复制文件描述符,与dup功能相同

        函数返回值(取决于cmd)

                成功 :

                           若cmd为F_DUPFD,返回一个新的文件描述符        

                            若cmd为F_GETFL,返回文件描述符的flags值

                           若cmd为F_SETTFL,返回0

                失败返回-1,并设置errno值

        

dup和dup2函数

dup函数

        函数描述:

               复制文件描述符,返回复制后的文件描述符

        函数原型

                int dup(int oldfd);

        函数参数:

                oldfd:要复制的文件描述符

        函数返回值:

                成功:返回最小且没有被占用的文件描述符

                失败:返回-1,并设置errno值

int fd=open("a.txt",O_RDWR);
printf("fd=%d\n",fd);
int newfd=dup(fd);
printf("newfd=%d\n",newfd);
write(fd,"oldfd",6);
write(newfd,"newfd\n",6);

        此时,文件描述符fd和oldfd都是指向的a.txt文件,所以写入的字符全部在a.txt中

dup2函数

        函数描述:

                复制文件描述符,返回复制后的文件描述符

        函数原型:

                dup2(int oldfd,int newfd);

        函数参数:

                oldfd:原来的文件描述符

                newfd:复制后的新的文件描述符,如果newfd已经指向了一个文件,先关闭原来打开的文件,再将newfd指向oldfd指向的文件。

        函数返回值:

                成功:将oldfd复制给newfd,两个文件描述符指向同一个文件

                失败:返回-1,设置errno值

复制前没有指向文件

int fd=open("a.txt",O_RDWR);
printf("fd=%d\n",fd);
int newfd=dup2(fd,10);
printf("newfd=%d\n",newfd);
write(fd,"oldfd",6);
write(newfd,"newfd",6);

        此时,文件描述符3和10都是指向的a.txt,所以对文件描述符3和文件描述符10进行写入,都是写入到a.txt中。

复制前指向文件

int fda=open("a.txt",O_RDWR);
int fdb=open("b.txt",O_RDWR);
dup2(fda,fdb);
write(fdb,"newfd\n",6);

让指向b.txt的文件描述符指向了a.txt,再对其进行写入,写到的是a.txt中

perror和strerror函数

        许多系统调用和库函数失败时设置外部变量来指明失败的原因。许多不同函数库都把这个变量用做报告错误的标准方法。

        注意:程序必须在函数报错出错之后立刻检查errno变量,因为它可能马上被下一个函数调用所覆盖,即使下一个函数没有出错,也会覆盖这个变量。

        系统调用失败后,常见的做法是根据errno打印错误消息。

perror函数

        函数描述:

                打印errno值相对应的报错信息

        头文件

                #include<stdio.h>

        函数原型:

                void perror(const char* s);

        函数参数

                s:一个字符串,用于在输出报错信息前添加一些其他的信息

例如打开aaa.txt,因为没有这个文件,所以会执行perror函数。

int fd=open("./aaa.txt",O_RDWR);
if(fd==-1){
    perror("打开文件失败");
}

strerror函数

        函数描述:

                将错误码转换成相应的错误信息字符串

        头文件:

                #include<string.h>

        函数原型:

                char *strerror(int errnum);

        函数参数:

                errnum:错误码

        函数返回值

                返回包含错误信息的字符串

例如

#include<errno.h>
int fd=open("./aaa.txt",O_RDWR);
if(fd==-1){
    printf("打开文件失败:%s\n",strerror(errno));
}

stat/lstat/fstat函数

        函数描述:

                获取文件属性,lstat和stat的区别在于如果文件是符号链接,返回的文件属性是符号链接本身。fstat则是指定文件描述符获取文件信息。

        头文件:

                #include<sys/stat.h>

        函数原型:

                int stat(const char* pathname,struct stat* statbuf);

                int lstat(const char* pathname,struct stat* statbuf);

                int fstat(int fd,struct *statbuf);

        函数参数:

                pthname:要获取属性的文件路径

                statbuf:传出参数,指向struct stat结构体的指针,用于存储获取到的文件信息

                fd:要获取属性的文件描述符

        函数返回值:

                成功返回0

                失败返回-1

struct stat{
    dev_t    st_dev;        //文件所在设备号
    ino_t    st_ino;        //inode号
    mode_t   st_mode;       //文件类型及权限
    nlink_t  st_nlink;      //硬链接计数
    uid_t    st_uid;        //拥有者
    gid_t    st_gid;        //所属用户组
    dev_t    st_rdev;       //如果是设备文件时有效,为设备号
    off_t    st_size;       //文件的字节数
    blksize_t st_blksize;   //文件系统中block的大小
    blkcnt_t st_blocks;     //文件所占扇区数量
    time_t    st_atime;     //文件最后访问时间
    time_t    st_mtime;     //最后修改时间
    time_t    st_ctime;     //最后改变状态时间
}
#include<sys/stat.h>
#include<time.h>
struct stat file info;
stat("./a.txt",&file info);
printf("st ino=ldn",file info.st ino);
printf("st mode = dn",file info.st mode);
printf("st uid = gd\n",file info.st uid);
printf("st gid = &d\n",file info.st gid);
printf("st size =ldn",file info.st size);
printf("st mtim =s\n",ctime(&file info.st mtime)):
if(file info.st mode &S IRUSR){
    printf("文件所有者有读权限");
if((file info.st mode &S IEMT)==S IFREG)
    printf("该文件是普通文件\n");
if(s ISREG(file info.st mode)){
    printf("该文件是普通文件\n");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值