首页 > 系统相关 >在Linux下的文件IO的使用(一)

在Linux下的文件IO的使用(一)

时间:2022-09-25 19:44:24浏览次数:48  
标签:文件 STR int char fd IO Linux include

系统调用

系统调用: 操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务  在这里插入图片描述

为什么用户程序不能直接访问系统内核提供的服务为了更好地保护内核空间,将程序的运行空间分为 内核空间用户空间(也就是常称的内核态用户态),它们分别运行在不同的级别上 在逻辑上是相互隔离的 。 因此 用户进程在通常情况下不允许访问内核数据 ,也无法使用内核函数,它们只能在用户空间操作用户数据 ,调用用户空间的函数 。
在这里插入图片描述进行系统调用时 ,程序运行空间从用户空间进入内核空间 ,处理完后再返回到用户空间系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断机制向内核提交请求,以获取内核服务的接口 。在实际使用中程序员调用的通常是用户编程接口 API 。
在这里插入图片描述Linux 中的系统调用包含在 Linux 的 libc 库中,通过标准的 C 函数调用方法可以调用系统命令相对 API 更高了一层,它实际上是一个可执行程序,它的内部调用了用户编程接口 (API )来实现相应的功能 。在这里插入图片描述内核如何区分和引用特定的文件

通过文件描述符 。文件描述符是一个非负的整数 ,是一个索引值 ,指向在内核中每个进程打开文件的记录表 。 当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描
述符;当需要读写文件时 也需要把文件描述符作为参数传递给相应的函数 。是一个非负的整数(通常是小整数),posix标准要求每次打开一个文件,必须使用当前进程最小的文件描述符号码,因此打开一定是3.
一个进程启动时 通常会打开 3 个文件:

标准输入标准输入标准出错
STDIN_FILENOSTDOUT_FILENOSTDERR_FILENO
stdinstdoutstderr
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define MSG_STR "hello world\n"
int main(int argc, char **argv)
{
   printf("%s",MSG_STR);
   fputs(MSG_STR,stdout);
   write(STDOUT_FILENO,MSG_STR,strlen(MSG_STR));//标准输出到屏幕MSG_STR
        return 0;
}

关于fputs和weitey

fputs(const char *s, FILE *stream);
write(int fd, const void *buf, size_t count);

文件的创建/打开

open() 函数用于打开或者创建文件。其在打开或者创建文件时可以指定文件的属性及用户的权限等各种参数。

int open(const char *pathname, int flags);//打开已存在的文件
int open(const char *pathname, int flags, mode_t mode);//打开不存在的文件
//flags:read write操作文件的权限
//mode:该文件在磁盘中 相对于 用户的权限
int open(const char *path, int oflag, [mode_t mode]);

args:
    const char *path: 文件路径,可以是绝对,也可以是相对路径 
    int oflag       : 文件打开的方式
                        - O_RDONLY 只读打开
                        - O_WRONLY 只写打开
                        - O_RDWR   可读可写打开
                        以上3种必选一个,以下4种可以任意选择
                        - O_APPEND 追加打开,所写数据附加到文件末
                        - O_CREAT  若此文件不存在则创建它
                        - O_EXCL   若文件存在则报错返回 
                        - O_TRUNC  如果文件已存在,并且以只写或可读可写方式打开
                        		   则将其长度截断为0字节
    [mode_t mode]   : 文件权限,只有在创建文件时需要使用
    
return:
    文件描述符,非负整数是成功,-1是失败
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc ,char **argv)
{
        int fd = -1;

        if((fd = open("test.txt",O_CREAT|O_RDWR,0666))<0)
        if(-1==fd)
        {
                printf("文件创建失败\n");
        }
        else
        {
                printf("文件打开成功,fd = %d\n",fd);
        }
        return 0;
}

文件创建成功,并打印fd = 3.

写文件

当文件打开后,我们就可以向该文件写数据了。在Linux系统中,用 write() 向打开的文件写入数据,要使用这个函数,需要包含 #include <unistd.h> 。下面是函数的说明:

ssize_t write(int fildes, const void *buf, size_t nbyte);

args:
    int fildes     : 写入文件的文件描述符
    const void *buf: 写入数据在内存空间存储的地址
    size_t nbyte   : 期待写入数据的最大字节数
    
return:
    文件实际写入的字节数,非负整数是成功,-1是失败(磁盘已满或者超出该文件的长度等)
        if((rv = write(fd, MSG_STR,strlen(MSG_STR)))<0)
        if(rv == -1)
        {
                printf("写入数据失败\n");
        }
        else
        {
                printf("写入数据成功\n");
        }

