Linux系统调用文件操作

  • Post author:
  • Post category:linux




Linux中缓存IO的概念:

缓存IO机制中,操作系统会将 I/O 的数据缓存在文件系统的页缓存( page cache )中 ,IO输入输出的数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。

这种机制的

优点

显而易见:

  • 缓存 I/O 使用了操作系统内核缓冲区,在一定程度上分离了应用程序空间和实际的物理

    设备
  • 因为我们的数据被缓存到了页缓存中,所以缓存 I/O 可以减少读盘的次数,直接从页缓存中获取数据,从而提高性能。


    缺点

不能直接在应用程序地址空间和磁盘之间进行数据传输 ,数据拷贝操作所带来的 CPU 以及内存开销是非常大。

Linux系统调用中关于文件的操作,需要包含一些头文件:

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

这些头文件中包含了打开,关闭,创建,读文件,写文件的函数,还有标志位,以及一些宏变量定义。具体需要包含的头文件可以使用man查找帮助。



1、文件描述符

文件描述符是一个非负整数。当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,用

open



creat

返回的文件描述符标识该文件,将其作为参数传送给

read



write



2、open函数

open函数存在两个函数原型,

函数原型1:

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

返回值:若成功为文件描述符,出错返回-1

参数说明:

pathname

即为需要打开的文件名,可以包含文件路径


oflag

参数可用来说明此函数的多个选择项。用下列一个或多个常数进行或运算构成

oflag

参数(这些常数定义在< fcntl.h >头文件中):


  • O_RDONLY

    只读打开。

  • O_WRONLY

    只写打开。

  • O_RDWR

    读、写打开。

    上面的这三个参数是打开方式,只指定一个。

    还可以搭配下面的参数:

  • O_APPEND

    追加到文件末端。

  • O_TRUNC

    如果此文件存在,而且为只读或只写成功打开,则将其长度截短为 0。

  • O_CREAT

    若此文件不存在则创建它。使用此选择项时,需同时说明第三个参数

    mode

    ,用其说明该新文件的存取许可权位。

  • O_EXCL

    如果同时指定了

    O_ CREAT

    ,而文件已经存在,则出错。这可测试一个文件是

    否存在,如果不存在则创建此文件成为一个原子操作。

    例如,使用

    open

    函数创建并打开一个文件:
int open(pathname, O_RDWR|O_CREAT|O_TRUNC, mode) ;

函数原型2:

int open(const char *path, int oflags,mode_t mode);

当我们使用open打开并且创建一个不存在的文件时才会使用原型2,mode参数是为创建的文件添加的权限,可以取值如下:

在这里插入图片描述

其实也可以使用数字组合作为

mode

的值,使用

0777

即为赋予全部权限。



3、creat函数

创建一个新文件

函数原型:

int creat(const char *pathname, mode_t mode) ;

参数说明:


mode

文件的权限,具体可以参考

open

函数。

返回值:若成功为文件描述符,出错返回-1



4、close函数

关闭一个已经打开的文件

需要包含

#include <unistd.h>

头文件,原型:

int close (int filedes)

返回:若成功为 0,若出错为- 1


filedes

为已打开的文件描述符。



5、lseek函数


lseek

函数可以设置当前文件位移量,定位打开的文件。原型:

#include <sys/types.h>
#include <unistd.h>

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

返回:若成功为新的文件位移,若出错为- 1。


filedes

为文件描述符


offset

为偏移量吗,与

whence

相关


whence

说明:

• 若whence是

SEEK_SET

,则将该文件的位移量设置为

距文件开始处

offset 个字节。

• 若whence是

SEEK_CUR

,则将该文件的位移量设置为

其当前值加offset

, offset可为正或负。

• 若whence是

SEEK_END

,则将该文件的位移量设置为

文件长度加offset

, offset可为正或负。



6、read函数

read函数从打开的文件中读数据。

ssize_t read(int fd,void *buf,size_t len)

参数说明:


buf

:读取文件后存放数据的地址

len:读取的字节大小

返回值:读到的字节数,若已到达文件尾,返回0;出错返回-1。



7、write函数

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

参数说明:


buf

:为需要写入数据


count

:写入的数据的大小,单位字节


返回值

:若成功返回已写的字节数,出错返回-1。

综合代码示例:

#include <stdio.h>
#include <stdlib.h>

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

char buf[] = "hello file!";
char buf1[] = "set offset!\n";

int main(int argc, char **argv)
{
    int i;
    int fd;
    if(argc<2)
    {
        printf("no filename to creat!");
    }
    else 
    {
        for(i=1;i<argc;i++)
        {
            if((fd=open(argv[i], O_CREAT|O_RDWR, 777))==-1)
            {
                printf("creat %s failed!\n",argv[i]);           
            }
            else 
            {
                printf("%s creat success!\n",argv[i]);
                if(write(fd, buf, sizeof(buf))>=0)
                {
                    printf("write success!\n");
                    if(lseek(fd, 20, SEEK_SET)>=0)
                    {
                        printf("set offset success!\n");
                        if(write(fd, buf1, sizeof(buf1))>=0)
                        {
                            printf("rewrite success!\n");
                        }
                        close(fd);
                    }                   
                }else{
                    printf("write failed!\n");
                }
            }
        }    
    }
    exit(0);
}

根据main函数传入的参数,先

open

创建并以读写方式打开一个文件,创建成功后写入

"hello file!"

,然后

lseek(fd, 20, SEEK_SET)

设置当前文件偏移量距开始处20,再次写入

set offset success!\n

,结果如下:

在这里插入图片描述

可以看到已经生成了hello.c和a.txt了,内容与我们期望的一致,在开头偏移20处写入了

set offset!\n



在这里插入图片描述

hello.c和a.txt写入的内容完全一致。

在这里插入图片描述

示例2,简单的创建文件并且进行读写:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

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

char *test_string = "import me!\n";
//不能使用字符串常量,否则无法读出数据存入buf
char user_buf1[] = {0};
char user_buf2[]= {0};

int main(int argc, char *argv[])
{
    int fd1, fd2;
    int count;
    int size;
    
    printf("sizeof(test_string) = %d\n", (int)sizeof(test_string));
    printf("strlen(test_string) = %d\n", (int)strlen(test_string));

    /*/home/boy/Unix/*/
    if((fd1 = creat("main.py", 0777)) != -1)
    { 
        count = write(fd1, test_string, 11);//sizeof(test_string)
        if(count < 0)
        {
            printf("write main.py failed!\r\n");
            return -1;
        }
        //close(fd1);
        printf("write main.py success!\n");
        fd1 = open("main.py", O_RDWR); //需要再次打开文件才能读 
        if((count = read(fd1, user_buf1, 11)) == -1)
        {
            printf("read main.py failed!\r\n");
            return -1;
        }
        printf("userbuf1 = %s\n", user_buf1);
        close(fd1);
   } 

   if((fd2 = open("haha.c", O_RDWR | O_CREAT, 0777)) > 0)
   {
        printf("haha.c creat success!\n");
        if((count = read(fd2, user_buf2, sizeof("hello file\n")) < 0 ))
        {
            printf("read haha.c failed!\n");    
            return -1;
        }
        printf("user_buf2 = %s\n", user_buf2);
        close(fd2);
   }
   exit(0);
}

首先从文件

creat

创建文件

main.py

,然后向其写入,写入之后需要重新打开,才能进行读操作,获取文件内容进行验证,接着打开已经存在的文件

haha.c

,读取文件内容,进行验证,haha.c内容如下:

在这里插入图片描述

执行结果:

在这里插入图片描述



版权声明:本文为qq_41790078原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。