关于linux下c语言的文件IO

🛑前言

什么是IO:input output 输入输出
IO的分类:文件IO和标准IO
以下是我对文件IO的学习
文件IO:
1.不带缓冲区的操作
2.由操作系统提供,由 POSIX(通用可移值操作系统接口)定义
3.不可跨平台 windows Linux 操作系统不同,系统调用的方式也不同
4.以文件描述符为操作依据,文件描述符是 一个 非负的整数,其本质是一个数组下标

🍃操作普通文件

🌿打开文件

open()

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

使用形式:int open(const char *pathname, int flags, mode_t mode);

函数功能:打开文件

函数参数:
pathname 是被打开文件的路径
flags 是以什么样的形式打开文件

必须包含以下三个的其中一个
O_RDONLY : 以只读的形式打开该文件
O_WRONLY : 以只写的形式打开该文件
O_RDWR : 以读写的形式打开该文件
-----------------------------------------------------
下列是追加
-----------------------------------------------------
O_EXCL:如果文件已经存在,则打开操作失败。通常与 O_CREAT 一起使用,用于确保创建新文件而不覆盖
已存在的文件。
O_CREAT:如果文件不存在,则创建文件。如果文件已存在,它不会被截断,而只是打开。
O_TRUNC:如果文件已经存在,将文件长度清为0。这将删除文件的现有内容。
O_APPEND:将文件指针设置到文件末尾,以便所有写入操作都追加到文件末尾,而不是覆盖现有内容。
O_NONBLOCK:以非阻塞模式打开文件。在非阻塞模式下,读取和写入操作将不会被阻塞,即使没有可用的数
据或空间。
O_NDELAY同O_NONBLOCK
O_SYNC:要求所有I/O操作是同步的,即写入操作完成后,才返回。这可以确保数据写入到磁盘而不是缓存在
内存中。
O_DIRECTORY:要求打开的是一个目录而不是文件。用于确保只能打开目录。
O_NOFOLLOW:如果 pathname 是一个符号链接,则打开操作失败。用于防止解引用符号链接。
O_DIRECT:要求绕过内核缓存,直接在应用程序和存储设备之间进行数据传输。通常用于低级I/O操作和性
能优化。
O_TMPFILE:创建一个临时文件,该文件在关闭后会自动删除。适用于需要临时文件的场景。
O_NOCTTY如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机
如果需要别的权限,要使用 | 形式拼装 
例如 O_WRONLY | O_CREAT | O_APPEND
以只写的形式打开该文件
如果文件不存在,则创建文件。如果文件已存在,它不会被截断,而只是打开。
将文件指针设置到文件末尾,以便所有写入操作都追加到文件末尾,而不是覆盖现有内容。

mode 是创建文件的权限 权限用二进制表示

函数返回值:成功返回文件描述符,失败返回-1(有可能会设置errno)

🌿关闭文件

close()

#include <unistd.h>

使用形式:int close(int fd);

函数功能:关闭文件

函数参数:
fd 是目标文件

函数返回值:成功返回0,失败返回-1并设置errno

🌿操作文件

🍀对文件的读和写

读:
read()

#include <unistd.h>

使用形式: ssize_t read(int fd, void *buf, size_t count);

函数功能:读文件

函数参数:
fd 被读取的文件
buf 指向读到的空间
count 被读取的数据大小

函数返回值:成功返回成功读到的个数,,读完了返回0,失败返回-1并更新errno

写:
write()

#include <unistd.h>

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

函数功能:从buf表示的空间往fd表示的文件中写入count个数据

函数参数:
fd 被写入的文件
buf 写入的数据存在的空间
count 写入数据的大小

函数返回值:成功返回成功写入的个数,0表示什么也没写,失败返回-1并更新errno

☘️案例

利用read()和write()实现复制文件

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

int main(int argc, const char *argv[])
{
	int fr = 0;
	int fw = 0;
	int ret = 0;
	char buf[20] = {0};

	//打开文件
	//open(const char *pathname, int flags, mode_t mode);
	fr = open(argv[1], O_RDONLY);
	fw = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0664);
	if(-1 == fr || -1 == fw)//错误检测
	{
		perror("打开错误");
		return -1;
	}

	//操作文件
	//使用read把数据从fr存入buf中
	//read(int fd, void *buf, size_t count);
	//使用write把数据从buf存入fw中
	//write(int fd, const void *buf, size_t count);
	while(1)
	{
		memset(buf, 0, 20);//清空buf
		ret = read(fr, buf, 20);
		if(-1 == ret)
		{
			perror("读取错误");
			break;
		}else if(0 == ret)
		{
			break;
		}
		write(fw, buf, 20);
	}
	
	//关闭文件
	close(fr);
	close(fw);
	return 0;
}

