Linux系统编程---文件IO

这篇具有很好参考价值的文章主要介绍了Linux系统编程---文件IO。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、系统调用

由操作系统实现并提供给外部应用程序的编程接口(Application Programming Interface,API),用户程序可以通过这个特殊接口来获得操作系统内核提供的服务

系统调用和库函数的区别:

系统调用(系统函数)     内核提供的函数

库调用                         程序库中的函数

错误处理函数

errno用于记录系统的最后一次错误代码,返回一个int值(错误码),在errno.h中定义,不同的错误码表示不同的含义,新建errno.c如下:

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

int main(void)
{
        FILE *fp = fopen("txt","r");//打开一个不存在的文件

        if (NULL == fp)
        {
                printf("fopen failed\n");
                printf("errno:%d\n",errno);//打印errno返回的错误码
                printf("fopen:%s\n",strerror(errno));//使用strerror函数来解释错误码

                return 1;
        }

        return 0;
}

编译再执行可得如下结果:

fopen failed
errno:2
fopen:No such file or directory

虚拟地址空间:

Linux系统编程---文件IO,Linux系统编程,linux

文件描述符

  • 当我们打开文件或者新建文件时,系统会返回一个文件描述符用来指定已打开的文件,这个文件描述符相当于这个已打开文件的标号,操作这个文件描述符就相当于操作这个描述符所指定的文件;
  • 程序运行起来后每个进程都有一张文件描述符的表,标准输入、输出,标准错误输出,对应的文件描述符0、1、2就记录在表中,程序运行起来后这三个文件描述符是默认打开的;

Linux系统编程---文件IO,Linux系统编程,linux

文件描述符是指向一个文件结构体的指针

进程控制块(PCB):本质---结构体

FILE结构体:主要包含文件描述符、文件读写位置、IO缓冲区三部分内容

最大打开文件数:一个进程默认打开文件的个数1024

命令查看:ulimit -a 查看open files 对应值。默认为1024   

可以使用ulimit -n 4096 修改

cat /proc/sys/fs/file-max可以查看该电脑最大可以打开的文件个数。受内存大小影响。

二、常用文件IO函数

1.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);

参数:

        pathname: 欲打开的文件路径名

        flags:文件打开方式: #include <fcntl.h>

                O_RDONLY|O_WRONLY|O_RDWR

                O_CREAT|O_APPEND|O_TRUNC|O_EXCL|O_NONBLOCK ....

        mode:这个参数只有在文件不存在时有效,指新建文件时指定文件的权限

                取值8进制数,用来描述文件的访问权限。 rwx 0664

                创建文件最终权限 = mode & ~umask

返回值:

        成功: 打开文件所得到对应的 文件描述符(整数)

        失败: -1, 设置errno

flags必选项:

O_RDONLY        以只读的方式打开    

O_WRONLY       以只写的方式的打开

O_RDRW           以可读、可写的方式打开

 可选项,和必选项进行位或(|)

O_CREAT                文件不存在则创建文件,使用此选项时需使用mode说明文件的权限
O_EXCL                   如果同时指定了O_CREAT,且文件已经存在,则出错
O_TRUNC                如果文件存在,则清空文件内容
O_APPEND              写文件时,数据添加到文件末尾
O_NONBLOCK         对于设备文件,以O_NONBLOCK方式打开可以做非阻塞I/O

2.close函数

#include <unistd.h>

int close(int fd);
功能:
        关闭已打开的文件
参数:
        fd:文件描述符,open()的返回值
返回值:
        成功:0
        失败:-1,并设置errno

代码示例:

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

int main(int argc,char *argv[])
{
        int fd;
        open("./dict.cp",O_RDONLY | O_CREAT | O_TRUNC,0644);//rw-r--r--
                
        printf("fd = %d\n",fd);

        close(fd);

        return 0;
}

3.write函数

#include <unistd.h>


ssize_t write(int fd, const void *buf, size_t count);
功能:
        把指定数目的数据写到文件(fd)
参数:
        fd:文件描述符
        buf:数据首地址
        count:写入数据的长度(字节)
返回值:

        成功:实际写入数据的字节个数
        失败:-1

4.read函数

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
功能:
        把指定数目的数据读到内存(缓冲区)
参数:
        fd:文件描述符
        buf:内存首地址
        count:读取的字节个数
返回值:
        成功:实际读取到的字节个数
        失败:-1

 用read和write实现一个copy函数:

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

int main(int argc,char *argv[])
{
        char buf[1024];
         
        int n = 0;

        int fd1 = open(argv[1],O_RDONLY);//read
        if (fd1 == -1){
                perror("open argv1 error");
                exit(1);
        }

        int fd2 =open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0644);
        if (fd2 == -1){
                perror("open argv2 error");
                exit(1);
        }


        while((n = read(fd1,buf,1024)) != 0){
                if (n < 0){
                        perror("read error");
                        break;  
                }
                write(fd2,buf,n);
        }

        close(fd1);
        close(fd2);

        return 0;
}

5.lseek函数

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


