c/c++:文件IO(Linux系统IO、C标准库IO、标准C 库IO和 Linux系统IO的关系、虚拟地址空间)
程序员文章站
2022-06-07 14:28:46
...
目录
一、Linux系统IO和C标准库IO
1.1 标准C库IO函数
1.2 标准C 库IO和 Linux系统IO的关系
标准C 库IO:带缓冲区
Linux系统IO:不带缓冲区,(有些书上说Linux系统有缓存,那是内核的缓存,不是IO的缓存)
二、 虚拟地址空间
下图以32位机为例,2的32次方为4G,64位机是2的64次方,太大了不好画。
文件描述符表默认大小: 1024,每个进程启动之后, 都有一个文件描述符表,所以每个进程默认能打开的文件个数: 1024
前三个文件文件描述符是默认被使用了的: - 标准输入 -> 0, 标准输出 -> 1, 标准错误 -> 2
除去被占用的每个进程默认能打开的文件个数: 1021
三、Linux系统IO函数
- errno -> 属于Linux系统函数库, 库里边的一个全局变量, 记录的是错误号
#include <stdio.h>
void perror(const char *s); - s参数: 用户描述, 比如:hello
perror打印的是errno对应的错误描述, 实际输出: hello: xxxxx(实际的错误描述)
- open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// open函数
// 打开一个已经存在文件
int open(const char *pathname, int flags);
参数:
- pathname: 要打开的文件路径
- flags: 对文件的操作权限设置
- O_RDONLY, O_WRONLY, O_RDWR 这三个设置是互斥的
返回值:
// 使用open创建一个新文件
int open(const char *pathname, int flags, mode_t mode);
参数:
- pathname: 要打开的文件路径
- flags: 对文件的操作权限设置
- 必选项: O_RDONLY, O_WRONLY, O_RDWR 这三个设置是互斥的
- 可选项: O_CREAT -> 文件不存在, 创建新文件
- mode: 八进制的数, 表示用户对创建出的新文件的操作权限, 比如: 0775, mode & ~umask
0777 -> 111111111
0775 -> 111111101
&
0775 111111101
按位与: 0和任何数都为0
- close
#include <unistd.h>
int close(int fd);
- read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
- fd: open得到的, 通过这个fd操作某一个文件
- buf: 缓冲区, 存储读到的数据, 数组的地址
- count: buf的大小
返回值:
- 成功:
>0: 返回实际读到的字节数
==0: 文件已经读完了
- 失败: -1
- write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
- fd: open得到的, 通过这个fd操作某一个文件
- buf: 要往磁盘写入的数据
- count: 要写的数据的实际大小
返回值:
成功: 实际写入的字节数
失败: -1
- lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:
- fd: open得到的, 通过这个fd操作某一个文件
- offset: 偏移量
- whence:
SEEK_SET
设置文件指针的偏移量
SEEK_CUR
设置偏移量: 当前位置 + 第二个参数的值
SEEK_END
设置偏移量: 文件大小 + 第二个参数的值
int fseek(FILE *stream, long offset, int whence);
// 1. 移动文件指针到文件头
lseek(fd, 0, SEEK_SET);
// 2. 获取当前文件指针的位置
lseek(fd, 0, SEEK_CUR);
// 3. 获取文件长度
lseek(fd, 0, SEEK_END);
// 4. 拓展问长度, 当前文件10b, 110b, 增加的字节的0
lseek(fd, 100, SEEK_END);
// 要进行一次写操作
write(fd, " ", 1);
四、Linux其他系统函数
- stat / lstat
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
blksize_t st_blksize; //块大小(文件系统的I/O 缓冲区大小)
blkcnt_t st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
关于变量 st_mode:
- st_mode -- 16位整数
○ 0-2 bit -- 其他*限
- S_IROTH 00004 读权限
- S_IWOTH 00002 写权限
- S_IXOTH 00001 执行权限
- S_IRWXO 00007 掩码, 过滤 st_mode中除其他*限以外的信息
○ 3-5 bit -- 所属组权限
- S_IRGRP 00040 读权限
- S_IWGRP 00020 写权限
- S_IXGRP 00010 执行权限
- S_IRWXG 00070 掩码, 过滤 st_mode中除所属组权限以外的信息
○ 6-8 bit -- 文件所有者权限
- S_IRUSR 00400 读权限
- S_IWUSR 00200 写权限
- S_IXUSR 00100 执行权限
- S_IRWXU 00700 掩码, 过滤 st_mode中除文件所有者权限以外的信息
○ 12-15 bit -- 文件类型
- S_IFSOCK 0140000 套接字
- S_IFLNK 0120000 符号链接(软链接)
- S_IFREG 0100000 普通文件
- S_IFBLK 0060000 块设备
- S_IFDIR 0040000 目录
- S_IFCHR 0020000 字符设备
- S_IFIFO 0010000 管道
- S_IFMT 0170000 掩码,过滤 st_mode中除文件类型以外的信息
(st_mode & S_IFMT) == S_IFREG
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
参数:
- pathname: 操作的文件的路径
- buf: 结构体变量, 传出
struct stat st;
stat("hello.txt", &st);
stat是一个int类型数据,一个int数据可以表示32位2进制数,具体如下:
- opendir 目录遍历函数
DIR *opendir(const char *name);
参数:
- name: 要打开的目录
返回值: DIR *
struct dirent
{
ino_t d_ino; // 此目录进入点的inode
ff_t d_off; // 目录文件开头至此目录进入点的位移
signed short int d_reclen; // d_name 的长度, 不包含NULL 字符
unsigned char d_type; // d_name 所指的文件类型
har d_name[256]; // 文件名
};
d_type
DT_BLK - 块设备
DT_CHR - 字符设备
DT_DIR - 目录
DT_LNK - 软连接
DT_FIFO - 管道
DT_REG - 普通文件
DT_SOCK - 套接字
DT_UNKNOWN - 未知
struct dirent *readdir(DIR *dirp);
- 返回一个结构体, 这个对应一个文件
int closedir(DIR *dirp);
上一篇: 练习7-8 方阵循环右移 (20分)