一、IO
(一)IO与文件
- 文件:相关数据的集合。
- 文件系统:管理文件的工具。
- 文件存储的介质:长期的,固态存储。
- 扩展存储器:大容器、低成本、长期存储
- 扩展存储器种类:光盘、U盘、机械硬盘、固态硬盘
- 存储原理:
- 寻道:
- 寻址:
- Linux中文件类型(7种):
- 普通文件:-
- 目录文件:d
- 连接文件:l,软连接
- 管道文件:p
- 字符型设备文件:c
- 块设备文件:b
- 套接字文件:s,本地网络通信
(二)系统调用
- 系统调用(文件IO):操作系统提供给用户的一套API接口(函数),用于访问内核或硬件。文件IO无缓存IO。
- C库(标准IO):C语言或C编译器提供给用户的API接口(标准IO)。C库再调用系统调用,移植性更好。标准IO带缓存IO。
- 编程操作文件:
(三)函数五要素
- API接口函数的学习方法:
- 函数的五要素:
- 功能与作用:
- 头文件:库、#include
- 函数原型(函数声明):函数名字、有无返回值及其类型、有无参数,参数类型及其个数。
- 参数列表:参数的含义。
- 返回值:返回值的意义。
- Linux中系统提供的使用手册:man命令,用于查询系统使用手册。(windows操作系统的使用手册:F1。)
(四)标准IO
- 规范(专业术语):
- 头文件:#include <stdio.h>
- 流:stream,文件访问的流程,需要打开文件生成流,类似于银行卡,是操作文件的凭证,流指针:存放流地址的一个指针变量。程序上是一个结构体(类型为FILE),里面存放了文件名字,以及缓存,文件指针,描述符等。
- 流的文件指针:文件读写时,从该位置开开始进行读写,每次完成读写时,文件指针会相应移动。
- 文件访问流程:
- 打开文件,生成流。fopen()
- 读写文件。
- 关闭文件,关闭流,刷新缓存。fclose()
- 文件的缓冲:
- 无缓冲:任何读写都直接进行IO操作。
- 行缓冲:通过识别’\n’来确定是否需要进行IO操作。
- 全缓冲:通过缓存空间满了就进行IO操作。
- 标准输入输出流:当一个C程序运行时,即自动打开3个流。
- 标准输入流:stdin,scanf();默认行缓冲。
- 标准输出流:stdout,printf();默认行缓冲。
- 错误输出流:stderr,perror();默认无缓冲。
- 流的打开与关闭:
-
fopen():流的打开,使用fopen()+“w”创建文件时,会尝试以0666的文件权限创建文件,回受标准IO权限掩码限制,umask查看系统的权限设置。
-
作用:用于打开一个文件,生成一个流。
-
头文件:#include <stdio.h>
-
函数原型:FILE *fopen(const char *path,const char *mode)
-
参数列表:
-
path:文件名,字符串,含路径,若没有路径,默认当前工作目录。
-
mode:打开方式,字符串
- r:以只读方式打开文件,流的文件指针会定位到文件开头。若文件不存在,会报错。
- r+:可读可写方式打开,流的文件指针会定位到文件开头。若文件不存在,会报错。
- w:以只写方式打开文件,流的文件指针会定位到文件开头。若文件不存在,则自动创建该文件。若文件存在,会自动截短(原文件内容会被删除)。
- w+:可读可写方式打开,流的文件指针会定位到文件开头。若文件不存在,,则自动创建该文件。
- a:以追加的方式只写文件,打开文件,流的文件指针会定位到文件末尾。
- a+:以追加方式读写文件,打开文件,流文件指针定位到文件末尾,若文件不存在,自动创建该文件,打开文件,生成流后,若第一次操作是写文件,则文件指针定位到文件末尾;若第一次操作,是读文件,则文件指针定位到文件开始。
(Windows中C库有提供以下方式++)
- b:以二进制块形式打开文件,只读,流文件指针定位到文件开头,若文件不存在,报错。
- b+:以二进制块形式打开文件,可读可写,流文件指针定位到文件开头,若文件不存在,则创建该文件
-
-
返回值:返回打开文件的地址,FILE *;出错会返回NULL指针。
- 全局错误码(errornum):perror()函数用于打印错误码对应的错误提示信息。只能报错最近一次标准IO调用的错误码。
-
-
fclose():流的关闭
- 读写:
- 按字节读写:fegetc、fputc;读到EOF文件结束。
- 按行读写:fgets、fputs;读到’\n’文件结束。对文本文件有效,对二进制文件无效
- 作用:按行读取。
- 头文件:#include <stdio.h>
- 函数原型:char *fgets(char *s,int size,FILE *stream);
- 参数列表:
- s:数据读出时,存放的容器。
- size:容器大小。若需读的文件的一行数据量大于容器大小size,系统将该行的前size-1个字符存放到s中,末尾添加’\n’。
- 返回值:读到文件末尾,返回NULL,有数据被读出,返回s。
- 按块读写:fread、fwrite
- 作用:按块读取。
- 头文件:#include <stdio.h>
- 函数原型:
- size_t fread(void *ptr,size_t size, size_t nmembm,FILE *stream);
- size_t fwrite(void *ptr,size_t size, size_t nmembm,FILE *stream);
- 参数列表:
- ptr:容器地址。
- size:容器大小。若需读的文件的一行数据量大于容器大小size,系统将该行的前size-1个字符存放到s中,末尾添加’\n’。
- 返回值:读到文件末尾,返回NULL,有数据被读出,返回s。
- 一个程序中,流的最大限制:1024个,查看命令:ulimit -n。
- 缓存的手动刷新:fflush()。
- 缓存的设置:默认标准IO为1024字节。
- setvbuf():int setvbuf(FILE *stream, char *buf, int mode, size_t size);
(五)文件IO
- 文件IO:是系统调用,是Linux系统提供给用户的IO接口。
- 设计规范:遵循,可靠,简单,适应性强
- 文件描述符:是系统调用,用于标记或定位一个打开的文件或打开的设别或打开的套接字等。文件描述符是一个整型的正整数(0-1024)。
- 文件描述符表:是由系统维护的一个表(数组)。系统分配文件描述符,原则上,会提供最小的一个可用的文件描述符。
- 操作函数:
-
打开文件: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);
- 参数列表:
- pathname:文件名,带路径的文件名。
- flags:打开方式。
- 必须有,且只能有一个。
- O_RDONLY:只读方式打开。
- O_WRONLY:只写方式打开。
- O_RDWR:可读可写方式打开。
- 附加属性:可以多选项
- O_CREAT:若文件不存在,就创建,此时open原型为open2()。
- O_EXCL:若文件不存在就报错。
- O_NOCTTY:若打开的文件是一个终端文件,该文件不作为系统终端。
- O_TRUNC:若文件存在就截短。
- O_APPEND:追加模式打开文件。
- 必须有,且只能有一个。
- 返回值:
- >= 0:是一个新的,可用的文件描述符。
- == -1:错误
- perror():打印错误。
- 头文件:
-
读写文件:read();write();
- 头文件:#include <unistd.h>
- 函数原型:
- ssize_t read(int fd, void *buf, size_t count);
- ssize_t write(int fd, const void *buf, size_t count);
- 参数列表:
- fd:文件描述符,要操作的对象。
- buf:用户存放数据的容器
- count:
- 对于read而言,你想要读的数据长度,单位字节,通常为数据容器的大小。
- 对于write而言,你要写入的数据长度,单位字节。
- 返回值:
- < 0:出错。
- == 0:没有数据可写
- > 0:表示世界读出或写入的数据个数
-
关闭文件:close()
- 头文件:#include <unistd.h>
- 函数原型:int close(int fd);
-
文件指针移动:lseek();
-
头文件:
- #include <sys/types.h>
- #include <unistd.h>
-
函数原型:off_t lseek(int fd, off_t offset, int whence);
-
参数列表:
- fd:文件描述符。
- offset:偏移量。
- whence:基准点。
- SEEK_SET:基于文件开始。
- SEEK_CUR:基于当前位置。
- SEEK_END:基于文件末尾
-
返回值:
- == -1:错误
- >= 0:移动后,文件指针相对于文件头的位置
-
(六)目录操作
- 打开目录(opendir):
- 头文件:
- #include <sys/types.h>
- #include <dirent.h>
- 函数原型:DIR *opendir(const char *name);
- 参数列表:
- name:目录名
- 返回值:
- 成功,返回打开的目录目录流。
- 失败,返回NULL。
- 读目录(readdir):
- 头文件:#include <dirent.h>
- 函数原型:struct dirent *readdir(DIR *dirp);
- 参数列表:
- dirp:打开的目录目录流
- 返回值:
- 成功,返回一个结构体的地址,描述文件的一个结构体。
- 失败,NULL或读目录结束。
- 关闭目录(closedir):
- 头文件:
- #include <sys/types.h>
- #include <dirent.h>
- 函数原型:int closedir(DIR *dirp);
(七)文件的属性
- 获取文件属性:stat();
- 头文件:
- #include <sys/types.h>
- #include <sys/stat.h>‘
- #include <unistd.h>
- 函数原型:int stat(const char *pathname, struct stat *buf);
- 参数列表:
- pathname: 带路径的文件名
- buf: 结构体容器 ,用于存放文件的属性
struct stat {
dev_t st_dev; /* ID of device containing file /
ino_t st_ino; / inode number /
mode_t st_mode; / protection /
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; / blocksize for filesystem I/O /
blkcnt_t st_blocks; / number of 512B blocks allocated /
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 */
}
st_mode: 存放的是文件的权限 与类型
文件类型掩码: S_IFMT 0170000 bit mask for the file type bit field
S_IFSOCK 0140000 socket == [1 100]
S_IFLNK 0120000 symbolic link == [1 010]
S_IFREG 0100000 regular file == [1 000]
S_IFBLK 0060000 block device == [0 110]
S_IFDIR 0040000 directory == [0 100]
S_IFCHR 0020000 character device == [0 010]
S_IFIFO 0010000 FIFO == [0 001]
通过用户ID 得到用户名 :struct passwd *getpwuid(uid_t uid);