文件I/O:系统调用

  • 一、文件I/O基本概念
    • 1.什么是文件I/O?
    • 2.文件描述符
  • 二、文件I/O函数
    • head.h
    • 1.open、close(打开、关闭文件)
      • 1.1open、close函数API
      • 1.2文件I/O和标准I/O文件打开方式对比
      • 1.3open函数实例1(只读、只写)
      • 1.4open函数实例2(参数O_EXCL)
      • 1.5close函数实例3(关闭标准输出)
    • 2.read、write(读取、写入文件)
      • 2.1read、write函数API
      • 2.2read函数实例1(读取整数、字符串、结构体)
      • 2.3write函数实例2(写入整数、字符串、结构体)
      • 2.4write函数实例3(计算文件大小)
      • 2.5read、write函数实例4(文件拷贝)
      • 2.6fgets、write函数实例5(键盘输入内容到文件)
    • 3.lseek(定位文件指针)
      • 3.1lseek函数API
      • 3.2lseek函数实例1
      • 3.3lseek函数实例2
    • 4.stat(获取文件属性)
      • 4.1stat函数API
      • 4.2根据uid获取用户名,getpwuid函数
      • 4.3根据gid获取组名,getgrgid函数
      • 4.4stat函数实例1(实现 ls -l)

一、文件I/O基本概念

1.什么是文件I/O?

posix(可移植操作系统接口)定义的一组函数,不提供缓冲机制,每次读写操作都引起系统调用,核心概念是文件描述符,访问各类型文件,在Linux下,标准I/O基于文件I/O实现。

2.文件描述符

文件描述符(fd)是一个非负整数,Linux为程序中每个打开的文件分配一个文件描述符。文件描述符从0开始分配,依次递增,在ubuntu系统中一个正在执行的程序,文件描述符的范围是 0~1023(1024个)。每一个正在执行的程序都有自己的一套文件描述符,相互不干扰。

一个正在执行的程序中0,1,2文件描述符已经被占用了,分别对应的是标准输入,标准输出,标准出错。

#include <stdio.h>int main(int argc, const char* argv[])
{printf("in  fd = %d\n", stdin->_fileno);  // 0printf("out fd = %d\n", stdout->_fileno); // 1printf("err fd = %d\n", stderr->_fileno); // 2return 0;
}

ulimit -a 显示当前所有的资源限制等。
ulimit -n 2048 修改文件描述符范围为2048。

二、文件I/O函数

head.h

编写head.h的头文件
将head.h放到/usr/include路径下
修改head.h文件所属用户和组,sudo chown linux:linux /usr/include/head.h
修改用户代码片段(c.json),将#include <stdio.h>改成#include <head.h>

#ifndef __HEAD_H__
#define __HEAD_H__#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define PRINT_ERR(msg) \do                 \{                  \perror(msg);   \return -1;     \} while (0)#endif

1.open、close(打开、关闭文件)

1.1open、close函数API

#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);
功能:打开文件
参数:@pathname:打开文件的路径及名字@flags   :打开文件的方式O_RDONLY :只读O_WRONLY :只写O_RDWR   :读写O_APPEND :追加O_CREAT  :创建,如果flags中填写了O_CREAT,就必须填写第三个参数,第三个参数代表创建文件的权限O_TRUNC  :清空O_EXCL   :和O_CREAT结合使用,在创建文件的时候加上这个选项,如果文件存在就返回EEXIST,如果文件不存在就会不返回错误O_NOCTTY :使用本参数时,如文件为终端,那么终端不可作为调用open()系统调用的那个进程的控制终端。@mode:创建文件的权限,为8进制表示法实际创建出来的文件的权限 = (mode & ~umask)umask:文件的掩码:通过umask命令可以查看掩码的默认值是0002  ~umask:文件掩码的取反是在最大默认文件的权限的基础上取反的,最大默认文件的权限是0666实际创建出来的文件的权限 = (0666 & ~(0002)) =  (0666 & 0664) = 0664
返回值:成功返回文件描述符,失败返回-1置位错误码
#include <unistd.h>int close(int fd);
功能:关闭文件
参数:@fd:文件描述符
返回值:成功返回0,失败返回-1置位错误码

1.2文件I/O和标准I/O文件打开方式对比

