IO系统-文件与目录操作
1.文件内核数据结构
一个打开的文件在内核中使用三种数据结构表示:
(1)文件描述符表
文件描述符标志
文件表项指针
(2)文件表项:
文件状态标志:读、写、追加、同步和非阻塞等状态标志
当前文件偏移量
i节点表项指针
引用计数器
(3)i节点
文件类型和对该文件的操作函数指针
当前文件长度
文件所有者
文件所在的设备、文件访问权限
指向文件数据在磁盘上所在位置的指针等。
2. 原子操作
打开文件时使用O_APPEND标志,进程对文件偏移量调整和数据追加成为原子操作。
O_APPEND
write(){ //write成为一个原子操作
1)从i节点中读取文件长度作为当前偏移量
2)往文件中写入数据
3)修改i节点中文件长度
}
内核每次对文件写之前,都将进程的当前偏移量设置为该文件的尾端,这样不再需要lseek来调整偏移量。
(2)文件创建:
对open函数的O_CREAT和O_EXCL的使用,若该文件存在,open将失败,否则创建该文件,并且使得文件是否存在的判定和创建过程成为原子操作。
3. I/O处理方式
3.1 I/O处理的五种模型
阻塞I/O模型:若所调用的I/O函数没有完成相关的功能就会使进程挂起,直到相关数据到达才会返回,如:终端、网络设备的访问。
非阻塞模型:当请求的I/O操作不能完成时,则不让进行进程休眠,而且返回一个错误。如:open、read、write访问。
I/O多路转接模型:如果请求的I/O操作阻塞,且它不是真正的阻塞I/O,而且让其中的一个函数等待,在这期间,I/O还能进行其他操作,如:select函数。
信号驱动I/O函数:在这种模式下,通过安装一个信号处理程序,系统可以自动捕获特定信号的到来,从而启动I/O。
异步I/O模型:在这种模式下,当一个描述符已准备好,可以启动I/O时,进程会通知内核,由内核进行后续处理,这种用法现在较少。
3.2 非阻塞I/O
低速系统调用时,进程可能会阻塞
非阻塞I/O确定操作(read、open、write)不阻塞,如果操作不能完成,则出错返回。
设定非阻塞的方式:1、使用open打开文件,设置O_NONBLOCK标志;2、如果一个文件已经打开,则使用fcntl修改文件状态标志。
4. 高级文件操作-文件锁
当多个用户共同使用、操作一个文件的时候,Linux通常采用的方法是给文件上锁,来避免共享资源产生竞争的状态。
文件锁按功能分为:1、共享读锁:文件描述符必须读打开;一个文件上了读锁,其他进程也可以上读锁进行读取。2、独占写锁:1、文件描述符必须写打开;一个进程上了写锁,其它进程就不能上写锁和读锁进行写操作。
文件锁按类型分为建议锁和强制性锁。建议锁要求上锁文件的进程都要检测是否有锁存在,并尊重已有的锁。强制性锁由内核和系统执行的锁。
fcntl不仅可以实施建议锁而且可以实施强制性锁。
4.1 加锁和解锁区域的注意点
该区域可以在当前文件尾端处开始或越过其尾端处开始,但是不能在文件起始位置之前开始或越过该起始位置。
如若l_len为0,则表示锁的区域从其起点(由l_start和l_whence决定)开始直至最大可能位置为止。也就是不管添写到该文件中多少数据,它都处于锁的范围。
为了锁整个文件,通常的方法是将l_start设置为0,l_whence设置为SEEK_SET,l_len设置为0。
4.2 锁的继承和释放
一个进程终止,它所建立的锁全部释放;
关闭一个文件描述符,此进程对应该文件的所有的锁都释放;
子进程不继承父进程的锁;
执行exec以后,新进程可以选择是否继承原来执行进程的锁。
5. 存储映射
存储映射是一个磁盘文件与存储空间的一个缓存相映射,对缓存数据的读写就相应的完成了文件的读写。
5.1 调用函数
#include <sys/types.h>
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int port, int flags, int fd, off_t offset);
返回:若成功则为映射区的起始地址,若出错则为-1
功能:I/O使一个磁盘文件与存储空间中的一个缓存相映射。
int munmap(void *addr, size_t length);
返回:成功返回0,出错返回-1
功能:解除映射
mmap函数从缓存中获取数据,就相当于读文件中的相应字节,与其类似,将数据存入缓存,则相应字节就自动地写入文件,这样就可以在不使用read和write的情况下执行I/O。
子进程继承父进程的存储映射区。
参数:
addr:存储映射区的起始地址,通常设为0,让系统分配。
length:需要映射的字节数
offset:映射字节在文件中的偏移量
prot:PROT_READ映射区可读、PROT_WRITE映射区可写、PROT_EXEC映射区可执行、PROT_NONE:映射区不可访问
flags:MAP_FIXD返回地址必须等于addr,不推荐使用、MAP_SHARED存储操作立刻修改映射文件内容、MAP_PRIVATE存储操作导致创建映射文件的副本,并对副本读写。
6. 文件属性
struct stat是存放文件属性的结构体
struct stat{
mode_t st_mode; //file type & permission
ino_t st_ino; //i-node number
dev_t st_dev; //device number(file system)
dev_t st_rdev; //device number for special files
nlink_t st_nlink; //number of links
uid_t st_uid; //user ID of owner
gid_t st_gid; //group ID of owner
off_t st_size; //size in bytes
time_t st_atime; //time of last access
time_t st_mtime; //time of last modification
time_t st_ctime; //time of last file status change
blksize_t st_blksize; //best I/O block size最佳块大小
blkcnt_t st_blocks; //number of disk blocks allocated
};
6.1 文件属性操作函数
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *pathname, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
返回:若成功返回0,若出错则为-1
功能:返回一个与pathname或fd执行的文件属性信息,存储在结构体buf中。
参数:pathname:文件路径名称;buf:struct stat结构体指针。
lstat函数类似于stat,但是当命名的文件是一个符号连接时,lstat返回该符号连接的有关信息,而不是由该符号连接引用的文件的信息。
6.2 文件类型
文件类型 判别函数
普通文件(regular file) S_ISREG()
目录文件(directory file) S_ISDIR()
块特殊文件(block special file) S_ISBLK()
字符特殊文件(character special file) S_ISCHR()
FIFO(named pipe) S_ISFIFO()
套接字(socket) S_ISSOCK()
符号链接(symbolic link) S_ISLNK()
6.3 文件权限
9种文件访问权限:
用户权限:S_IRUSR、S_IWUSR、S_IXUSR
组权限:S_IRGRP、S_IWGRP、S_IXGRP
其它权限:S_IROTH、S_IWOTH、S_IXOTH
文件权限通过按位或方式构造。
6.4 文件权限相关函数
#include <unistd.h>
int access(const char *pathname, int mode);
返回:成功执行返回0,若出错为-1
功能:检查是否可以对指定文件进行某种操作
参数:pathname:文件路径;
mode:文件访问权限:
R_OK:判断文件是否有读权限;
W_OK:判断文件是否有写权限;
X_OK:判断文件是否有可执行权限;
F_OK:判断文件是否存在。
(2)umask函数
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask (mode_t mode);
返回:以前的文件模式创建屏蔽字(掩码)
功能:为进程设置文件方式创建屏蔽字,并返回以前的值
参数:mode:文件权限常量(如:S_IRGRP、S_IWGRP等)
被umask设置过的权限不能再使用在创建文件的权限上。
(3)chmod和fchmod函数
#include <sys/stat.h>
int chmod(const char * pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
返回:成功返回0,出错返回-1
功能:更改现存文件的权限。chmod函数在指定的文件上进行操作,而fchmod函数对已打开的文件进行操作。
参数:pathname:文件路径名字
mode:文件权限(按位或操作)
S_ISUID、S_ISGID、S_ISVTX
S_IRWXU、S_IRUSR、S_IWUSR、S_IXUSR
S_IRWXG、S_IRGRP、S_IWGRP、S_IXGRP
S_IRWXO、S_IROTH、S_IWOTH、S_IXOTH
想要改变一个文件的权限位,需满足条件:进程的有效用户ID必须等于文件的所有者ID或者进程具有超级用户权限。
(4)truncate和ftruncate函数
#include <sys/types.h>
#include <unistd.h>
int truncate(const char * pathname, off_t length);
int ftruncate(int fd, off_t length);
返回:成功返回0,出错返回-1
功能:文件截断
参数:pathname:文件路径名字;length:文件截断后的长度。
在文件尾端处截去一些数据以缩短文件。
将一个文件的长度截短为0是一个特例,用O_TRUNC标志可以做到这一点。
如果该文件以前的长度大于length,则超过length以外的数据就不再能存取。如果以前的长度短于length,则其后果与系统有关。
7. Linux文件系统结构
文件操作相关的最基本元素是:目录元素、索引节点和文件的数据本身。
目录结构(目录项)
索引节点(i节点)
文件的数据
(1)link和unlink函数
#include <unistd.h>
int link(const char *exitingpath, const char *newpath);
返回:成功返回0,出错返回-1
功能:创建一个指向现存文件连接(硬链接)
int unlink(const char *pathname);
返回:成功返回0,出错返回-1
功能:删除pathname指定的硬链接,并将由pathname所引用的文件链接计数-1
硬链接创建条件:针对文件创建链接,必须是同一个分区,只有超级用户才能对目录建立链接。
文件删除条件:链接计数为0,无其它进程打开该文件。
(2)remove和rename函数
#include <unistd.h>
int remove(const char * pathname);
返回:成功返回0,出错返回-1
功能:解除对一个文件或目录的链接
int rename(const char * oldname, const char * newname);
返回:成功返回0,出错返回-1
功能:文件或目录更名
对于文件,remove的功能和unlink相同
对于目录,remove的功能和rmdir相同
(3)symlink和readlink函数
#include <unistd.h>
int symlink(const char * actualpath, const char * sympath);
返回:成功返回0,出错返回-1
功能:创建一个符号链接(软链接)
int readlink(const char * restrict_pathname, char * restrict buf, size_t bufsize);
返回:成功返回读到的字节数,出错返回-1
功能:打开该链接本身,并读该链接中的名字
符号链接创建并不要求actualpath存在,可以跨文件系统建立符号链接,软链接也可以针对目录创建。
8. 文件时间
字段 |
说明 |
例子 |
ls选项 |
st_atime |
文件数据最后访问时间 |
Read |
-u |
st_mtime |
文件数据最后修改时间 |
Write |
默认 |
st_ctime |
i节点最后更改时间 |
chmod、chown |
-c |
(1)utime函数
#include <sys/types.h>
#include <utime.h>
int utime(const char * pathname, const struct utimebuf * times);
返回:成功返回0,出错返回-1
功能:更改文件的存取时间和修改时间
struct utimebuf{
time_t actime; //access time
time_t modtime; //modification time
};
参数times:
空指针则读取当前时间:进程的有效用户ID必须等于文件的所有者ID,或者进程对该文件具有写权限
非空取times结构体中的时间:进程有效用户ID等于该文件的所有者的ID,或者进程是超级用户进程。
utime操作会自动更新st_ctime值。
9. 目录函数
#include <sys/types.h>
#include <sys/stat.h>
int mkdir(const char * pathname, mode_t mode);
返回:成功返回0,出错返回-1
功能:创建目录
int rmdir(const char * pathname);
返回:成功返回0,出错返回-1
功能:删除目录
创建目录:创建一个新的空目录,.和..目录项是自动创建的。创建目录时,至少指定一个执行权限位。
目录删除条件:该目录的链接计数为2(只包含.和..),无其它进程打开目录。
(2)opendir、readdir、rewinddir和closedir函数
#include <sys/types.h>
#include <dirent.h>
DIR * opendir(const char * pathname);
返回:成功返回目录指针,出错返回NULL
功能:打开目录
struct dirent * readdir(DIR *dp);
返回:成功返回指针,若在目录结尾或者出错返回NULL
功能:读取目录
void rewinddir(DIR *dp);
功能:重新定位从头开始读取
int closedir(DIR *dp);
返回:成功返回0,出错返回-1
功能:关闭目录
struct dirent{
ino_t d_ino; //i-node number
char d_name[NAME_MAX+]; //null-terminated filename
};
#include <unistd.h>
int chdir(const char * pathname);
int fchdir(int fd);
返回:成功返回0,出错返回01
功能:分别用pathname或fd来指定新的当前工作目录
char *getcwd(char *buf, size_t size);
返回:成功返回buf,出错返回NULL
功能:获取当前工作目录的绝对路径名
当前工作目录是一个进程的属性,所以它只影响调用chdir的进程本身,而不影响其它进程。
问题:改变了路径是否会影响shell的当前路径?
不会影响。
10. 设备特殊文件
每个文件系统所在的存储设备都由主、次设备号表示;
major和minor宏可用来得到主、次设备号;
只有字符特殊文件和块特殊文件才有st_rdev值。
IO系统-文件与目录操作的更多相关文章
- Python之文件与目录操作及压缩模块(os、shutil、zipfile、tarfile)
Python中可以用于对文件和目录进行操作的内置模块包括: 模块/函数名称 功能描述 open()函数 文件读取或写入 os.path模块 文件路径操作 os模块 文件和目录简单操作 zipfile模 ...
- Shell命令-文件及目录操作之ls、cd
文件及目录操作 - ls.cd 1.ls:列出目录的内容及其内容属性信息 ls命令的功能说明 ls命令用于列出目录的内容及其内容属性信息. ls命令的语法格式 ls [OPTION]... [FILE ...
- 【转】Python之文件与目录操作(os、zipfile、tarfile、shutil)
[转]Python之文件与目录操作(os.zipfile.tarfile.shutil) Python中可以用于对文件和目录进行操作的内置模块包括: 模块/函数名称 功能描述 open()函数 文件读 ...
- Python之文件与目录操作(os、zipfile、tarfile、shutil)
Python中可以用于对文件和目录进行操作的内置模块包括: 模块/函数名称 功能描述 open()函数 文件读取或写入 os.path模块 文件路径操作 os模块 文件和目录简单操作 zipfile模 ...
- Java编程的逻辑 (59) - 文件和目录操作
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Python::OS 模块 -- 文件和目录操作
os模块的简介参看 Python::OS 模块 -- 简介 os模块的进程管理 Python::OS 模块 -- 进程管理 os模块的进程参数 Python::OS 模块 -- 进程参数 os模块中包 ...
- 零基础学Python--------第10章 文件及目录操作
第10章 文件及目录操作 10.1 基本文件操作 在Python中,内置了文件(File)对象.在使用文件对象时,首先需要通过内置的open() 方法创建一个文件对象,然后通过对象提供的方法进行一些基 ...
- Shell命令-文件及目录操作之cp、find
文件及目录操作 - cp.find 1.cp:复制文件或目录 cp命令的功能说明 cp命令用于复制文件或目录. cp命令的语法格式 cp [OPTION]... SOURCE... DIRECTORY ...
- Shell命令-文件及目录操作之mkdir、mv
文件及目录操作 - mkdir.mv 1.mkdir:创建目录 mkdir命令的功能说明 mkdir命令用于创建目录,默认情况下,要创建的目录已存在,会提示文件存在,不会继续创建目录. mkdir命令 ...
随机推荐
- spring的几个面试题
Spring 是一种轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性.Spring 官网:https://spring.io/. 我们一般说 Spring 框架指的都是 Spring Fr ...
- 盘一盘 Thread源码
线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 继承关系图 线 ...
- Java实现简单的学生成绩管理系统
ScoreInformation.java import java.util.Scanner; class ScoreInformation { private String stunumber ...
- 什么时候用for循环什么时候用while循环?
简述 for循环和while循环最大的区别在于[循环的工作量是否确定],for循环就像空房间依次办理业务,直到把[所有工作做完]才下班.但while循环就像哨卡放行,[满足条件就一直工作],直到不满足 ...
- 一款类似loadRunner的优秀国产压力测试工具——kylinTOP测试与监控平台
市面上流行的压力/负载/性能测试工具多是来自国外,近年来国内的性能测试工具也如雨后春笋般崛起,但大部分产品是基于Jmeter开源内核包装起来的性能测试工具,其中也不乏佼佼者,如:kylinTOP测试与 ...
- 深入JVM(二)JVM概述
深入JVM(一)JVM指令手册 深入JVM(二)JVM概述 一.JVM的原理 Java虚拟机是Java平台的基石,解决了硬件和操作系统的相互独立性.不同平台(Windows,Linux和MacOS)的 ...
- 使用element的upload组件实现一个完整的文件上传功能(下)
本篇文章是<使用element的upload组件实现一个完整的文件上传功能(上)>的续篇. 话不多说,接着上一篇直接开始 一.功能完善—保存表格中每一列的文件列表状态 1.思路 保存表格中 ...
- js中时间戳转换成xxxx-xx-xx xx:xx:xx类型日期格式的做法
1.十三位数字的时间戳转换方法 var time = new Date(datetime).toLocaleString().replace(/年|月/g, "-").replac ...
- 从头学pytorch(九):模型构造
模型构造 nn.Module nn.Module是pytorch中提供的一个类,是所有神经网络模块的基类.我们自定义的模块要继承这个基类. import torch from torch import ...
- 洛谷$P5329\ [SNOI2019]$字符串 字符串
正解:字符串 解题报告: 传送门$QwQ$ 有两个很妙的方法,分别港下$QwQ$ 首先为了表示方便,这里和题面一样设$s_i$表示去掉第$i$个字母得到的字符串.另设$lcp(i,j)$表示$suf_ ...