🍀操作led灯

开灯
sudo sh -c “echo 1 > /sys/class/leds/input1::capslock/brightness”
关灯
sudo sh -c “echo 0 > /sys/class/leds/input1::capslock/brightness”

☘️案例

使电脑键盘上的led等间隔1s闪烁

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

int main(int argc, const char *argv[])
{
	int fd = 0;
	
	//打开文件
	fd = open("/sys/class/leds/input1\::capslock/brightness", O_WRONLY);
	if(fd < 0)//错误判断
	{
		perror("打开错误");
		return -1;
	}
	
	//操作文件
	while(1)
	{
		//间隔1s闪烁
		write(fd, "1", 1);
		sleep(1);
		write(fd, "0", 1);
		sleep(1);
	}
	
	//关闭文件
	close(fd);

	return 0;
}

🍀读取按键

按键和鼠标由linux输入子系统控制,还可以管理手柄,触摸屏,蜂鸣器等设备
打开键盘的设备文件之后,如果按键被按下或者被抬起,内核会将键盘触发的事件发送给应用程序
应用程序可以使用read函数读取事件,事件的结构体:

struct input_event
{
	struct timeval time; //事件发生的时间
	unsigned short type; //事件的类型,按键被按下或被抬起 EV_KEY 鼠标移动 EV_REL
	unsigned short code; //事件编码,按键的编码
	unsigned int value; //按键事件中,0表示按键抬起,1表示按下,2表示连击
}

按键编码在 /usr/include/linux/input-event-codes.h 文件中定义,程序中可以包含这一个头文件

#include <linux/input-event-codes.h>

通过按键事件的code字段进行判断
code字段

☘️案例
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <stdio.h>
#include <linux/input-event-codes.h>

int main(int argc, const char *argv[])
{
	int fd = 0;

	//1.打开文件
	if(0 > (fd = open("/dev/input/event1", O_RDONLY)))
	{
		perror("open");
		return -1;
	}
	struct input_event ev;

	//2.读文件
	while(1)
	{
		read(fd, &ev, sizeof(ev)); //read(1.fd, 2.buf, 3.size);
#if 0
	//检测按键是否被按下
		if(ev.type == EV_KEY )
		{
			switch(ev.value)
			{
			case 0:
				printf("taiqi\n");
				break;
			case 1:
				puts("anxia");
				break;
			case 2:
				puts("lianji");
				break;
			}
		}
#endif
#if 1
		//检测特定按键
		if(ev.type == EV_KEY && ev.code == KEY_LEFTCTRL)
		{
			switch(ev.value)
			{
				case 0:
					printf("ctrl taiqi\n");
					break;
				case 1:
					puts("ctrl anxia");
					break;
				case 2:
					puts("ctrl lianji");
					break;
			}
		}
#endif
	}
	
	//3.关闭文件
	close(fd);
	return 0;
}

🍃操作目录文件

🌿打开目录文件

opendir()

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

使用形式:DIR *opendir(const char *name);

函数功能:打开目录文件

函数参数:
name 是需要被打开的目录文件

函数返回值:成功返回目录流指针,失败返回NULL,并更新errno

🌿关闭目录文件

closedir()

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

使用形式:int closedir(DIR *dirp);

函数功能:关闭目录文件

函数参数:
dirp 指向目录流

函数返回值:成功返回0,失败返回-1并更新errno

🌿读目录文件

readdir()

#include <dirent.h>

使用形式:struct dirent *readdir(DIR *dirp);

函数功能:读dirp所指示的目录流的下一个成员的信息,并且封装一个struct dirent类型的结构体,然后将此结构体的地址作为返回值返回

struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types */
char d_name[256]; /* Null-terminated filename */
};

函数参数:
dirp 指向目录流

函数返回值:成功返回指针(非NULL);读完了返回NULL,不设置errno;发生错误返回NULL,并设置errno

🌿获取文件更加详细的信息

stat()

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

使用形式:
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);

函数功能:获得文件相关的信息

struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};

函数返回值:成功返回0,失败返回-1并更新errno

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值