文件IO

文件IO

  • 文件IO没有缓存

一、什么是文件IO?

前面我们介绍过文件IO又叫做系统调用,它遵从POSIX标准。它是不带缓存的和操作系统
相交互的接口函数。常用的接口如下:。如果要学习文件IO首先必须理解文件描述符。

include <unistd.h> //系统调用的头文件

二、什么是文件描述符?

  • 对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,用open返回的文件描述符标识该文件,将其作为参数传送给read或write。
  • 注:在一个进程能默认可以打开的文件的个数是1024个,所以文件描述符的范围【0-1023】。但是用户也可以通过 ulimit -n 2048将打开的文件描述符的值修改为2048个通过ulimit -a查看修改后的信息。
  • 0 代表标准输入,PC环境下对应一般是键盘
  • 1 代表标准输出,PC环境下对应一般是显卡管理的显示器
  • 2 代表错误输出
[1] open 打开文件
  1. 头文件:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
  2. 函数原型:

    • int open(const char *pathname, int flags);
    • int open(const char *pathname, int flags, mode_t mode);
  3. 功能:按照用户设置的方式打开文件

  4. 参数:

    • pathname :文件的名(绝对或者相对路径)
    • flags:打开文件的方式
      • O_RDONLY 只读
      • O_WRONLY 只写
      • O_RDWR 读写
      • O_APPEND 追加
      • O_CREAT 新建文件
      • O_TRUNC 清空
      • O_NONBLOCK - 非阻塞
    • mode:当指定O_CREAT,这表示创建文件的文件权限,如果为指定则忽略这个参数
  5. 返回值:成功返回文件描述符,失败返回-1,同时置位errno

[2] umask 掩码

注:创建文件的实际的权限是和umask有关系的

  1. 假如掩码为 002 这是一个八进制数,如果你用open的creat来设置文件权限为 0666,那么文件真正的权限是(0666 & ~(0002)),相当于掩盖了其他人的可写权限
  2. umask 022可以修改掩码的值
[2] close 关闭文件
  1. 头文件:#include <unistd.h>
  2. 函数原型:int close(int fd);
  3. 功能:关闭文件
  4. 参数:@fd:文件描述符
  5. 返回值:成功返回0,失败返回-1,同时置位errno
[3] 标准IO对文件操作和文件IO中对文件操作的对应关系?
  • r O_RDONLY
  • r+ O_RDWR
  • w O_WRONLY|O_CREAT|O_TRUNC
  • w+ O_RDWR|O_CREAT|O_TRUNC
  • a O_WRONLY|O_CREAT|O_APPEND
  • a+ O_RDWR|O_CREAT|O_APPEND
[4] read
  1. 头文件:#include <unistd.h>
  2. 函数原型:ssize_t read(int fd, void *buf, size_t count);
  3. 功能:将文件中的数据读取到buf中
  4. 参数:
    • fd:文件描述符
    • buf:缓冲区
    • count:读取的字节的个数,如果返回0表示文件已经读取完
  5. 返回值:成功返回读取到的字节的个数,失败返回-1并设置errno
[5] write
  1. 头文件:#include <unistd.h>
  2. 函数原型:ssize_t write(int fd, const void *buf, size_t count);
  3. 功能:将buf中的数据写入到文件
  4. 参数:
    • fd:文件描述符
    • buf:缓冲区
    • count:读取的字节的个数
  5. 返回值:成功返回读取到的字节的个数,失败返回-1并设置errno
[6] lseek
  1. 头文件:
    • #include <sys/types.h>
    • #include <unistd.h>
  2. 函数原型:off_t lseek(int fd, off_t offset, int whence);
  3. 功能: 移动文件指针
  4. 参数:
    • fd 文件描述符
    • offset 偏移值
    • whence:
      • SEEK_SET: 文件开头位置
      • SEEK_CUR: 当前文件指针位置
      • SEEK_END: 文件结尾位置
  5. 返回值: 成功返回设置后的文件指针相对于文件开始的偏移值,失败返回 -1设置errno