off_t 1seek(int fd,off_t offset,int whence);

功能:
       改变文件的偏移量(读写位置)

参数:
        fd:文件描述符

        offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了文件末尾,再次写入时将增大文件尺寸。


        whence:其取值如下:
                SEEK_SET:从文件开头移动offset个字节

                SEEK_CUR:从当前位置移动offset个字节            

                SEEK__END:从文件未尾移动offset个字节

返回值:
        若1seek成功执行,则返回新的偏移量

        如果失败,返回-1

lseek允许超过文件结尾设置偏移量,文件会因此被拓展。

使用lseek获取文件大小:

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

int main(int argc,char *argv[])
{
        int fd = open(argv[1],O_RDWR);
        if (fd == -1)
        {
                perror("read error");
                exit(1);
        }

        int lenth = lseek(fd,0,SEEK_END);//获取文件大小
        //int lenth = lseek(fd,107,SEEK_END);//扩展文件大小
        printf("file size:%d\n",lenth);

        //write(fd,"a",1);

        close(fd);

        return 0;
}

应用场景:

1. 文件的“读”、“写”使用同一偏移位置。

2. 使用lseek获取文件大小(返回值接收)

3. 使用lseek拓展文件大小:要想使文件大小真正拓展,必须【引起IO操作】。

使用 trumcate 函数,直接拓展文件。

int ret =truncate("dict.cp”,250):

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

int main(int argc,char *argv[])
{
        //open/lseek(fd,249.SEED_END)/write(fd,"\0",1);
        int ret = truncate("dict.cp",250);
        printf("ret = %d\n",ret);

        return 0;
}

三、系统调用和库函数比较---预读入缓输出

Linux系统编程---文件IO,Linux系统编程,linux

fputc/fgetc实现:

int main(void){
    FILE *fp,*fp_out;
    int n = 0;

    fp = fopen( " hello.c" , "r");
    if(fp == NULL)
    {
        perror( " fopen error" );
        exit( 1);
    }

    fp_out = fopen ( "hello.cp" ,"w" );
    if(fp_out =NULL)
    {
        perror( "fopen error" );
    exit(1);
    }

    while((n = fgetc(fp))!= EOF)
    {
        fputc(n, fp_out) ;
    }

    fclose(fp);
    fclose(fp_out);
    return 0;
}

read/write实现:

int main( int argc, char *argv[])
{
    char buf[ 1];

    int n = 0;

    int fd1 = open(argv[1],0_RDONLY);
    int fd2 = open(argv[2],O_RDWR|0_CREAT|0_TRUNC,0664);

    while((n = read (fd1,buf,1)) != 0)
    {
        write(fd2, buf, n);
    }

    close(fd1);
    close(fd2);
    return 0;
}

结果表明:read/write速度慢

原因分析:

  • read/write这块,每次写一个字节,会疯狂进行内核态和用户态的切换,所以非常耗时。
  • fgetc/fputc,有个缓冲区,4096,所以它并不是一个字节一个字节地写,内核和用户切换就比较少

预读入,缓输出机制。所以系统函数并不是一定比库函数牛逼,能使用库函数的地方就使用库函数。

  • 标准IO函数自带用户缓冲区,系统调用无用户级缓冲。系统缓冲区是都有的。

四、阻塞和非阻塞

产生阻塞的场景:读设备文件。读网络文件的属性。(读常规文件无阻塞概念)

/dev/tty -- 终端文件。

open("/dev/tty", O_RDWR | O_NONBLOCK) --- 设置 /dev/tty 非阻塞状态。(默认为阻塞状态)

更改非阻塞读取终端——超时设置

#include <unistd.h>  
#include <fcntl.h>  
#include <stdlib.h>  
#include <stdio.h>  
#include <errno.h>  
#include <string.h>  
  
#define MSG_TRY "try again\n"  
#define MSG_TIMEOUT "time out\n"  
  
int main(void)  
{  
    //打开文件
    int fd, n, i;  
    fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);  
    if(fd < 0){  
        perror("open /dev/tty");  
        exit(1);  
    }  
    printf("open /dev/tty ok... %d\n", fd);  
  	
    //轮询读取
    char buf[10];  
    for (i = 0; i < 5; i++){  
        n = read(fd, buf, 10);  
        if (n > 0) {                    //说明读到了东西  
            break;  
        }  
        if (errno != EAGAIN) {          //EWOULDBLOCK    
            perror("read /dev/tty");  
            exit(1);  
        } else {  
            write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));  
            sleep(2);  
        }  
    }  
  	//超时判断
    if (i == 5) {  
        write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));  
    } else {  
        write(STDOUT_FILENO, buf, n);  
    }  
  
    //关闭文件
    close(fd);  
    return 0;  
}  

五、传入传出参数

传入参数:

        1. 指针作为函数参数。

        2. 同常有const关键字修饰。

        3. 指针指向有效区域, 在函数内部做读操作。

