Linux 文件IO

1.文件IO 概念

①不带缓存的IO,read()| write()直接使用内核中的一个系统调用;
②文件IO 又称为低级磁盘IO,遵循POSIX标准;
③文件IO读写文件时,每次操作都会执行相关系统调用,优点:直接读写实际文件,缺点:频繁的系统调用会增加系统开销;

2.文件描述符 (int fileno)

范围:3~1024个文件描述符

vim -t STDIN_FILENO
//在标准IO中,使用的最基本的文件描述符
stdin   0
stdout  1
stderr  2

打印标准IO中的stdin\stdout\stderr

int main()
{
	FILE *fp;
	fp=stdin;
	printf("stdin:%d\n",fp->_fileno);
	fp=stdout;
	printf("stdout:%d\n",fp->_fileno);
	fp=stderr;
	printf("stderr:%d\n",fp->_fileno);
}

3.int open(const char *pathname, int flags, mode_t mode);

//参数:
//pathname 文件名
//flags O_RDONLY, O_WRONLY, O_RDWR,O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE, O_TRUNC
//mode 文件掩码,修改文件权限 :实际权限为mode & ~umask (默认权限为0002)
//返回值
//成功返回文件描述符,失败返回-1;

	   #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);

       int creat(const char *pathname, mode_t mode);

       int openat(int dirfd, const char *pathname, int flags);
       int openat(int dirfd, const char *pathname, int flags, mode_t mode);

flags 用法,mode用法

O_RDONLY        //只读
O_WRONLY  		//只写
O_RDWR			//读写
O_APPEND        //追加
O_CREAT			//创建
O_CLOEXEC 		//把文件截断成0

//常用组合
"r" -> O_RDONLY
"r+"-> O_RDWR

"w" -> O_WRONLY|O_CREAT  |O_TRUNC,0666
"w+"-> O_RDWR  | O_CREAT | O_TRUNC,0666

"a" -> O_WRONLY | O_CREAT |O_APPEND,0666
"a+"-> O_RDWR   | O_CREAT | O_APPEND,0666
//实际权限为mode & ~umask ----->可以使用umask 命令查看umask

打开文件

int main()
{
	int fd;
	fd=open("log.txt",O_RDONLY);
	if(fd<0)
	{
		perror("Fail to open");
		return -1;
	}
	close(fd);
	return 0;
}

4.ssize_t read(int fd, void *buf, size_t count);

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

	#include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);
    ssize_t write(int fd, const void *buf, size_t count);
//参数:
//fp 文件描述符
//buf,字符串首地址
//count 传入字符串大小 :sizeof(buf);
//返回值:
//成功返回读到的字节数,失败返回-1;

//从标准输入流输入,从标准输出流输出

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

int main(int argc,const char *argv[])
{
	char buf[1024]={0};
	int n=0;
	while(1)
	{
		memset(buf,0,sizeof(buf));
		n=read(STDIN_FILENO,buf,sizeof(buf));
		if(strncmp(buf,"quit",4)
		{
			break;
		}
		write(STDOUT_FILENO,BUF,siezof(buf));
		
	}
	return 0;
}

5. off_t lseek(int fd, off_t offset, int whence);

// 与offset /whence 两个参数与标准IO fseek()函数后两个参数使用方法一样

	   #include <sys/types.h>
       #include <unistd.h>
       off_t lseek(int fd, off_t offset, int whence);
//参数
//fd  文件描述符
/offset  相对偏移量
//whence  相对偏移起点
//返回值  成功返回光标相对文件开头的偏移量

6. DIR *opendir(const char *name);//操作目录

int closedir(DIR *dirp);

struct dirent *readdir(DIR *dirp);

//隐藏文件 d_name 开头为 '.'时;

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

       DIR *opendir(const char *name);//成功返回目录流指针,失败返回-1
       DIR *fdopendir(int fd);
       
 	   struct dirent *readdir(DIR *dirp);


 struct dirent {
               ino_t          d_ino;       /* inode number */
               off_t          d_off;       /* not an offset; see NOTES */
               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]; /* filename */
           };

//示例:对目录的打开关闭操作

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

