目录
- 文件IO是不带缓冲区的。
- 文件IO函数是由操作系统提供的,与操作系统绑定,又称之为系统调用。
- 标准IO是通过流指针维护一个文件,文件IO是通过文件描述符来维护一个文件。
文件描述符
1. 概念
- 尝试打开一个文件的时候,系统会自动给这个文件分配一个编号,用这个编号来描述这个文件。这个编号就是文件描述符。
- 文件描述符的本质:数组下标。在main函数启动前,操作系统会帮助我们在用户空间创建一个数组(文件描述符表),且容量默认为1024. 范围是[0, 1023]
- 文件描述符申请原则:从小到大依次遍历,直到遇到没有被使用的文件描述符
2. 特殊的文件描述符
特殊的流指针 | 特殊的文件描述符 | |
FILE* stdin | stdin->_fileno | 0 |
FILE* stdout | stdout->_fileno | 1 |
FILE* stderr | stderr->_fileno | 2 |
结果为0 1 2
3. 文件描述符的总量
默认是1024个
- 循环打开不关闭,直到超出打开上限,得到文件描述符总量。
- getdtablesize()函数:获取操作系统的文件描述符总量。 printf("%d\n", getdtablesize());
文件IO的函数
1.open
功能:打开一个文件;
原型:
#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);
参数:
char *pathname:指定要打开的文件的路径和名字;
int flags:打开方式
O_RDONLY 只读,
O_WRONLY 只写,
O_RDWR 读写
----以上三种必须包含一种----------
O_APPEND 追加方式打开,
O_TRUNC 清空,若文件存在,且是一个普通文件,且以写的方式打开
O_CREAT 若文件不存在,则创建一个普通文件。
若有多个选项合成一个打开方式,则用按位或连接:
"w":O_WRONLY | O_CREAT | O_TRUNC
mode_t mode:用来指定文件创建的时候的权限,例如:0664
若flags中包含了O_CREAT或者O_TMPFILE的时候,就必须写mode参数;
若flags没有O_CREAT或者O_TMPFILE的时候,会忽略mode参数;
返回值:
成功,返回文件描述符,
失败,返回-1,更新errno;
代码展示
标准IO中的 r r+ w w+ a a+,用文件IO中的flags进行组合。
┌─────────────┬───────────────────────────────┐
│fopen() mode │ open() flags │
├─────────────┼───────────────────────────────┤
│ r │ O_RDONLY │
├─────────────┼───────────────────────────────┤
│ w │ O_WRONLY | O_CREAT | O_TRUNC │
├─────────────┼───────────────────────────────┤
│ a │ O_WRONLY | O_CREAT | O_APPEND │
├─────────────┼───────────────────────────────┤
│ r+ │ O_RDWR │
├─────────────┼───────────────────────────────┤
│ w+ │ O_RDWR | O_CREAT | O_TRUNC │
├─────────────┼───────────────────────────────┤
│ a+ │ O_RDWR | O_CREAT | O_APPEND │
└─────────────┴───────────────────────────────┘
2.umask
the mode of the created file is (mode & ~umask).
文件创建时候的真实权限是 mode & ~umask
mode : 0777 ----> 111 111 111
umask? 111 111 101==> ~umask ---> umask = 000 000 010 = 0002
结果: 0775 ----> 111 111 101
i. umask是什么
文件权限掩码,目的就是影响文件创建时候的权限。可以通过设置umask的值保证某些用户肯定没有某些权限。
ii. 获取umask的值
终端输入:umask
iii. 修改umask的值
- 终端输入: umask 0 只在设置终端有效
- umask()函数
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
umask(0);
3.close
功能:关闭文件; 释放文件描述符;
原型:
#include <unistd.h>
int close(int fd);
参数:
int fd:指定要关闭的文件描述符;
返回值:
成功,返回0;
失败,返回-1,更新errno;
4.write
功能:将数据写入到文件中;
原型:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
int fd:指定要将数据写入到哪个文件中,填对应的文件描述符;
void *buf:指定要输出的数据的首地址,可以是任意类型数据;
size_t count:指定要输出的数据字节数;
返回值:
成功,返回成功输出的字节数;
失败,返回-1,更新errno;
注意,write函数指定写多少个字节,就会从内存中拿多少个字节,写入到文件中,即使越界
5.read
功能:从文件中读取数据;
原型:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
int fd:指定要从哪个文件中读取数据,填对应的文件描述符;
void *buf:指定要将读取到的数据存储到那块空间中,可以是任意类型数据;
size_t count:指定要读取的数据字节数;
返回值:
>0, 成功,返回成功读取的字节数;
=0, 文件读取完毕;
=-1, 失败,返回-1,更新errno;
代码展示
6.lseek
功能:修改文件偏移量;
原型:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:
int fd:文件描述符;
off_t offset: 距离whence参数指定的偏移量。往前偏移填负数, 往后偏移填正数
int whence:
SEEK_SET, 文件开头位置
SEEK_CUR, 文件当前位置
SEEK_END 文件结尾位置
返回值:
成功,修改偏移量后,文件当前位置距离文件开头的偏移量;
失败,返回-1,更新errno;
//计算文件大小
off_t size = lseek(fd_r, 0, SEEK_END);
printf("size=%ld\n", size);
若偏移量在文件开头,能否继续往前偏移 ---》 不行
若偏移量在文件结尾,能否继续往后偏移 ---》可以
目录相关的函数
1.opendir
功能:打开一个目录文件;
原型:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
参数:
char *name:指定要打开的目录的路径以及名字;
返回值:
成功,返回指针;
失败,返回NULL,更新errno;
2.closedir
功能:关闭目录;
原型:
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
返回值:
成功,返回0;
失败,返回-1,更新errno;
3.readdir
功能:读取目录;
原型:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
参数:
返回值:
成功,返回结构体指针:
失败,返回NULL; 更新errno;
目录读取完毕,返回NULL,不更新errno;
struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
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]; /* Null-terminated filename */
};
获取文件属性
- rw-rw-r-- 1 ubuntu ubuntu 372 七月 31 11:29 01_fileno.c
文件的类型 文件权限 文件的硬链接数 文件所属用户 文件所属组用户 大小
文件的类型 : bsp-lcd
文件权限: rw- rw- r-- 文件所属用户权限 组用户权限 其他用户权限
1.stat
功能:获取文件的属性;
原型:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
参数:
char *pathname:指定要获取属性的文件路径以及名字;
struct stat *statbuf:存储获取到的属性;
返回值:
成功,返回0;
失败,返回-1,更新errno;
vi -t stat 或者 man手册往下翻
struct stat {
ino_t st_ino; /* Inode number */ inode号
mode_t st_mode; /* File type and mode */ 文件类型和权限
nlink_t st_nlink; /* Number of hard links */ 硬链接数
uid_t st_uid; /* User ID of owner */ 用户的uid
gid_t st_gid; /* Group ID of owner */ 组用户的gid
off_t st_size; /* Total size, in bytes */ 文件大小
struct timespec st_atim; /* Time of last access */ 最后一次被访问的时间
struct timespec st_mtim; /* Time of last modification */ 最后一次被修改的时间
struct timespec st_ctim; /* Time of last status change */ 最后一次改变状态的时间
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
2.提取文件的权限
mode_t st_mode 本质上是一个unsigned int类型,里面存储了文件的类型和权限。
st_mode中其中低9bits存储了文件的权限:[0bit - 8bit]
mode: 0100664 ---> rw-rw-r--
664----> 110 110 100 ---> 0664
100 000 000 ---> 0400
------------
100 000 000 ===> 0400结果不等于0,需要打印'r'。否则打印'-'
664----> 110 110 100 ---> 0664
010 000 000 ---> 0200
------------
010 000 000 ===> 0200结果不等于0,需要打印'w'。否则打印'-'
664----> 110 110 100 ---> 0664
001 000 000 ---> 0100
------------
000 000 000 ===> 0000结果等于0,需要打印'-'。否则打印'x'
void get_filePermission(mode_t m) //mode_t m = buf.st_mode
{
char buf[] = "rwx";
for(int i=0; i<9; i++)
{
if( (m & (0400>>i)) == 0)
{
putchar('-');
continue;
}
//能运行到当前位置,则代表对应位置有权限
//需要判断是r w x中的哪一个
/*
switch(i%3)
{
case 0:
putchar('r');
break;
case 1:
putchar('w');
break;
case 2:
putchar('x');
break;
}
*/
printf("%c", buf[i%3]);
}
return;
}
3.提取文件的类型
mode_t st_mode 本质上是一个unsigned int类型,里面存储了文件的类型和权限。
方法一
man 2 stat --> st_mode --->see inode(7)
man 7 inode -->
S_ISREG(m) is it a regular file? -
S_ISDIR(m) directory? d
S_ISCHR(m) character device? c
S_ISBLK(m) block device? b
S_ISFIFO(m) FIFO (named pipe)? p
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.) l
S_ISSOCK(m) socket? (Not in POSIX.1-1996.) s
若是该类型文件,则返回真,否则返回假
void get_fileType(mode_t m)
{
if(S_ISREG(m))
putchar('-');
else if(S_ISDIR(m))
putchar('d');
else if(S_ISCHR(m))
putchar('c');
return ;
}
方法二
mode 0040775
S_IFMT 0170000 bit mask for the file type bit field
mode 0040775 ---> 000 100 000 111 111 101
S_IFMT 0170000 ---> 001 111 000 000 000 000 &
------------------------------
000 100 000 000 000 000 ---> 040000
与下列宏进行比较,与哪个相同,就是对应类型文件
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
mode: 0100664 ---> 001 000 000 110 110 100
S_IFMT 0170000 ---> 001 111 000 000 000 000 &
------------------------------
001 000 000 000 000 000 ---> 0100000
void get_fileType(mode_t m) //mode_t m = buf.st_mode
{
switch(m & S_IFMT)
{
case S_IFSOCK: putchar('s'); break;
case S_IFLNK: putchar('l'); break;
case S_IFREG: putchar('-'); break;
case S_IFDIR: putchar('d'); break;
}
return;
}
4.提取文件所属用户名
uid_t st_uid; /* User ID of owner */ 用户的uid
功能:通过uid号获取用户的信息;
原型:
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
参数:
uid_t uid:指定uid号;
返回值:
成功,返回结构体指针;
失败,返回NULL;更新errno;
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
struct passwd* pwd = getpwuid(buf.st_uid);
if(NULL == pwd)
{
ERR_MSG("getpwuid");
return -1;
}
printf("%s\n", pwd->pw_name);
4.提取文件所属组用户名
gid_t st_gid; /* Group ID of owner */ 组用户的gid
功能:通过gid号获取组用户的信息;
原型:
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
参数:
gid_t gid:指定gid号;
返回值:
成功,返回结构体指针;
失败,返回NULL;更新errno;
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
struct group* grp = getgrgid(buf.st_gid);
if(NULL == grp)
{
ERR_MSG("getgrgid");
return -1;
}
printf("%s\n", grp->gr_name);