- 作者: 雪山肥鱼
- 时间:20210625 06:39
- 目的:I/O device
# 文件与目录
# 相关API介绍
## 创建文件
## 读写文件
## 读写文件,不按顺序
## fsync() 强行写入
##
文件 与 目录
每个文件在底层都会有一个 low - level 名字 即 inode number。从OS的角度来看是不知道你存储的文件格式的,是视频?音频? 还是代码?并不关心。读数据就完事儿了
目录与文件相似,也有 low-level 的名字。但是low-level的内容比较特殊。是一个pairs
- 目录名
- inode
比如有目录 foo,则 ("foo", 10) 影射了目录名与inode.
目录中的每一项要么是文件,要么是其他目录。通过目录套目录的方式,可以构建目录树,存放了文件与目录。
目录树.png
相关API 介绍
创建文件
int fd = open("foo", O_CREAT|O_WRONLY|O_TRUNC, SIRUSR|S_IWUSR);
文件描述符 fd file descriptor.
fd 是一个整数,每个进程独有,在linux中用fd去访问文件资源。一个文件被打开,只要你获得许可,就可以利用fd去读写文件。
- 这就让fd成为了一种能力或者说权限
- 也可以将fd认为一个指针,指向文件句柄,即吻技安资源。
读写文件
利用strace 去追踪函数的系统调用
strace cat foo
图片.png
实际的输出要比上图多很多。
大文件的拷贝可以 尝试 dd
strace dd if=a.out of=b.out //以块大小拷贝文件
读写文件,不按顺序
通常的读写文件都是从第一行读到最后一行。但是也会有业务需求从中间,或者文件的某个位置开始操作。
比如,在文本中构建了索引,并利用它来寻找特定的单词。
off_t lseek(int fd, off_t offset, int whence)
参数 whence,搜索执行的方式
- SEEK_SET
the offset is set to offset bytes, 设置到 offset - SEEK_CUR
the offset is set to its current location plus offset bytes, 当前位置+offset - SEEK_END
the offset is set to the size of file plus offset bytes, 文件结尾处 + offset 位置
lseek 不会 导致磁盘I/O的自动发生
lseek只是修改内存中的变,这个变量代跟踪了(即返回值 offset)进程,下一个读取或写入的偏移量。lseek 肯定会导致在即将进行的读取或写入中进行搜索。但不会导致任何磁盘I/O 的发生。**也就是说 只是纯粹的定位功能,并不代表主动向disk提出I/O请求。
当发送给disk 的读写 与上次读写不在同一个磁道上,才会出现磁盘寻道,磁头才会移动。
fsync() 强行写入
调用write() 只是告诉文件系统,请在将来的某个时刻,将数据写进磁盘。并不会立即写入,只是将内容写在buffer中。何时写入 由OS决定。所以会有丢掉数据的风险。
但是类似数据库这种系统,需要将文件内容立即写入
int fd = open("/root/.../foo", O_CREAT|O_WRONLY|O_TRUNC);
assert(fd > -1);
int rc = wirte(fd, buffer, size);
assert(rc == size);
rc = fsync(fd);
assert(rc == 0);
在某些情况,fsync还需要包含绝对路径,因为同时也要修改目录信息。细节的忽略,会导致应用程序级别的错误。
文件的重命名
mv 操作实际上调用的是 系统api: rename(char * old, char * new) 。
是一种原子操作。
获取文件信息
除了访问文件的内容,文件也有自己的信息。这些信息就是文件的 metadata 元数据。可以使用state or fstate命令你个查看
sturct stat {
dev_t st_dev; //所处设备
ino_t st_ino; // inode number
mode_t st_mode; //权限
nlink_t st_nlink;; //numbers of hardlinks
uid_t st_uid; //user ID of owner
gid_t st_gid; //group id
dev_t st_rdev; //device id
off_t st_size;//total size, in bytes
blksize_t st_blksize;// file system I/O 中 block 大小(扇区组成的大小)
blkcnt_t st_blocks; //分配了多少个 blocks
time_t st_atime // 最后一次访问的时间
time_t st_mtime; //最后一次修改的时间
time_t st_ctime; //最后一次状态修改的时间
}
metadata of a file.png
每个文件系统都有 inode, inode number 指向一片文件资源信息。所以metadata中,我觉得最重要的就是这个信息。
创建目录
目录你是不能直接写的,因为目录的内容是 metadata. 你只能间接的去更新目录。比如在目录下新增文件。就会间接的更新目录。
mkdir创建目录会默认的隐藏两个文件
- . 当前文件
- .. 父目录
读目录
int main( int argc, char **argv) {
DIR * dp = opendir(".");
assert(dp != NULL);
struct dirent *d;
while((d = readdir(dp)) != NULL) {
printf("%lu %s\n", (unsigned log) d-> d_ino, d->d_name);
}
closedir(dp);
return 0;
}
}
struct dirent {
char d_name[256]; //file name
ino_t d_ino; // inode number
off_t d_off; // offset to the next dirent
unsigned short d_reclen; // length of this record
unsigned char d_type
}
Hard link & Symbol link
Hard link
当执行 link(old file , new file) 的时候。 类似下图。
图片.png
其实几个文件同时hard linke 到文件资源。三者指向同一处。当file 的 内容更改了,三个文件同时更改。
hard link file.png
硬链接所创建出来的文件是 regular file。
所以 linux 的删除文件采用的时 unlink 的系统调用,当links内容
Symbol link
Symbol link
ln -s file.old file.new
- Symbol link 不会增加 links 的 count ,所以就不是一个 regular file
- Symbol link 的 类型是 l 我们把他想象成 windows上的 快捷方式就行
-
当把连接 指向的文件删除后会出现以下情况
灰色了.png -
软连接的大小 与 文件长度有关
4b.png
15b.png
挂载文件系统
制作文件系统
mkfs 创建 文件系统。 比如 ext3,
a. 已知设备的一个分区 /dev/sda1
b. 制作文件系统
c. mount 挂在文件系统
假设有一个未挂载的ext3 文件系统,存储在设备分区/dev/sda1 中。它的内容包括 根目录 和 两个子目录 a 和 b。每个子目录里都有一个 foo的文件。假设文件向挂在 /home/user 上。则:
mount -t ext3 /dev/sda1 /home/users
然后可以访问 /home/users/a/foo
文件系统树上可以挂在很多不同的文件系统
- ext3/4 (标准的基于磁盘的文件系统)
- proc (用于访问当前进程信息的文件系统)
- AFS (分布式文件系统)
网友评论