系统IO: 不带缓冲的IO,其是基于标准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);
功能:打开一个文件并返回这个文件的描述符
文件描述符:就是文件表项的下标 文件表项就是一个矢量 即数组!
数组中存储了文件描述符和文件指针!文件描述符本质就是这个文件指针在数组中的下标!
参数:pathname:带路径的文件名
flags:打开文件的标志,可以使用位或的我形式添加一下成员:
O_WRONLY :只写权限
O_RDONLY :只读权限
O_RDWR :可读可写权限
以上三个标志必须并且只能选择其中一个!
可以位或一下几个:
O_APPEND :追加方式 写数据到文件末尾
O_CREAT :创建标志,如果文件不存在就创建,存在则打开。
O_EXCL :该标志一般与O_CREAT一起使用,用来测试文件是否存在,如果存在且是一个普通文件则报错,
如果不存在则创建!
O_NONBLOCK :非阻塞方式打开文件
关于阻塞和非阻塞学习第二阶段进程时会讲!
O_TRUNC : 截断标志 假如文件存在且是一个普通文件,而且打开的方式是O_RDWR 或者
O_WRONLY,那么文件就会被清空!
前两个参数是第一个open函数和第二个函数共有的参数,第三个参数只有当第二个参数flags中有
O_CREAT 时才有意义:
mode :打开创建文件的权限:有两种方式确定!
1、使用以下的固定宏 以下宏可以位或使用
S_IRWXU 00700 user (file owner) has read, write and execute
permission
文件所有者可读可写可执行权限
S_IRUSR 00400 user has read permission
文件所有者可读的权限
S_IWUSR 00200 user has write permission
文件所有者可写权限
S_IXUSR 00100 user 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 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
2.通过8进制形式指定
0 八进制 八进制 八进制·
文件所有者权限 用户组权限 其他用户权限
1 1 1
r w x 分别对应一个八进制位,只要该位为1,即拥有此权限!
ex:0710 意思是什么? 所有可读可写可执行,用户组可执行 其他用不可写不可读不可执行!
返回值:成功返回一个非负数即文件描述符,失败返回-1;错误存放在errno!
关闭文件:
#include <unistd.h>
函数原型 int close(int fd);
参数:fd open的返回值,即一个文件描述符
返回值: 成功返回0 失败返回-1;
2、读写一个文件:
读取:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
功能:从文件描述符fd所指的文件中读取count个字节的数据到buf所指的内存中!
参数: fd 文件描述符 open的返回值!
buf 存储读取数据的内存的首地址
count 读取数据的大小!
返回值:成功返回读取到数据的字节数,失败返回-1;
返回值 与 count的关系是什么? 返回值<=count!
返回值:
>0说明读取到了数据 并且数据大小就是 返回值的大小
=0 说明文件已经读完了!
<0 说明出错了!
写:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:将buf所指的内存中的count个字节的数据写入到fd这个文件中!
参数:fd 文件描述符 open的返回值!
buf 存储写入数据的内存的首地址
count 写入数据的大小!
返回值: 成功返回 成功写入数据的大小
失败返回 -1;
返回值 与count 的关系? 返回值<=count!
>0 :说明写入了返回值大小的数据
=0 :说明什么东西都没写进去!
<0 :写入失败!最典型的写入失败就是没有权限操作时的写入!
作业:使用系统IO实现cp指令!
3、定位
lseek:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:fd 文件描述符
offset 偏移量
whence 从哪里开始偏移 有以下三个取值
1、SEEK_SET 从文件头开始偏移 此时 offset只能为正
2、SEEK_END 从尾巴开始偏移
3、SEEK_CUR 从当前位置开始偏移 偏移量可正可负 正为向后偏移 负为向前偏移!
返回值:成功返回当前光标位置相对于文件头的距离!
失败返回-1!
写一个函数求文件的大小!
4、删除一个空目录或者普通文件
remove
#include <stdio.h>
int remove(const char *pathname);
功能:删除一个普通文件或空目录
参数:带路径的文件名或空目录名!
返回值:成功返回0 失败返回-1;
作业:实现mv指令:
移动或者重命名文件的!
注意:区别移动还是重命名!如何区别?此时我们先用文件后缀名来区别!如果后缀名
相同则为重命名,不同则为移动!
mv 实现: cp + remove
5、获取文件属性即文件信息和状态《小写的LL能查看当前目录下所有文件的状态信息》
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
功能:
stat 用来将path指定的文件的信息和状态保存到buf 所指的内存空间中!
fstat 与stat函数类似,其试讲fd这个已经打开的文件的信息和状态保存到buf所指的内存空间!
lstat 与stat函数类似,只不过,当path符号链接的时候,获取的是链接本身的状态和信息,而不是他所指的
文件,也就是说stat函数观察不到符号链接的状态,要使用lstat函数观察!
符号链接: 就是软连接 其实就是一个快捷方式!
硬链接: 其实就是一个备份!
参数: path 带路径的文件名!也可以是路径
如果linux库函数中见到path 指的就是路径 也可以是带路径的文件!
如果见到 pathname 一定是带路径的文件名!不能是路径!
fd 文件描述符 使用open打开文件的返回值!
buf 类型是 struct stat * 结构体指针,这个执行执行一个结构体是用来保存文件状态信息的!
struct stat {
dev_t st_dev; /* ID of device containing file */ 文件的设备编号
ino_t st_ino; /* inode number */ i节点号
mode_t st_mode; /* protection */ 文件的类型或者存储权限
nlink_t st_nlink; /* number of hard links */ 链接到该文件的硬链接数目,刚建立该文件是为1!
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; /* blocksize for filesystem I/O */ IO文件系统的缓冲区大小
blkcnt_t st_blocks; /* number of 512B blocks allocated */ 占用文件区块的个数,每个区块大小为512个字节
time_t st_atime; /* time of last access */ 最后一次存取的时间
time_t st_mtime; /* time of last modification */ 最后一次修改的时间
time_t st_ctime; /* time of last status change */ 最后一次更改权限或者用户状态(用户所有者)的时间
};
重点要看到的是st_mode这个成员:
这个成员变量包含了文件的权限和文件类型!
文件权限通过位与的形式得到
S_IRWXU 00700 mask for file owner permissions
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 mask for group permissions
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 mask for permissions for others (not in group)
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
一般不怎么常用,就是在做文件系统时要考虑!
文件的类型是通过以下的宏定义得出的:
S_ISREG(m) is it a regular file?
如果这个宏的真值为1 就说明这个文件是一个普通文件!
S_ISDIR(m) directory?
如果这个宏的真值为1则说明该文件是一个目录文件,就是一个文件夹!
S_ISCHR(m) character device?
如果这个宏的真值为1则说明该文件是一个字符设备文件:学驱动的时候会将!
S_ISBLK(m) block device?
如果这个宏的真值为1 则说明该文件是一个块设备文件
S_ISFIFO(m) FIFO (named pipe)?
如果这个宏的真值为1 则说明该文件是一个管道文件,在学习进程间通信是会讲!
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
如果这个宏的真值为1则说明该文件是一个软连接文件,这个再1996年之前的系统中没有!
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
如果这个宏的真值为1则说明该文件是一个网络文件,这个再1996年之前的版本中也没有!
以上宏中的m就是st_mode的值!
返回值:成功返回0,失败返回-1;错误存放在errno!
错误编号解析:
ENOENT 参数path指定的文件或目录不存在!
ENOTDIR 参数path所指的目录存在,但不是一个真正的目录!
ELOOP 准备打开的文件有过多的符号链接问题,一个设备或者文件最多能有多少个符号链接?上限为16个
EFAULT 参数buf是一个无效的指针,指向了非法的区域!比如buf指向.rodata区!
char *p = "123456";
*p = 'a';对吗? 不对!原因是 p是一个指针,指向一个字符串的首地址!这个字符串存放在常量区!
char q[] = "123456";
*q = 'a';对吗?对,原因是q是一个字符数组,修改该数组中的第一个成员是合法的!
练习:mv指令实现判断重命名和移动的方式使用stat来实现!发邮箱!
6、目录结构和目录操作
linux底下用小写LL能查看当前目录下所有的文件状态。
1、创建和删除一个目录!
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
参数: pathname 带路径的文件名,(在linux下所有东西都是文件)
mode 同open的mode 有两种方式确定!
1、使用以下的固定宏 以下宏可以位或使用
S_IRWXU 00700 user (file owner) has read, write and execute
permission
文件所有者可读可写可执行权限
S_IRUSR 00400 user has read permission
文件所有者可读的权限
S_IWUSR 00200 user has write permission
文件所有者可写权限
S_IXUSR 00100 user 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 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
2.通过8进制形式指定
0 八进制 八进制 八进制·
文件所有者权限 用户组权限 其他用户权限
1 1 1
r w x 分别对应一个八进制位,只要该位为1,即拥有此权限!
返回值:成功返回0 失败返回-1,错误存放在errno中!
删除一个目录
#include <unistd.h>
int rmdir(const char *pathname);
参数:要删除的目录名,成功返回0 失败返回-1;
2、打开一个目录:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
参数:name 要打开的目录名称!
fd 打开的目录文件描述符!
返回值:成功返回目录指针,失败返回NULL;
目录指针:实质是一个指针,指向一个目录!
关闭一个目录
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR* drip);
3、读取目录
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
参数:从dirp指向的目录中,读取下一个目录项!一般为opendir的返回值!
返回值:成功返回读取到目录的地址,并将目录指针指向下一个目录项!失败返回NULL!
目录信息结构体:
struct dirent {
ino_t d_ino; /* inode number */ i 节点号
off_t d_off; /* not an offset; see NOTES */ 在目录文件中的偏移量!
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]; /* filename */ 文件名
};
如何实现ls?
ls 是干嘛的?列举当前文件下所有的文件的!
先实现一个不带参数的!
第一步打开目录
读目录 读一个打印其中一个的名字!
如何实现带参数的ls!
linux 下 以.开头的文件都是隐藏文件!
4、改变当前工作路径
#include <unistd.h>
int chdir(const char *path);
int fchdir(int fd);
参数:目标路径
5、获取当前工作路径
#include <unistd.h>
char *getwd(char *buf);
参数 :保存的路径名!
getwd 该函数会报一个与gets一样的警告,原因是该函数不会检测 buf是否越界!
作业:
1、实现完整的mv指令 方法已经讲过了!先复制 再删除 然后注意区分是重命名还是移动!
如果是移动则第二个参数就是一个目录文件 此处就可以做了!
2、使用递归实现目录的打印,注意跳过当前目录和上一级路!
这两道题目发邮件!2452476922@qq.com!