文件IO
1. 文件IO的概念
文件IO(系统IO):
操作系统提供的对文件进行输入输出操作的接口函数。
2. 文件IO的应用
2.1 打开文件(open)
/*
Name :
open - open and possibly create a file
*/
// Synopsis:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flagsm, mode_t mode);
pathname : 要打开或创建的文件名
flags : 打开一个文件的标志
-
O_RDONLY: 只读打开read only -
O_WRONLY: 只写打开write only -
O_RDWR: 读写打开read/write -
O_APPEND: 追加标志,对写入操作进行追加
它并不直接影响读取文件的操作。当使用该标志打开文件时,写入操作会自动将数据加到文件的末尾,而无论文件指针在那个地方。
这对于避免,并发写入时的竞争条件非常有用,确保写入的数据始终追加到文件的末尾。然而,对于读取文件的操作,该标志没有直接的影响,而是由文件指针的位置有读取操作决定。
-
O_CREAT: 创建标志,如果不存在,则创建它。 -
O_EXCL: 用来测试文件是否存在,该标志一般和O_CREAT配合使用 -
O_TRUNC: 文件截短,把文件内容清空 -
O_NONBLOCK: 非阻塞方式打开文件
- 非阻塞:”不等待“
如果文件没有内容,read不会阻塞,直接返回一个错误。
如果文件没有空间,write不会阻塞,直接返回一个错误。
阻塞:”等待“(默认的情况一般是阻塞)
如果文件没有内容,read会阻塞(等到有数据可读或出错)。
如果文件没有空间,write会阻塞(等到有数据可写或出错)。
多个选项(标志)使用 \(|\) 来进行连接,因为这些表标志其实都是使用“位域”实现的。
mode : 当第二个参数中,带有O_CREAT标志,则需要指定创建文件的权限。
(1) 使用系统定义的宏。
S_IRWXU /S_IRWXUG/S_IRWXO: 用户rwx/组用户rwx/其他用户rwx
S_IRUSR S_IWUSR S_IXUSR 用户
S_IRGRP S_IWGRP S_IXGRP 组用户
S_IROTH S_IWOTH S_IXOTH 其他用户
(2)使用一个八进制的数据来表示文件的权限
0777 : 111 111 111 --rwx rwx rwx
返回值:
(1)成功返回一个已经打开的文件的文件描述符( > 2 )
操作系统会自动为每个进程打开三个文件:
-
STDIN_FILENO标准输入文件 文件描述符为 0 -
STDOUT_FILENO标准输出文件 文件描述符为 1 -
STDERR_FILENO标准出错文件 文件描述符为 2
(2)失败返回-1,同时errno被设置。
-
errno: 是一个全局变量,定义在#include <errno.h>用来保存最后一个出错的错误码! -
perror: 把错误码对应的提示信息打印出来。
2.2 操作文件
read
/*
Name :
read - read from a file descriptor
*/
// Synopsis:
#include <unistd.h>
/*
read : 从一个文件描述符所指定的文件中读取文件的内容
*/
typedef ssize_t signed int;
typedef size_t unsigned int;
int read(int fd, void *buf, size_t count);
fd : 文件描述符,表示你要操作的文件
buf : 通用指针,指向一个可写的存储空间,用来保存读到的文件内容。
count : 表示你想要读取多少个字节大小的内容
返回值 :
> 0: 返回实际上读到的字节数= 0: 表示什么也没读= -1: 读取错误,同时设置error
write
/*
Name :
write - write to a file descriptor
*/
// Synopsis:
#include <unistd.h>
/*
write : 在一个文件描述符所指定的文件中写入文件内容
*/
int write(int fd, const void *buf, size_t count);
fd : 文件描述符,表示你要操作的文件
buf : 指针,指向一个存储空间,这个存储空间保存了将要写入到文件中去的内容。
count : 写入内容的字节数
返回值 :
> 0: 返回实际上写入的字节数= 0: 表示什么也没写= -1: 写入错误,同时设置error
lseek
/*
Name :
lseek - reposition read/write file offset
*/
// Synopsis:
#include <sys/types.h>
#include <unistd.h>
/*
lseek : 重新定位读/写时文件光标偏移量
*/
int lseek(int fd, int offset, int whence);
fd : 文件描述符
offset : 偏移量
whence : 定位方式,具体有如下三种
SEEK_SET: 基于文件开头位置定位SEEK_CUR: 基于当前光标位置定位SEEK_END: 基于文件末尾位置定位
返回值 :
>= 0: 新光标位置离文件开头的字节数。= -1: 失败,同时设置error
2.3 关闭文件(close)
close : 用于关闭一个已经打开了的文件
int close(int fd);
fd : 文件描述符,待关闭的文件
返回值 :
- 成功 0
- 失败 -1
3. 其他文件IO的应用
3.1 umask
/*
Name :
umask - set file mode creation mask
umask 设置一个文件在创建时权限的掩码
*/
// Synopsis:
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
mask : 指定文件的掩码
返回值 : 返回上一个文件掩码
3.2 getwd 与 getcwd
NAME
getwd getcwd
SYNOPSIS
#include <unistd.h>
char *getwd(char *buf);
getwd : 用于获取当前进程工作目录的绝对路径,并保存在buf指向的空间中。
@buf : 用来保存进程当前的工作目录的绝对路径 => “字符串”
返回值:
成功 buf
失败 NULL,同时errno被设置
// 警告: the 'getwd' function is dangerous and should not be used.
// 当buf的空间不够,则会有越界风险。
char *getcwd(char *buf, size_t size);
getcwd : 作用与 getwd 的作用是一样的,但是 getcwd 避免了越界的风险。
buf: 用来保存进程当前的工作目录的绝对路径 => “字符串”size: 指定buf指向的空间的最大长度。
如果当前工作目录的绝对路径字符串的长度超过size,此时这个函数在编译阶段就会报错。
3.3 chdir与fchdir
NAME
chdir fchdir
SYNOPSIS
#include <unistd.h>
chdir, fchdir : 都是用来改变进程的当前工作目录的
int chdir(const char *path);
int fchdir(int fd);
3.4 文件截短
NAME
truncate ftruncate
- truncate a flie to a specified length
SYNOPSIS
#include <unistd.h>
#include <sys/types.h>
truncate ftruncate : 用来给一个指定的文件截短到指定的长度。
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
fd : 指定要截短的文件
length : 截短后的文件内容的长度
返回值 :
- 0 成功
- -1 失败,同时
errno会被设置
3.5 删除一个文件
unlink : 删除一个文件
#include <unistd.h>
int unlink(const char *pathname);
rmdir : 删除一个空目录
#include <unistd.h>
int rmdir(const char * pathname);
remove : 删除一个普通文件或空目录
#include <stdio.h>
int remove(const char *pathname);
3.6 获取文件属性
stat fstat 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);
// 当pathname是一个符号链接时,lstat获取的是符号链接文本本身的属性信息。
int lstat(const char *pathname, struct stat *statbuf);
statbuf : 指向的结构体用来保存文件的属性信息。
返回值 :
- 0 成功
- -1 失败
struct stat {
dev_t st_dev; /* 文件设备号 */
ino_t st_ino; /* 文件的inode变换 */
mode_t st_mode; /* 文件权限与类型 */
/*
S_ISREG(st.st_mode) 普通文件 -
S_ISDIR(st.st_mode) 目录文件
dS_ISCHR(st.st_mode) 为真则表示该文件是 字符设备 c
S_ISBLK(st.st_mode) 块设备 b
S_ISLNK(st.st_mode) 符号链接 l
S_ISFIFO(st.st_mode) 管道文件p
S_ISSOCK(st.st_mode) 套接字 s
/*
nlink_t st_nlink; /* 硬链接数 */
uid_t st_uid; /* 文件所有者用户ID */
gid_t st_gid; /* 文件所有者组用户ID */
dev_t st_rdev; /* 设备号 (if special file) */
off_t st_size; /* 文件内容大小 */
blksize_t st_blksize; /* 块大小 */
blkcnt_t st_blocks; /* 该文件占多少块 */
struct timespec st_atim; /* 最后访问文件内容的时间 */
struct timespec st_mtim; /* 最后修改文件内容的时间 */
struct timespec st_ctim; /* 最后改变文件属性的世界 */
/*
char *ctime(const time_t *timep);
*/
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
4. 目录操作
4.1 目录与普通文件的区别
在Linux操作系统下,任何一个文件要存在,必须有一个inode。
普通文件的内容:"文件内容"
目录文件的内容:"目录项数组"
创建一个空目录时,系统为它预留一个"目录项数组"(4k => 40968)
当在这个目录下创建一个文件或目录,就是填充一个目录项到该"目录项数组"中去。
4.2 打开目录
在Linux中,用结构体类型
DIR来描述一个已经打开的目录
opendir fdopendir
#include <sys/types.h>
#include <dirent.h>
DIR* opendir(const char *name);
DIR* fdopendir(int fd);
name: 指定要打开的那个目录文件的文件名- 返回值
- 成功 返回一个
DIR*类型的指针 - 失败 返回NULL,同时设置
errno
- 成功 返回一个
4.3 读一个目录中的目录项
readir
#include <dirent.h>
struct dirent
{
ino_t d_ino; /* ino的编号 */
off_t d_off; /* 目录项的偏移量 */
unsigned short d_reclen; /* 结构体的长度 */
unsigned char d_type; /* 该目录项指向的那个文件的类型 */
char d_name[256];/* 该目录项指向的那个文件的名字 */
}
/*
用来从dirp指向的目录中,去返回下一个目录项(struct dirent)的指针。每调用一次readdir,就会返回下一个目录项的指针,直到返回NULL。
*/
struct dirent* readdir(DIR *dirp);
dirp:想要从哪个目录中读取下一个目录项- 返回值 : 返回下一个目录项的指针,如果读完了,则返回NULL。
4.4 关闭目录
closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);

浙公网安备 33010602011771号