Linux文件IO操作

1、系统调用概述

系统调用,顾名思义,说的是操作系统提供给用户程序调用的一组“特殊”接口。(重要!!!)
一个进程(用户态、内核态)(了解)
在这里插入图片描述

2、系统调用 和 库函数的区别(重要!!!)

在这里插入图片描述
在这里插入图片描述
系统调用是需要时间的,程序中频繁的使用系统调用会降低程序的运行效率。当运行内核代码时,CPU工作在内核态,在系统调用发生前需要保存用户态的栈和内存环境,然后转入内核态工作。系统调用结束后,又要切换回用户态。这种环境的切换会消耗掉许多时间 。

3、文件描述符(重要!!!)

用一个非负整数 来标识一个文件 这个非负的整数 就是文件描述符。
打开一个文件 系统就会为我们非配一个文件描述符 操作文件描述符 就等价于 操作文件.

文件描述符表:进程运行的时候 系统创建文件描述符表 来管理系统中文件描述符。
每一个进程 默认打开了3个文件描述符(0标准输入设备/键盘 1标准输出设备/屏幕 2标准错误输出/屏幕)

案例:读取文件数据

在这里插入图片描述
在这里插入图片描述
运行结果:
在这里插入图片描述
在这里插入图片描述
当用户打开一个文件的时候 系统 会给我们分配一个最小可用的文件描述符(重要!!!)
在这里插入图片描述
文件描述符表的管理(位图)
在这里插入图片描述

4、文件的打开读写关闭

4.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);//打开不存在的文件
//flags:read write操作文件的权限
//mode:该文件在磁盘中 相对于 用户的权限
功能:
    打开文件,如果文件不存在则可以选择创建。
参数:
    pathname:文件的路径及文件名
    flags:打开文件的行为标志,必选项 O_RDONLY, O_WRONLY, O_RDWR
    mode:这个参数,只有在文件不存在时有效,指新建文件时指定文件的权限
返回值:
    成功:成功返回打开的文件描述符
    失败:-1

4.1.1、flags宏的介绍(打开方式)

比如:以读写的方式打开 不存在则创建 存在清空 flags=O_RDWR | O_CREAT | O_TRUNC
在这里插入图片描述

4.1.2、mode的介绍(权限)

mode的权限分3组:所拥有者、同组用户、其他用户
每组都必须有独立的权限。
在这里插入图片描述
4表示读r 2表示写w 1表示可执行x
在这里插入图片描述
在这里插入图片描述
文件的最终权限 = 默认权限 - 文件掩码
文件掩码:屏蔽其他用户的权限
在这里插入图片描述
在这里插入图片描述

chmod 777 xxx将xxx的最终权限设置为777

4.2、关闭文件close

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

在这里插入图片描述
运行结果:
在这里插入图片描述

4.3、文件的写操作write

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:
    把指定数目的数据写到文件(fd)
参数:
    fd :  文件描述符
    buf : 数据首地址
    count : 写入数据的长度(字节)
返回值:
    成功:实际写入数据的字节个数
    失败: - 1

在这里插入图片描述

4.4、read读取文件数据

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

案例:读文件数据

在这里插入图片描述

案例:实现cp命令: cp src_file dst_dir

在这里插入图片描述

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
	//./main test.txt  test
	if(argc != 3)
	{
		printf("please intput:./main src dst_dir\n");
	}
	char src_file[128]="";
	char dst_file[128]="";
	strcpy(src_file, argv[1]);//test.txt
	sprintf(dst_file,"%s/%s",argv[2], argv[1]);//"test/test.txt"
	
	int fd1 = open(src_file, O_RDONLY);
	if(fd1 < 0)
	{
		perror("open");
		return 0;
	}
	int fd2 = open(dst_file, O_WRONLY|O_CREAT,0777);
	if(fd2 <0)
	{
		perror("open");
		return 0;
	}

	while(1)
	{
		char buf[128]="";
		//从s源文件中读取数据
		int ret = read(fd1,buf,sizeof(buf));
		if(ret <= 0)
			break;
		//将读到的w数据写到目的文件中
		write(fd2,buf,ret);
	}

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

运行结果:
在这里插入图片描述

5、文件的阻塞特性

【注意】阻塞与非阻塞是对于文件而言的,而不是指read、write等的属性

案例:默认终端是读是阻塞的

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
	// /dev/tty --> 当前终端设备
	int fd = open("/dev/tty", O_RDONLY);//默认是阻塞的
	if(fd<0)
	{
		perror("open");
		return 0;
	}
	
	printf("fd = %d\n",fd);
	
	char buf[128]="";
	printf("准备读!!!\n");
	read(fd,buf,sizeof(buf));
	printf("buf=%s\n",buf);
	
	close(fd);
	return 0;
}

运行结果:
在这里插入图片描述

案例:非阻塞()

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
	// /dev/tty --> 当前终端设备
	//int fd = open("/dev/tty", O_RDONLY);//默认是阻塞的
	int fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);//不阻塞的
	
	if(fd<0)
	{
		perror("open");
		return 0;
	}
	
	printf("fd = %d\n",fd);
	
	char buf[128]="";
	printf("准备读!!!\n");
	read(fd,buf,sizeof(buf));
	printf("buf=%s\n",buf);
	
	close(fd);
	return 0;
}