传出参数:

        1. 指针作为函数参数。

        2. 在函数调用之前,指针指向的空间可以无意义,但必须有效。

        3. 在函数内部,做写操作。

        4。函数调用结束后,充当函数返回值。

传入传出参数:

        1. 指针作为函数参数。

        2. 在函数调用之前,指针指向的空间有实际意义。

        3. 在函数内部,先做读操作,后做写操作。

        4. 函数调用结束后,充当函数返回值。文章来源地址https://www.toymoban.com/news/detail-850074.html

到了这里,关于Linux系统编程---文件IO的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】文件周边001之系统文件IO

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》 《数据结构》 《蓝桥杯试题》 《LeetCode刷题笔记》 《实训项目》 《C++》 《Linux》《算法》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.C语言文件IO 1.1C语言文件IO接口汇总  1.2当前路径指的是什么?  1.3stdi

    2024年01月24日
    浏览(34)
  • 【Linux】基础IO_文件系统

     环境:centos7.6,腾讯云服务器 Linux文章都放在了专栏:【 Linux 】欢迎支持订阅 相关文章推荐: 【Linux】冯.诺依曼体系结构与操作系统 【C/进阶】如何对文件进行读写(含二进制)操作? 【Linux】基础IO_文件操作 【Linux】基础IO_文件描述符与重定向 在前文我们所讲的都是

    2024年02月05日
    浏览(32)
  • 【Linux】基础IO----系统文件IO & 文件描述符fd & 重定向

    作者:დ旧言~ 座右铭:松树千年终是朽,槿花一日自为荣。 目标:了解在Linux下的系统文件IO,知道什么是文件描述符,什么是重定向 毒鸡汤:白日莫闲过,青春不再来。 专栏选自:Linux初阶 望小伙伴们点赞👍收藏✨加关注哟💕💕 最早我们在C语言中学习关于如何用代码

    2024年04月14日
    浏览(36)
  • 【Linux】基础IO——系统文件IO&&fd&&重定向

    大家好我是沐曦希💕 空文件,也要在磁盘占据空间,因为文件也有属性,属性也属于数据,需要空间进行存储。所以 文件包括内容和属性 所以 对文件操作就是对内容或者对属性进行操作,或者对内容和属性进行操作。 文件具有唯一性,所以在 标定一个文件时候,必须使用

    2024年02月02日
    浏览(33)
  • Linux之基础IO文件系统讲解

    在C语言中,读文件和写文件是常见的操作,用于从磁盘读取数据到内存或将数据从内存写入磁盘文件中。这些操作需要使用标准库中的文件I/O函数。下面我将详细解释如何在C语言中进行读文件和写文件操作,并举例说明。 在C语言中,读取文件的过程涉及以下步骤: 打开文

    2024年02月11日
    浏览(29)
  • 【Linux】基础 IO(文件系统 & inode & 软硬链接)-- 详解

    1、前言 我们一直都在说打开的文件,磁盘中包含了上百万个文件,肯定不可能都是以打开的方式存在。其实文件包含打开的文件和普通的未打开的文件,下面重点谈谈未打开的文件。 我们知道打开的文件是通过操作系统被进程打开,一旦打开,操作系统就要维护多个文件,

    2024年03月21日
    浏览(35)
  • 【Linux】基础IO——文件系统|软硬链接|动静态库

    基于上篇博客所写到的文件各种操作都是基于被打开文件所进行操作的,那么如果一个文件没有被打开它存在哪里呢?这个答案毫无疑问肯定是存在于磁盘上的。那么,对于一个没有打开的文件(也就是磁盘文件)我们应该如何理解呢? 这里我们所要讲的磁盘是机械硬盘、即

    2024年02月04日
    浏览(33)
  • Linux 系统调用IO口,利用光标偏移实现文件复制

    用系统调用IO函数实现从一个文件读取最后2KB数据并复制到另一个文件中,源文件以只读方式打开,目标文件以只写的方式打开,若目标文件不存在,可以创建并设置初始值为0664,写出相应代码,要对出错情况有一定的处理,并能够让用户自行输入要复制的文件名。 IO口即指

    2024年02月08日
    浏览(28)
  • Linux文件(系统)IO(含动静态库的链接操作)

    fopen打开文件,fclose关闭文件 fwrite操作(写文件) fwrite函数从 ptr 里将 nitems 个大小为 size 字节的数据写进定 stream 里 hello_w.c 文件 这里我们将会在此路径得到一个写有 5 行 hello fopen 的 myfile.txt 文件,如下gif: fread操作(写文件) fread 不会在字符串末尾添加 null 终止符( \\0

    2024年04月14日
    浏览(35)
  • 【Linux后端服务器开发】基础IO与文件系统

    目录 一、基础IO 1. C语言文件读写 2. 标志位传参 3. C语言与系统调用关系 二、文件系统 1. 文件描述符 2. 输入输出重定向 文件调用 库函数接口: fopen、fclose、fwrite、fread、fseek 系统调用接口:open、close、write、read、lseek r/w/a :读/写/追加 若打开的文件不存在,“r”报错,“

    2024年02月15日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包