1.介绍
文件IO是posic(可移植操作系统接口)定义的一组函数,他不提供缓冲机制,每次读写操作都引起系统调用。他的核心概念是文件描述符,它能访问各种类型的文件。在Linux下,标准IO基于文件IO实现。
-
文件IO遵循POSIX标准,文件IO实际使用系统调用函数。
-
标准IO适用于操作普通文件,文件IO适用任意类型文件
-
标准IO通过流唯一标识一个文件,文件IO通过文件描述符唯一标识一个文件
2.文件描述符
- 对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个按顺序分配的非负整数。
- 当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write。
- 因为文件创建时默认打开三个特殊流,占编号0、1、2,所以再打开的文件其编号按顺序就会是3.
三个特殊流的文件描述符:
标准输入 stdin — 0
标准输出 stdout ---- 1
标准错误 stderr ----- 2
注:是按顺序进行编号
所以如果再关闭如标准输出stdout,此时编号1也释放,则再打开个新文件,其编号就是1
3.文件IO相关系统调用函数
(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);
返回值:成功则返回文件描述符,失败返回-1,
参数:pathname :文件名(可含路径)
flags : 从以下宏选其一作为参数
O_RDONLY :以只读方式打开文件
O_WRONLY :以只写方式打开文件
//与标准IO的写不同,文件IO只是覆盖要写的部分,没有写的位置不改变其原文件内容
O_RDWR :以读写方式打开
O_CREAT :文件不存在时则创建新文件,并用mode设置其文件权限
O_EXCL :一般和O_CREAT联合使用,检测文件是否存在,存在则终止创建并产生错误
O_APPEND :以追加方式打开文件,在文件末尾另起一行继续写入
O_TRUNC :打开文件之后,会将原文件清空 //同一个参数需要多个宏作为参数时,可通过|(按位或)的方式联合输入
//需要新建文件(普通文件)时才需要输入mode参数,而且flag为O_CREAT。另外mode用于给新建文件设置初始权限,一般为0664
//文件最终实际权限=初始权限&(~umask),umask称为权限掩码
mode :文件权限(三位八进制数,如0664)
(2)读写文件
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:fd :读取文件的文件描述符
buf :用户自定义的缓冲区,用于存放读取的内容
count :请求读取的字节数//若文件大小小于请求读取的大小,则有多少读多少
返回值:成功则返回读取到的字节数,失败返回-1,读到文件末尾返回0
4.目录操作
(1)打开目录
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
参数:name:要打开的目录名
返回值;成功返回目录流指针,失败返回NULL
(2)读取目录
readdir一次只能读取一个目录项且为随机读取,(隐藏文件也可以读)
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
返回值:成功返回一个指向dirent结构体的指针,读取到目录流的末尾则返回NULL不产生新错误号,如果读取发生错误返回NULL且产生相应错误号
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 */
};
一般使用char d_name[256]参数,即读取到的文件名
(3)关闭目录
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
参数:DIR 目录流指针
返回值:成功返回0,失败返回-1
(4)获取文件属性 lstat
#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);//能获取链接文件本身信息
一般使用lstat,
参数:
pathname :文件名
statbuf :stat结构体的地址
返回值:成功返回0,失败返回-1
stat结构体定义:
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
};
将文件信息结构体中的用户id和组id转换用户名和用户组名的函数 getpwuid() getgrgid()
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);
passwd结构体定义如下:
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
#include <sys/types.h>
#include <grp.h>
struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);
group结构体如下:
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
关于文件类型和权限的转换,先看lstat关于mode的介绍
如下:
This field contains the file type and
mode. See inode(7) for further infor‐
mation.
//说明需要查看inode的第7页,所以
man 7 inode
然后找到文件类型掩码
S_IFMT 0170000 bit mask for the file type bit field
S_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
转换规则:如果st_mode & S_IFMT 等于对应文件类型宏,则文件类型宏对应类型就是该文件类型
往下翻能找到权限掩码
The following mask values are defined for the
file mode component of the st_mode field:
S_ISUID 04000 set-user-ID bit (see execve(2))
S_ISGID 02000 set-group-ID bit (see below)
S_ISVTX 01000 sticky bit (see below)
S_IRWXU 00700 owner has read, write, and execute permission
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 group has read, write, and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others (not in group) have read, write, and
execute permission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
转换:st_mode & 对应权限宏 ==宏本身 ,表示具有该权限
//补充要想判断某一位是0还是1,可以 st_mode & (1<<i)
// 该表达式值为0,则说明st_mode的第i+1位为0,
// 该表达式的值非0,这说明i+1位为1.