运行结果:
在这里插入图片描述

5.1、通过fcntl函数设置文件的阻塞特性(了解)

我们还可以通过fcntl函数来设置文件描述符的阻塞特性
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */);
功能:改变已打开的文件性质,fcntl针对描述符提供控制。
参数:
    fd:操作的文件描述符
    cmd:操作方式
    arg:针对cmd的值,fcntl能够接受第三个参数int arg。
返回值:
    成功:返回某个其他值
    失败:-1
fcntl函数有5种功能:
1) 复制一个现有的描述符(cmd=F_DUPFD)
2) 获得/设置文件描述符标记(cmd=FGETFD或FSETFD)
3) 获得/设置文件状态标记(cmd=FGETFL或FSETFL)
4) 获得/设置异步I/O所有权(cmd=FGETOWN或FSETOWN)
5) 获得/设置记录锁(cmd=FGETLK, FSETLK或F_SETLKW)

案例:默认阻塞

在这里插入图片描述
fcntl函数设置非阻塞

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
	char buf[128]="";
	//fcntl设置文件标记的3步曲
	//获得文件的标记
	int flag = fcntl(0, F_GETFL);
	//修改文件的标记(非阻塞标记)
	flag |= O_NONBLOCK;
	//设置文件的标记
	fcntl(0,F_SETFL, flag);
	
	printf("准备读!!!\n");
	read(0,buf,sizeof(buf));
	printf("buf=%s\n",buf);	
	
	return 0;
}

运行结果:
在这里插入图片描述

6、通过文件名 直接获取文件的状态(了解)

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
功能:
    获取文件状态信息
    stat和lstat的区别:
        当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;
        而stat返回的是该链接指向的文件的信息。
参数:
    path:文件名
    buf:保存文件信息的结构体
返回值:
    成功: 0
    失败: -1

struct stat的结构信息:

struct stat {
    dev_t           st_dev;     //文件的设备编号
    ino_t           st_ino;     //节点
    mode_t          st_mode;            //文件的类型和存取的权限
    nlink_t         st_nlink;       //连到该文件的硬连接数目,刚建立的文件值为1
    uid_t           st_uid;     //用户ID
    gid_t           st_gid;     //组ID
    dev_t           st_rdev;        //(设备类型)若此文件为设备文件,则为其设备编号
    off_t           st_size;        //文件字节数(文件大小)
    blksize_t       st_blksize;     //块大小(文件系统的I/O 缓冲区大小)
    blkcnt_t        st_blocks;      //块数
    time_t          st_atime;       //最后一次访问时间
    time_t          st_mtime;       //最后一次修改时间
    time_t          st_ctime;       //最后一次改变时间(指属性)
};

st_mode(16位整数)参数说明:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

案例:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
	struct stat my_stat;
	stat("test.txt", &my_stat);
	
	printf("文件的大小:%u\n", my_stat.st_size);
	if(S_ISREG(my_stat.st_mode))
	{
		printf("它是一个普通文件\n");
	}
	else if(S_ISDIR(my_stat.st_mode))
	{
		printf("它是一个目录文件\n");
	}
	
	if((my_stat.st_mode& S_IRUSR)== S_IRUSR)
	{
		printf("所有者具备读的权限\n");
	}
	return 0;
}

运行结果:
在这里插入图片描述

7、文件的目录操作(了解)

我们经常需要读取一个目录下的所有文件名,所以一下介绍如何读取一个文件下的目录
步骤:

1、打开文件目录opendir

#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开一个目录
参数:
    name:目录名
返回值:
    成功:返回指向该目录结构体指针
    失败:NULL

2、读取目录readdir 调用一次 只能读取一个文件

#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取目录
参数:
    dirp:opendir的返回值
返回值:
    成功:目录结构体指针
    失败:NULL

struct dirent:

struct dirent
{
    ino_t d_ino;                  // 此目录进入点的inode
    off_t d_off;                    // 目录文件开头至此目录进入点的位移
    signed short int d_reclen;      // d_name 的长度, 不包含NULL 字符
    unsigned char d_type;           // d_type 所指的文件类型
    char d_name[256];               // 文件名
};

d_type取值:
在这里插入图片描述

3、关闭closedir

#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭目录
  参数:
      dirp:opendir返回的指针
  返回值:
      成功:0
      失败:-1

案例:

#include <stdio.h>
#include <dirent.h>
int main(int argc,char *argv[])
{
	//打开目录
	DIR *dir = opendir("test");
	if(dir == NULL)
	{
		perror("opendir");
		return 0;
	}
	//读取目录
	while(1)
	{
		struct dirent *p = readdir(dir);
		if(p == NULL)
			break;
		printf("文件名:%s  ", p->d_name);
		if(p->d_type == DT_DIR)
		{
			 printf("目录\n");
		}
		else if(p->d_type == DT_REG)
		{
			printf("普通文件\n");
		}
	}
	
	//关闭
	closedir(dir);
}

运行结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值