[7] 练习:使用系统调用完成文件的拷贝?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	if(argc != 3) {
		printf("usage: ./a.out src dist\n");
		return -1;
	}
	
	// argv[1] 源文件 
	// argv[2] 目标文件 
	int fd_src = open(argv[1], O_RDONLY);
	if(fd_src == -1) {
		perror("open");
		return fd_src;
//		return -1;
	}
	int fd_dist = open(argv[2], O_RDWR|O_CREAT|O_TRUNC, 0664);
	if(fd_dist == -1) {
		perror("open");
		close(fd_src);
		return fd_src;
	}

	char buf[100] = {0};
	while(1) {
		int ret = read(fd_src, buf, 100);
		if(ret == 0)  {  // 如果 read 的返回值为 0 表示读到文件结尾 
			printf("read end of file\n");
			break;// 跳出循环 	
		}
		//  ret 的值是 读到了多少字节数据 
		write(fd_dist, buf, ret);	
	}

	// 关闭文件 	
	close(fd_src);
	close(fd_dist);
	return 0;
}
[8] 重定向
  1. 头文件:#include <stdio.h>

  2. 函数原型:FILE *freopen(const char *path, const char *mode, FILE *stream);

  3. 功能:重定向【把打开的文件描述符定向到新的文件】

  4. 参数:

    • const char *path - 指向带路径的文件名
    • const char *mode - 指向操作方式字符串,如下仅能选择其中一个
      • "r":文件存在,且只读打开,文件位置在开头
      • "r+":文件存在,读写打开,文件位置在开头
      • "w":文件存在清空文件内容只写打开,文件不存在创建文件只写打开,文件位置在开头
      • "w+":文件存在清空文件内容读写打开,文件不存在创建文件读写打开,文件位置在开头
      • "a":文件存在则从文件尾巴开始写【定位位置在文件尾】打开,文件不存在创建文件只写打开,文件位置在文件尾
      • "a+":文件存在则从文件尾巴开始读写【定位位置在文件尾】打开,文件不存在创建文件读写打开,文件位置在文件尾
    • FILE *stream: 文件指针
  5. 实例

    #include <stdio.h>
    int main()
    {
    	//把标准输出定向到1.txt
    	FILE *fp = freopen("1.txt", "w+", stdout); 
    	if(NULL == fp){
    		perror("freopen");
    		return 0;
    	}
    	//其实际内部是调用标准输出,向终端输出格式化字符串
    	printf("hello world\n");
    	
    	//关闭重定向
    	fclose(fp);
    }
    
【9】opendir/readdir/closedir
#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *name);
功能:打开一个目录
参数:
    @name:目录的名字
返回值:成功返回目录的流指针,失败返回NULL,并设置errno
        
struct dirent *readdir(DIR *dirp);
功能:读取目录下的文件
参数:
    @dirp:打开目录返回的目录的流指针
返回值:成功返回struct dirent的结构体指针
       失败或者读取到结尾返回NULL,如果读取到结尾不会置位errno,如果失败会设置errno
        
struct dirent {
    ino_t          d_ino;       //文件的inode号
    off_t          d_off;       //在目录中的偏移
    unsigned short d_reclen;    //文件名的长度
    unsigned char  d_type;      //文件的类型
    char           d_name[256]; //保存文件名的数组
};


int closedir(DIR *dirp);
功能:关闭目录流指针
参数:
    @dirp:目录流指针
返回值:成功返回0,失败返回-1并设置errno
  • 示例代码

    // 获取当前目录下的文件名,并打印出来
    #include <stdio.h>
    #include <sys/types.h>
    #include <dirent.h>
    
    int main(int argc, const char *argv[])
    {
    	DIR * dir;
    	if (NULL == (dir = opendir("./")))
    	{
    		perror("opendir error ");
    		return -1;
    	}
    
    	struct dirent * d = NULL;
    	puts("\n***********************************************");
    	while (d = readdir(dir))
    		printf("filename: %s\n", d->d_name);
    	putchar('\n');
    
    	return 0;
    }
    
posted @ 2021-06-22 07:55  今天的风,甚是喧嚣  阅读(236)  评论(0)    收藏  举报