文件IO 标准IO 功能
O_RDONLY “r” 以只读的方式打开文件,将光标定位到开头
O_RDWR “r+” 以读写的方式打开文件,将光标定位到开头
O_WRONLY | O_CREAT | O_TRUNC,0666 “w” 以只写的方式打开文件,如果文件不存在就创建,如果文件存在清空,光标在开头
O_RDWR | O_CREAT | O_TRUNC,0666 “w+” 以读写的方式打开文件,如果文件不存在就创建,如果文件存在清空,光标在开头
O_WRONLY | O_CREAT | O_APPEND,0666 “a” 以只写和追加的方式打开文件,如果文件不存在就创建,如果存在光标在结尾
O_RDWR | O_CREAT | O_APPEND,0666 “a+” 以读写和追加的方式打开文件,如果文件不存在就创建,如果文件存在读光标在开头,写光标在结尾

1.3open函数实例1(只读、只写)

只读、只写方式打开文件。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define PRINT_ERR(msg) \do                 \{                  \perror(msg);   \return -1;     \} while (0)int main(int argc, const char *argv[])
{int fd1, fd2;// 只读方式打开文件if (-1 == (fd1 = open("./1.txt", O_RDONLY)))PRINT_ERR("open error");// 只写方式打开文件if (-1 == (fd2 = open("./hello.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666)))PRINT_ERR("open error");close(fd1);close(fd2);return 0;
}

1.4open函数实例2(参数O_EXCL)

如果文件不存在,创建文件,以只写方式打开文件。
如果文件存在,以只读方式打开文件。

#include <head.h>int main(int argc, const char *argv[])
{int fd;// 如果文件不存在,创建文件,以只写方式打开文件// 如果文件存在,以只读方式打开文件if (-1 == (fd = open("./1.txt", O_WRONLY | O_CREAT | O_EXCL, 0666))) {if (errno = EEXIST) {if (-1 == (fd = open("./1.txt", O_RDONLY)))PRINT_ERR("open error");puts("文件存在,以只读方式打开文件");} else {PRINT_ERR("open error");}} else {puts("文件不存在,创建文件,以只写方式打开文件");}printf("fd = %d\n", fd);close(fd);return 0;
}

1.5close函数实例3(关闭标准输出)

关闭标准输出(fd = 1),终端不会输出。

#include <head.h>int main(int argc, const char *argv[])
{puts("--------------start");close(1);puts("--------------end");  //关闭标准输出(fd = 1),终端不会输出这行return 0;
}

2.read、write(读取、写入文件)

2.1read、write函数API

#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
功能:读取文件中的内容
参数:@fd:文件描述符@buf:存储读取到数据的首地址@count:想要读取的字节的个数
返回值:成功返回读取到字节的个数,如果返回0代表读取到文件的结尾了失败返回-1置位错误码
#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);
功能:向文件中写数据
参数:@fd:文件描述符@buf:想要写的数据的首地址@count:想要写的字节的个数
返回值:成功返回写入的字节的个数,0表示不会写任何的数据失败返回-1置位错误码

2.2read函数实例1(读取整数、字符串、结构体)

配合2.3wirte函数实例2使用

#include <head.h>typedef struct stu {char name[20];int age;char sex;
}stu_t;int main(int argc, const char *argv[])
{int fd;if (-1 == (fd = open("./1.txt", O_RDONLY)))PRINT_ERR("open error");/*    // 1.验证读取整数int num;read(fd, &num, sizeof(num));printf("num = %d\n", num);// 2.验证读取字符串char buf[20] = {0};read(fd, buf, sizeof(buf));printf("buf = %s\n", buf);*/// 3.验证读取结构体stu_t stu;read(fd, &stu, sizeof(stu));printf("name = %s, age = %d, sex = %c\n", stu.name, stu.age, stu.sex);close(fd);return 0;
}

2.3write函数实例2(写入整数、字符串、结构体)

配合2.2read函数实例1使用

