文件系统之基本函数操作

在linux下用文件描述符来表示设备文件和普通文件。文件描述符是一个整型的数据,所有对文件的操作都得通过文件描述符来实现。文件描述符是文件系统中连接用户空间和内核空间的枢纽。当打开或创建一个文件时,内核空间创建相应的结构,并生成一个整型的变量传递给用户空间的对应进程。进程用这个文件描述符来对文件进行操作。用户空间对文件进行操作时,比如读、写一个文件时,将文件描述符作为参数传递给read或write,读写函数的系统调用到达内核时,内核解析作为文件描述符的整型变量,找出对应的设备文件,运行相应的函数,并返回用户空间结果。

文件描述符的范围是0~OPEN_MAX,是一个非负整数,它是一个索引值,指向在内核中每个进程所打开的文件记录表,同时它也是一个有限的资源,在使用完毕后需要及时释放。文件描述符的值仅仅在同一个进程中有效,即不同的进程的文件描述符,同一个值很可能描述的不是同一个文件。

Linux系统中有3个已经分配的文件描述符,即标准输入(stdin,对应的文件描述符的值为0)、标准输出(stdout,其对应的文件描述符的值为1)和标准错误(stderr,其对应的文件描述符的值为2)。

open()函数、create()函数:打开文件、创建新文件

函数原型为:

#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);

       根据用户设置的标志flags和模式mode在路径pathname下建立或打开一个文件。open()函数打开pathname指定的文件,当函数成功执行时,返回一个整型的文件描述符。执行出错返回-1pathname所指定的为一个字符串变量,这个变量的长度在不同的系统下其最大长度有区别,通常是1024个字节。当所给的路径长度大于1024字节时,系统会对字符串进行截断,仅选择最前面的字节进行操作。

         函数的参数flags用于设置文件打开后允许的操作方式,可以为只读(O_RDONLY)、只写(O_WRONLY)和读写(O_RDWR)进行读写。在打开文件时必须指定这三种模式之一。三个模式中O_RDONLY通常定义为0O_WRONLY定义为1O_RDWR定义为2

         除此之外,flags的选项还有一些可选的参数:

         O_APPEND      使每次对文件进行写操作时都追加到文件的尾端

         O_CREAT         如果文件不存在则创建,当使用此选项时,第三个参数mode需要同时设                                   定,用来说明新文件的权限

         O_EXCL             查看文件是否存在。如果同时指定了O_CREAT,而文件已经存在时,会返                                   回错误。用这种方法可以安全地打开一个文件。

         O_TRUNC        将文件长度截断为0。如果文件存在,并且成功打开,则会将其长度截断                                   0

         使用O_TRUNC选项,即对需要清空的文件进行归零操作。O_NONBLOCK打开文件为非阻塞方式,如果不指定此选项,默认打开方式为阻塞方式,即对文件的读写操作需要等待操作的返回状态。其中mode参数用户表示打开文件的权限,mode的使用必须结合flagsO_CREAT使用,否则是无效的。

mode参数的值和意义:

选项

意义

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

其他用户(文件所有者)有执行的权限

以上值的5位数字的含义为:

1位表示设置用户ID

2位表示设置组用户ID

3位表示用户自己的权限

4位表示组用户的权限

5位表示其他用户的权限

例如,要创建一个用户可读(4)、可写(2)、可执行(1),组用户没有权限,其他用户可读可执行的文件,并设置用户ID位,则值为10705

open()函数示例:在当前目录下打开一个名为test.txt文件。

创建一个openeg.c的文件

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

int main()
{
    int fd=-1;          //文件描述符声明
    char filename[]="test.txt";     //要打开的文件名
    fd=open(filename,O_RDWR);       //打开文件的方式为可读可写方式
    if(fd == -1)            //打开失败
    {
        printf("Open file %s failed !\nfd:%d\n",filename,fd);
    }
    else
    {
        printf("Open file %s succeed !\nfd:%d\n",filename,fd);
    }
    return 0;
}

之后,再执行编译

命令:gcc openeg.c -o openeg

最后,执行

         文件打开成功了,显示文件描述符的值为3。在Linux下如果之前没有其他文件打开,第一个调用打开文件成功的程序,返回的描述值为最低值,即3。因为值为012的文件描述符分配给了系统,表示标准输入、标准输出和标准错误。在Linux在可以直接对这3个描述符进行操作,而不用打开、关闭。

         open()函数不仅可以打开一般的文件,而且可以打开设备文件,例如“dev/sdal”文件,即磁盘的第一个分区。

         O_CREAT可以创建文件,与O_EXCL结合使用可以编写容错的程序。例如:创建openeg_1.c文件并编译执行

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
int main()
{
     int fd=-1;          //文件描述符声明
     char filename[]="test.txt";     //要打开的文件名        
     fd=open(filename,O_RDWR | O_CREAT | O_EXCL,S_IRWXU);       //打开文件的方式为可读可写方式
     if(fd == -1)            
     {
         printf("Open file %s has already exits !Reopen it !\n",filename);
         fd = open(filename,O_RDWR);         
         printf("fd:%d\n",fd);
     }
     else                
     {
         printf("Open file %s succeed !\nfd:%d\n",filename,fd);
     }
     return 0;
}

如果将openeg_1.c文件里的要打开的文件写为test1.txt,则会出现如下结果:

test1.txt文件不存在,则创建

         创建文件的函数除了可以在打开时创建外还可以使用creat()函数来创建一个新文件,函数原型为:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>	