int main(int argc,const char* argv[])\
{
	DIR *dirp=NULL;//定义一个目录流指针
	dirp=opendir("hello");//打开一个目录,返回目录流指针
	if(dirp==NULL)
	{
		perror("Fail to opendir");
		return -1;
	}
	closedir(dirp);//关闭一个目录
	return 0;
}

//示例:读取目录中的文件或目录
//注意:readdir()函数读完所有目录和遇到错误时都会返回NULL;

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

int main(int argc,const char* argv[])\
{
	DIR *dirp=NULL;//定义一个目录流指针
	struct dirent *entry=NULL;
	dirp=opendir("hello");//打开一个目录,返回目录流指针
	if(dirp==NULL)
	{
		perror("Fail to opendir");
		return -1;
	}
	errno=0;
	while(1)
	{
		entry=readdir(dirp);
		if(entry==NULL)//出错和到文件结尾,都会返回NULL,出错会置errno
		{
			if(errno!=0)//错误码被改变,说明读取出错
			{
				perror("Fail to readdir");
				return -1;
			}
			else
			{
				printf("EOF");//到文件结尾了
				break;
			}
		}
		printf("d_name:%s\n",entry->d_name);
	}
	closedir(dirp);//关闭一个目录
	return 0;
}

//示例:遍历文件夹下某一种类型的文件

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

