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、文件描述符

文件描述符是一个非负整数。当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,用opencreat返回的文件描述符标识该文件,将其作为参数传送给readwrite

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内容如下:

在这里插入图片描述

执行结果:

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值