读文件

同写文件类似,要使用读文件函数 read() ,需要包含 #include <unistd.h> 。下面是函数的说明:

ssize_t read(int fildes, void *buf, size_t nbyte);

args:
    int fildes  : 读取文件的文件描述符
    void *buf   : 读取数据在内存空间存储的地址
    size_t nbyte: 期待读取数据的最大字节数
    
return:
    文件实际读取的字节数,非负整数是成功,-1是失败
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


#define  BUFSIZE        1024
#define  MSG_STR  "i love  linux\n"


int main(int argc ,char **argv)
{
        int     fd = -1;
        int     rv = -1;
        char    buf[BUFSIZE];

        if((fd = open("test.txt",O_CREAT|O_RDWR,0666))<0)
        		if(fd==-1)
       	 		{
                printf("文件创建失败\n");
        		}
        		else
        		{
                printf("文件打开成功,fd = %d\n",fd);
        		}

        if((rv = write(fd, MSG_STR,strlen(MSG_STR)))<0)
        		if(rv == -1)
        		{
                printf("写入数据失败\n");
        		}
       	 		else
        		{
                printf("写入数据成功\n");
        		}
        memset(buf,0,sizeof(buf));//把buf的值为0,
		if((rv = read(fd,buf,sizeof(buf)))<0)
                if(rv == -1)
                {
                        printf("读写失败\n");
                }
                else
                {
                        printf("读写成功\n");
                        goto cleanup;
                }

        printf("读写的数据 %d\n %s\n",rv,buf);
        return 0;
}    

但是这样读出是空的,所以要使用lseek文件偏离量,通俗来说:就是改变光标的位置,从哪里读数据.
memset函数
memset是计算机中C/C++语言初始化函数。作用是将某一块内存中的内容全部设置为指定的值, 这个函数通常为新申请的内存做初始化工作。

void *memset(void *s, int ch, size_t n);
	str  -- 指向要填充的内存块。
	c 	 -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
	n	 -- 要被设置为该值的字符数。

文件的偏移量
在每个打开的文件中都有一个文件的偏移量,文件的偏移量会根据文件的读写而改变位置。我们可以通过 lseek() 函数来调整文件的偏移量。默认情况下,新打开文件的文件偏移量在文件的开始。同 write() 和 read() 函数类似,要使用这个函数,需要包含 #include <unistd.h> 。下面是函数的说明:

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

args:
    int fildes  : 修改文件的文件描述符
    off_t offset: 文件偏移量移动的距离
    int whence  : 文件偏移量的基址
                    - SEEK_SET 文件开始处
                    - SEEK_CUR 文件当前位置
                    - SEEK_END 文件结束处
    
return:
    当前文件指针的位置,非负整数是成功,-1是失败
lseek(fd , 0 ,SEEK_SET);//将文件偏移量设置到文件开始第一个字节上
lseek(fd , -1 ,SEEK_END);//将文件偏移量设置在文件倒数第一个字节上

在数据写入成功后,把文件偏移量移到文件开始第一行字节上

 if((rv = write(fd, MSG_STR,strlen(MSG_STR)))<0)
                if(rv == -1)
                {
                        printf("写入失败\n");
                }
                else
                {
                        printf("写入数据成功\n");
                        goto cleanup;
                }
        lseek(fd,0,SEEK_SET);

关闭文件
当文件不再被使用时,可以调用 close() 函数来关闭被打开的文件。 除了用 close() 显示地关闭文件外,通过结束进程也能隐式地关闭被该进程打开的所有文件。要使用该函数,需要包含 #include <unistd.h> 。下面是函数的说明:

int close(int fildes);

args:
   int fildes: 要关闭文件的文件描述符
   
return:
    文件关闭状态,0是成功,-1是失败

代码实现

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


#define  BUFSIZE        1024
#define  MSG_STR  "i love  linux\n"


int main(int argc ,char **argv)
{
        int     fd = -1;
        int     rv = -1;
        char    buf[BUFSIZE];

        if((fd = open("test.txt",O_CREAT|O_RDWR,0666))<0)
        		if(fd==-1)
       	 		{
                		printf("文件创建失败\n");
                		goto cleanup;
        		}	
        		else
        		{
                		printf("文件打开成功,fd = %d\n",fd);
        		}

        if((rv = write(fd, MSG_STR,strlen(MSG_STR)))<0)
        		if(rv == -1)
        		{
               			printf("写入数据失败\n");
                		goto cleanup;
        		}
       	 		else
        		{
                		printf("写入数据成功\n");
        		}
		lseek(fd,0,SEEK_SET);
		
        memset(buf,0,sizeof(buf));
        if((rv = read(fd,buf,sizeof(buf)))<0)
                if(rv == -1)
                {
                        printf("读写失败\n");
                        goto cleanup;
                }
                else
                {
                        printf("读写成功\n");
                }

        printf("读写的数据 %d\n %s\n",rv,buf);

cleanup:
        close(fd);
        return 0;
}