int main(int argc,const char* argv[])\
{
	DIR *dirp=NULL;//定义一个目录流指针
	struct dirent *entry=NULL;
	dirp=opendir("hello");//打开一个目录,返回目录流指针
	if(dirp==NULL)
	{
		perror("Fail to opendir");
		return -1;
	}
	errno=0;
	while(1)
	{
		entry=readdir(dirp);
		if(entry==NULL)//出错和到文件结尾,都会返回NULL,出错会置errno
		{
			if(errno!=0)//错误码被改变,说明读取出错
			{
				perror("Fail to readdir");
				return -1;
			}
			else
			{
				printf("EOF");//到文件结尾了
				break;
			}
		}
		if(entry->d_type==DT_REG)
		{
			printf("d_name:%s\n",entry->d_name);
		}
		//文件类型有七种:bcd-lps 及其宏定义
		//b  块文件  	DT_BLK
		//c  字符设备 	DT_CHR
		//d  目录文件	DT_DIR
		//-	 普通文件	DT_REG
		//l  链接问价	DT_LNK
		//p  有名管道文件DT_FIFO
		//s  套接字文件  DT_SOCK
	}
	closedir(dirp);//关闭一个目录
	return 0;
}
<think>好的,用户想了解Linux文件IO操作或者解决相关问题,需要教程或常见问题解决方案。首先,我需要整理一下相关的知识点,确保覆盖文件IO的基本操作、常见问题以及解决方法。根据用户提供的引用内容,尤其是引用4和引用5,里面提到了文件共享、打开方式、重定位等,这些都需要详细解释。 首先,应该从基础的文件操作开始,比如打开、读写、关闭文件。用户可能对系统调用如open、read、write、close不太熟悉,需要解释这些函数的使用方法,包括参数和返回值。同时,要提到文件描述符的概念,这是Linux文件IO的核心。 接下来,关于文件共享的三种方式,引用4中已经提到,我需要详细展开,说明不同进程如何共享文件,以及dup和dup2的作用。这部分可能涉及到文件描述符的复制,以及重定向的原理,如引用2中的重定位符号>的实现,这里可以结合例子说明。 然后,常见问题方面,用户可能会遇到权限问题、文件锁定、大文件处理等。比如,打开文件时权限不足,或者多个进程同时写入导致数据混乱。这时候需要讲解如何正确设置文件权限,使用flock或者fcntl进行文件锁定,以及处理大文件时使用O_LARGEFILE标志。 另外,用户提供的引用2和引用3提到了重定位和IO操作的条件,这部分可以解释输入输出重定向的原理,比如使用dup2系统调用实现,以及非阻塞IO的相关问题。可能用户在实际操作中遇到重定向失败或者IO阻塞的情况,需要给出解决方案。 还要考虑不同模式下的文件操作,如阻塞与非阻塞模式的区别,如何设置非阻塞模式,以及这些模式对读写操作的影响。引用3提到发起IO操作的条件,如果无法立即完成则报错,这可能与非阻塞模式有关,需要说明清楚。 在代码示例方面,用户可能需要实际的代码片段来理解如何操作。比如,使用open打开文件,并处理错误;使用read和write进行文件读写,并检查返回值;使用dup2实现重定向等。同时,需要强调错误处理的重要性,比如检查系统调用的返回值,避免程序崩溃。 关于文件位置指针的问题,用户可能在追加写入或随机访问时遇到问题,需要解释lseek函数的使用,以及O_APPEND标志的作用,确保写入位置正确。 最后,生成相关问题时要围绕用户可能进一步询问的方向,比如文件锁的具体使用、非阻塞IO的应用场景、文件描述符的复制方法等,这样可以帮助用户深入理解。 现在需要将以上思考整理成一个结构清晰的回答,分点讲解,结合引用中的内容,并附上代码示例和问题解决方案。注意使用正确的LaTeX格式,行内公式用$,独立公式用$$,同时确保引用标识正确添加在对应的位置。</think>### Linux 文件 IO 操作教程 #### 一、基础操作 1. **文件打开与关闭** 使用系统调用 `open()` 打开文件,返回文件描述符(fd)。需指定路径和模式(如只读、只写、追加等)。示例: ```c int fd = open("test.txt", O_RDWR | O_CREAT, 0644); // 创建或打开文件,权限644 if (fd == -1) { perror("open failed"); exit(1); } close(fd); // 关闭文件 ``` 模式参数如 `O_RDONLY`(只读)、`O_WRONLY`(只写)可通过位或组合[^4]。 2. **读写操作** - `read(fd, buf, size)`:从文件描述符读取数据到缓冲区。 - `write(fd, buf, size)`:将缓冲区数据写入文件。 示例: ```c char buf[1024]; ssize_t bytes_read = read(fd, buf, sizeof(buf)); // 返回实际读取字节数 if (bytes_read == -1) { /* 错误处理 */ } ``` #### 二、文件共享与描述符复制 1. **共享方式** - 同一进程多次 `open()` 同一文件。 - 不同进程分别 `open()` 同一文件。 - 使用 `dup()` 或 `dup2()` 复制描述符。 示例通过 `dup2` 实现输出重定向到文件: ```c int new_fd = open("output.txt", O_WRONLY | O_CREAT, 0644); dup2(new_fd, STDOUT_FILENO); // 将标准输出重定向到文件 ``` 2. **重定位原理** Shell 中的 `>` 符号通过 `open()` + `close()` + `dup()` 实现,将文件关联到标准输出描述符[^2]。 #### 三、常见问题与解决方案 1. **权限不足** - 检查文件权限:`ls -l` 查看权限,使用 `chmod` 修改。 - 确保 `open()` 调用时正确设置模式参数(如 `O_CREAT` 需指定权限)。 2. **并发写入冲突** - 使用文件锁(`flock()` 或 `fcntl()`): ```c struct flock lock = {F_WRLCK, SEEK_SET, 0, 0, getpid()}; fcntl(fd, F_SETLKW, &lock); // 阻塞式加锁 ``` 3. **大文件处理** - 编译时添加 `-D_FILE_OFFSET_BITS=64`,或使用 `O_LARGEFILE` 标志。 #### 四、进阶操作 1. **非阻塞模式** 设置 `O_NONBLOCK` 标志: ```c int fd = open("/dev/tty", O_RDONLY | O_NONBLOCK); if (fd == -1) { /* 处理错误 */ } ``` 若当前无法立即完成 IO,操作会返回 `EAGAIN` 错误[^3]。 2. **文件位置指针** 使用 `lseek(fd, offset, whence)` 调整读写位置。例如追加写入: ```c lseek(fd, 0, SEEK_END); // 移动到文件末尾 write(fd, "new data", 8); ``` 或直接通过 `O_APPEND` 标志实现原子追加[^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jun8086

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值