int creat(const char* pathname, mode_t mode);

函数creat()函数等于一个open()的缩写版本,等价于

open(const char* pathname,(O_CREAT | O_WRONLY | O_TRUNC));

create()的返回值与open()一样。

 

close()函数:关闭文件函数

         close()函数关闭一个打开的文件,即关闭之前打开文件所占用的资源。此函数实际上是关闭一个文件描述符,关闭以后此文件描述符不再指向任何文件,从而此描述符可以再次使用。当函数执行成功时返回0,错误时返回-1

函数原型为:

#include <unistd.h>
int close(int fd);

在打开文件之后,必须关闭文件。如果一个进程中没有正常关闭文件,在进程退出的时候系统会自动关闭打开的文件。在打开文件的时候,系统给文件分配的描述符是当前进程中最小的文件描述符的值,这个值一般情况下时递增的,而每个进程中的文件描述符的数量是有大小限制的。如果在一个进程中频繁地打开文件而又忘记关闭文件,当系统的文件描述符达到最大限制地时候,就会因为没有文件描述符可以分配而造成文件打开失败。如果只打开文件而不关闭,那么当文件描述符地值为1024的时候,由于超过了系统的可分配最大值,所以造成文件打开错误。

 

read()函数:读取文件函数,从打开的文件中读取数据,用户可以对读入的数据进行操作。

函数原型为:

#include <unistd.h>
ssize_t read(int fd,void* buffer,size_t count);

read()函数从文件描述符fd对应的文件中读取count字节的数据,放到buffer开始的缓冲区。如果count的值为0read()函数返回0,不进行其他操作;如果count值大于SSIZE_MAX,结果不可预知。

         read()函数执行成功时,函数返回1,执行发生错误时,函数返回-1。如果已经读取到文件的结尾,则返回0.返回值的类型为ssize_t类型,这种类型的数据是一个符号数,实际使用时可以返回intlong型数据。

         read()函数中的参数fd是一个文件描述符,通常是open()函数或者creat()函数成功执行后的返回值;参数buffer是一个指针,指向缓冲区地址的开始位置,读入的数据将保存在此缓冲区中;参数count表示每次要读取的字节数,通常用这个变量来表示缓冲区的大小,因此,count的值不要超过缓冲区的大小,否则会造成缓冲区的溢出。

         在实际使用read()函数时,不一定能够读取够count请求读取的字节数的数据,在以下几种情况下,实际读取到的数据小于count请求读取的字节数。

1)读取普通文件时,文件中剩余的字节数小于count

2)从终端设备读取数据时,其默认的长度小于count。例如终端缓冲区的大小为256count请求字节数为1024

3)从网络读取数据时,缓冲区大小可能小于读取请求的数据大小。

 

read()函数示例:从demo.txt中读取数据

demo.txt文件的内容是:

openeg.c文件的内容:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
 
int main()
{
     int fd=-1;      //文件描述符
     char filename[]="demo.txt";
     int i;
 
     char buffer[10];
     ssize_t size=-1;
     
     fd=open(filename,O_RDONLY);
     if(-1 == fd)    //文件不存在则创建
     {
         printf("打开文件%s失败,fd=%d\n",filename,fd);
     }   
     else
     {
         printf("文件%s打开成功,fd=%d\n",filename,fd);
     }   
 
     while(size)
     {
         size=read(fd,buffer,10);
         if(-1 == size)
         {
             close(fd);
             printf("文件读取出现错误!\n");
             return -1;
         }
         else
         {
             if(size > 0)
             {
                  printf("读取到%d字节数据:",size);
                  for(i=0;i<size;i++)
                  {
                      printf("%c",*(buffer+i));
                  }
                  printf("\n");
             }
             else
             {
                 printf("文件读取完毕!\n");
             }
         }
     }
     return 0;
}

编译并运行:

gcc readeg.c -o readeg

 

write()函数:写文件函数。向打开的文件中写入数据,将用户的数据保存到文件中。

函数原型为:

#include <unistd.h>
ssize_t write(int fd,const void* buffer,size_t count);

write()函数向文件描述符为fd的文件中写入数据,数据大小由count指定,buffer为要写入数据的指针,write()函数执行成功后返回成功写入文件的数据的字节数。当操作对象是普通文件时,写文件的位置从当前开始,操作成功后,写的位置会增加写入字节数的值。如果在写文件的时候指定了O_APPEND选项,每次写操作之前,会将写操作的位置移到文件的结尾处。

write()函数示例:向demo.txt文件中写入“ABC

demo.txt

writeeg.c

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
 
int main()
{
       int fd=-1;      //文件描述符
       char filename[]="demo.txt";
       int i;
       ssize_t size=-1;
       char buffer[]="ABC";
       fd=open(filename,O_RDWR);
       if(-1 == fd)
       {
           printf("文件%s打开失败,fd=%d\n",filename,fd);
       }
       else
       {
           printf("文件%s打开成功,fd=%d\n",filename,fd);
       }
       size=write(fd,buffer,strlen(buffer));
       printf("写入文件%s%d字节数据!\n",filename,size);
       close(fd);
       return 0;
}

编译并运行结果:

gcc writeeg.c -o writeeg

 

以上即是我所整理的关于文件操作的个别简单函数,剩下的会在以后更新~

特别说明,此博文的部分内容和代码来源于宋敬彬,孙海滨等编著的Linux网络编程一书,在此表示感谢!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值