#include <head.h>typedef struct stu {char name[20];int age;char sex;
}stu_t;int main(int argc, const char *argv[])
{int fd;if (-1 == (fd = (open("./1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666))))PRINT_ERR("open error");
/* // 1.验证写入整数int num = 12345;write(fd, &num, sizeof(num));// 2.验证写入字符串char buf[100] = "hello world!";write(fd, buf, strlen(buf));*/// 3.验证写入结构体stu_t stu = {.name = "xiaoming",.age = 21,.sex = 'm'};write(fd, &stu, sizeof(stu_t));close(fd);return 0;
}

2.4write函数实例3(计算文件大小)

#include <head.h>int main(int argc, const char *argv[])
{if (2 != argc) {fprintf(stderr, "Usage: %s <file>\n", argv[0]);return -1;}int fd;if (-1 == (fd = open(argv[1], O_RDONLY)))PRINT_ERR("open error");int total = 0;int ret;char buf[10] = {0};while (0 < (ret = read(fd, buf, sizeof(buf)))) {total += ret;}printf("%s size total is %d\n", argv[1], total);close(fd);return 0;
}

2.5read、write函数实例4(文件拷贝)

#include <head.h>int main(int argc, const char *argv[])
{// 1.校验用户输入的参数是否正确if (3 != argc) {fprintf(stderr, "Usage: %s <src_file> <dest_file>\n", argv[0]);return -1;}// 2.只读方式打开源文件,写的方式打开目标文件(创建)int sfd, dfd;if (-1 == (sfd = open(argv[1], O_RDONLY)))PRINT_ERR("open src_file error");if (-1 == (dfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666)))PRINT_ERR("open dest_file error");// 3.拷贝int ret;char buf[10] = {0};while (0 < (ret = read(sfd, buf, sizeof(buf)))) {write(dfd, buf, ret);}// 4.关闭文件close(sfd);close(dfd);return 0;
}

2.6fgets、write函数实例5(键盘输入内容到文件)

#include <head.h>int main(int argc, const char *argv[])
{if (2 != argc) {fprintf(stderr, "Usage: %s <file>\n", argv[0]);return -1;}int fd;if (-1 == (fd = open(argv[1], O_RDWR | O_APPEND | O_CREAT, 0666)))PRINT_ERR("open error");char buf[10] = {0};while (NULL != fgets(buf, 10, stdin)) {if (0 == strcmp(buf, "quit\n")) break;  //终端输入quit退出write(fd, buf, strlen(buf));}close(fd);return 0;
}

3.lseek(定位文件指针)

3.1lseek函数API

#include <sys/types.h>
#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
功能:设置光标的位置
参数:@fd:文件描述符@offset:偏移量>0:向后偏移=0:不偏移<0:向前偏移@whence:从那个位置开始偏移SEEK_SET:从文件的开头SEEK_CUR:从当前位置SEEK_END:从文件的结尾
返回值:成功返回光标到开头的字节数,失败返回-1置位错误码

3.2lseek函数实例1

#include <head.h>int main(int argc, const char *argv[])
{// abcdefg1234567// 1.读写方式打开文件int fd;if (-1 == (fd = open("./1.txt", O_RDWR)))PRINT_ERR("open error");// 2.文件开头向后偏移5个字节lseek(fd, 5, SEEK_SET);char ch;read(fd, &ch, 1);printf("ch = %c\n", ch);  //读取到第6个字符,fch = 'Q';write(fd, &ch, 1);  //写入到第7个字符,abcdefQ1234567close(fd);return 0;
}

3.3lseek函数实例2

如果使用读写和追加的方式打开文件,即使lseek偏移了文件指针,写指针永远是在结尾。

#include <head.h>int main(int argc, const char *argv[])
{// abcdefg1234567// 1.以读写和追加的方式打开文件int fd;if (-1 == (fd = open("./1.txt", O_RDWR | O_APPEND | O_CREAT, 0666)))PRINT_ERR("open error");// 2.文件开头向后偏移5个字节lseek(fd, 5, SEEK_SET);char ch;read(fd, &ch, 1);printf("ch = %c\n", ch);  //读取到第6个字符,fch = 'T';write(fd, &ch, 1);  //T字符写到了文件的结尾,写永远是在结尾int ret;ch = 0;ret = read(fd, &ch, 1);  //光标已经在结尾了,这里读是读取不到内容的,read返回0(end of file)printf("ch = %c, ret = %d\n", ch, ret);  //ch = , ret = 0close(fd); return 0;
}

4.stat(获取文件属性)

4.1stat函数API

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>int stat(const char *pathname, struct stat *statbuf);
//stat不能获取软连接文件,如果向测试软链接,使用lstat完成,用法和stat完全相同
功能:获取文件的属性信息
参数:@pathname:文件的路径及名字@statbuf:获取的属性信息结构指针struct stat {dev_t     st_dev;         //磁盘设备号,底层驱动课程讲解ino_t     st_ino;         //文件的inode号,文件系统识别文件的唯一编号,通过ls -i查看mode_t    st_mode;        //文件的类型和权限//1.文件的类型 文件的类型占4bit位,12-15就是文件的类型S_IFMT     0170000   bit mask for the file type bit fieldS_IFSOCK   0140000   socket           //套接字文件S_IFLNK    0120000   symbolic link    //软连接文件S_IFREG    0100000   regular file     //普通文件S_IFBLK    0060000   block device     //块设备文件S_IFDIR    0040000   directory        //目录S_IFCHR    0020000   character device //字符设备文件S_IFIFO    0010000   FIFO             //管道eg:      if((st_mode & S_IFMT) == S_IFREG){printf("普通文件\n");} //2.文件的权限 文件的权限占9bit位,0-8就是文件的权限 文件的权限 = st_mode & 0777nlink_t   st_nlink;       //硬链接数uid_t     st_uid;         //用户的uidgid_t     st_gid;         //用户的giddev_t     st_rdev;        //设备号,底层驱动课程讲解off_t     st_size;        //文件的大小,单位是字节blksize_t st_blksize;     //操作块设备的最小单位block,512字节blkcnt_t  st_blocks;      //文件的大小,单位是blockstruct timespec st_atim;  //最后一次访问这个文件的时间struct timespec st_mtim;  //最后一次修改这个文件的时间struct timespec st_ctim;  //最后一次状态改变的时间};
返回值:成功返回0,失败返回-1置位错误码

4.2根据uid获取用户名,getpwuid函数

#include <sys/types.h>
#include <pwd.h>struct passwd *getpwuid(uid_t uid);
功能:根据uid获取用户信息结构体
参数:@uid:用户的id
返回值:成功返回用户信息结构指针,失败返回NULL,置位错误码struct passwd {char   *pw_name;       //用户名char   *pw_passwd;     //用户的密码uid_t   pw_uid;        //uidgid_t   pw_gid;        //gidchar   *pw_gecos;      //用户的信息char   *pw_dir;        //用户的主目录char   *pw_shell;      //shell程序};

4.3根据gid获取组名,getgrgid函数

#include <sys/types.h>
#include <grp.h>struct group *getgrgid(gid_t gid);
功能:根据gid获取group结构体
参数:@gid:组号
返回值:成功返回结构体指针,失败返回NULL置位错误码struct group {char   *gr_name;        //组名char   *gr_passwd;      //组的密码gid_t   gr_gid;         //组号};

4.4stat函数实例1(实现 ls -l)

#include <head.h>void print_type(mode_t mode);
void print_permission(mode_t mode);
int print_time(struct timespec time);int main(int argc, const char *argv[])
{// 1.校验参数输入是否正确if (2 != argc) {fprintf(stderr, "Usage: %s <file>\n", argv[0]);return -1;}// 2.获取文件的属性struct stat st;if (stat(argv[1], &st))PRINT_ERR("stat get msg failed");// 3.将属性打印出来print_type(st.st_mode);  //打印文件类型print_permission(st.st_mode);  //打印文件权限printf(" %ld", st.st_nlink);  //打印硬链接个数printf(" %s", getpwuid(st.st_uid)->pw_name);  //打印用户名printf(" %s", getgrgid(st.st_gid)->gr_name);  //打印组名printf(" %ld", st.st_size);  //打印文件大小(字节)print_time(st.st_atim);  //打印时间戳printf(" %s", argv[1]);  //打印文件名puts("");return 0;
}// 打印文件类型
void print_type(mode_t mode) {switch (mode & S_IFMT) {case S_IFSOCK:putchar('s'); break;case S_IFLNK:putchar('l'); break;case S_IFREG:putchar('-'); break;case S_IFBLK:putchar('b'); break;case S_IFDIR:putchar('d'); break;case S_IFCHR:putchar('c'); break;case S_IFIFO:putchar('p'); break;}
}// 打印文件权限
void print_permission(mode_t mode) {for (int n = 8; n >= 0; n--) {if ((mode & 0777) & (1 << n)) {switch (n % 3) {case 2:putchar('r'); break;case 1:putchar('w'); break;case 0:putchar('x'); break;}} else {putchar('-');}}
}// 打印文件时间戳
int print_time(struct timespec time) {struct tm* tm;if (NULL == (tm = localtime(&time.tv_sec)))PRINT_ERR("change time error");printf(" %02d月 %2d %02d:%02d", \tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
}

【文件I/O】(二)文件I/O相关推荐

  1. OpenCV读写视频文件解析(二)

    OpenCV读写视频文件解析(二) VideoCapture::set 设置视频捕获中的属性. C++: bool VideoCapture::set(int propId, double value ...

  2. 基于C++与VS2012的HDF5文件处理(二)

    基于C++与VS2012的HDF5文件处理(二) 例程学习:三维矩阵读写 1 /************************************************************ ...

  3. Python基于MASK信息抽取ROI子图并构建基于迁移学习(densenet)的图像分类器实战(原始影像和mask文件都是二维的情况)

    Python基于MASK信息抽取ROI子图并构建基于迁移学习(densenet)的图像分类器实战(原始影像和mask文件都是二维的情况) 目录

  4. Python基于MASK信息抽取ROI子图实战:原始影像和mask文件都是二维的情况

    Python基于MASK信息抽取ROI子图实战:原始影像和mask文件都是二维的情况 目录 Python基于MASK信息抽取ROI子图实战:原始影像和mask

  5. unix系统编程小结(二)------文件和目录

    一.对linux的安全机制的一点感悟 各种权限,read,write,execute,set-user-ID,set-group-ID,sticky bit,对目录的权限,对文件的权限,用于保证系统安 ...

  6. 电脑粉碎文件 c语言,文件操作(二):文件粉碎机

    文件操作(2):文件粉碎机 文件粉碎机原理:文件被删除之前,用随机字符对其进行写操作 (注:参考的教材使用的是BCB编译器,BCB不会,所以这里改成使用MFC) 一. 首先建立一个基于对话框的MFC工 ...

  7. C语言文件操作解析(二)【转载】

    http://www.cnblogs.com/dolphin0520/archive/2011/10/05/2199598.html C语言文件操作解析(二) C语言中对文件进行操作必须首先打开文件, ...

  8. [转]文件IO详解(二)---文件描述符(fd)和inode号的关系

    原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...

  9. C语言文件操作解析(二)

    C语言文件操作解析(二) C语言中对文件进行操作必须首先打开文件,打开文件主要涉及到fopen函数.fopen函数的原型为 FILE* fopen(const char *path,const cha ...

  10. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

最新文章

  1. (一)Android Studio 安装部署 华丽躲坑
  2. Python天天美味(28) - urlopen
  3. 我在学python-我在大学毕业后学习Linux、python的一些经验
  4. SECD machine
  5. python 复制文件夹校验_Python多任务复制文件夹
  6. Linux 阻塞和非阻塞IO 实验
  7. 固定资产管理有关的计算机知识,计算机技术在固定资产管理中的具体应用.pdf...
  8. ubuntun系统mysql数据库同步_Canal 实现 Mysql数据库实时数据同步
  9. 吴恩达机器学习笔记五之神经网络
  10. 谈谈你了解的python_你也可以侃侃而谈,一文带你了解Python的前世今生
  11. Android开发之动态创建多个按钮
  12. 使用阿里云容器监控服务与第三方监控框架集成搭建自己的容器看板
  13. 游戏开发之C++类和对象相关概念实例(C++)
  14. r语言作业:出租车数据基础数据分析、时间处理等
  15. 小米路由器青春版(R1CL)刷breed固件
  16. 也谈正方形不是长方形
  17. 魔戒中超眩的武器装备!
  18. Java代码签名证书申请和使用指南
  19. w ndows10怎重装系统,笔记本重装系统教你笔记本怎么重装win10系统
  20. PPT学习资源和实用技巧

热门文章

  1. Vue自定义指令介绍及原理
  2. ADSP21489数据手册表摘要
  3. matlab 变压器 异名,Matlab simulink变压器的配置
  4. SAP ABAP ALV下钻
  5. c语言打印qword类型,c/c++开发分享c语言中数据类型BYTE,WORD和DWORD的格式说明符?...
  6. 远景智能-2021秋季招聘软件技术笔试题(第二批)
  7. java 配置文件配置路径_详解java配置文件的路径问题
  8. 你用 Python 写过最牛逼的程序是什么?
  9. 十大营养食品和十大垃圾食物
  10. python items与iteritems