strerror函数
C 库函数 char *strerror(int errnum) 从内部数组中搜索错误号 errnum,并返回一个指向错误消息字符串的指针。strerror 生成的错误字符串取决于开发平台和编译器。

char *strerror(int errnum)

进一步代码实现

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


#define  BUFSIZE        1024
#define  MSG_STR        "hello world\n"


int main(int argc ,char **argv)
{
        int     fd = -1;
        int     rv = -1;
        char    buf[BUFSIZE];


        fd = open("test.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
        if(fd < 0)
        {
                perror("创建/打开文件失败");
                return 0;
        }
        printf("打开文件成功 [%d]\n",fd);

        if((rv = write(fd,MSG_STR,strlen(MSG_STR))) < 0)
        {
                printf("文件写入失败:%s\n",strerror(errno));
                goto cleanup;
        }
        lseek(fd, 0 ,SEEK_SET);

        memset(buf, 0 ,sizeof(buf));
        if((rv = read(fd,buf,sizeof(buf))) < 0)
        {
                printf("读文件失败:%s\n",strerror(errno));
                goto cleanup;
        }
        printf("从文件读出%d数据:%s\n",rv,buf);

cleanup:
        close(fd);
        return 0;
}

标签:文件,STR,int,char,fd,IO,Linux,include
From: https://www.cnblogs.com/Ye-Wei/p/16728612.html

相关文章

  • MiniWord .NET Word模板引擎,藉由Word模板和数据简单、快速生成文件。
    Github/GiteeQQ群(1群):813100564/QQ群(2群):579033769视频教学介绍MiniWord.NETWord模板引擎,藉由Word模板和数据简单、快速生成文件。GettingStarted......
  • 使用IOptionsSnapshot读取appsettings配置文件,将Json映射到对象
    {"Logging":{"LogLevel":{"Default":"Information","Microsoft.AspNetCore":"Warning"}},"AllowedHosts":"*","ConnectionStri......
  • Linux学习(一)从搭建自己的code-server开始
    前言某天碰巧看到了网页版的VSCode,发现居然有这种好东西,浏览器访问https://vscode.dev/,ipad终于能当生产力工具而不是爱奇艺播放器了o.O其实这个东西已经够用了,代码......
  • 【JAVA】普通IO数据拷贝次数的问题探讨
    最近看到网上有些文章在讨论JAVA中普通文件IO读/写的时候经过了几次数据拷贝,如果从系统调用开始分析,以读取文件为例,数据的读取过程如下(以缓存I/O为例):应用程序调用read函......
  • Unix/Linux系统编程学习笔记-4
    笔记第七章文件操作文件操作级别文件操作分为五个级别,按照从低到高的顺序排列如下。(1)硬件级别:fdisk:将硬盘、U盘或SDC盘分区。mkfs:格式化磁盘分区,为系统做好......
  • 2022.39 AIOT和元宇宙
    元宇宙这一概念最早出自于尼尔·斯蒂芬森1992年出版的科幻小说《雪崩》。小说里的元宇宙是一个脱离于现实世界,却始终在线的平行数字世界,人们能够在其中以虚拟化身份自由生......
  • linux源码包 实验报告
    实验任务linux源码包的基础命令 实验环境一台centos7 实验步骤1.下载软件包将软件包拖进远程连接    2.解压缩  3.解压tar包  4.yum安......
  • 安装及管理文件
    源码编译安装优点:契合系统兼容性强如果你可以看懂源代码,修改新增功能比较自由缺点:如果编译出了问题,你看不懂源代码,无法解决安装过程复杂没有统一的管理人员安......
  • IO流详解--Robyn编程学习(Java)
    为什么要学习IO流文件在程序中是以流的形式来操作的(流也是Java程序和磁盘文件交互的方式)IO流则是针对程序而已,I是输入,O是输出IO流的知识体系字节流与字符流字节流输......
  • linux文件内容查看命令 实验报告
    实验任务Linux查看文件基础命令 实验环境一台centos7 实验步骤1.显示文件全部内容Cat+想要查看的文件名  2.显示文件全部内容并加行号  3.空行不......