目录
一丶概念
二丶特点
三丶函数
1.打开文件 open
2.关闭文件 close
3.读取文件 read
4.写入文件 write
5.文件定位操作
标准IO和文件IO区别
四丶获取文件属性
1.stat函数
2.获取文件类型
五丶目录操作
一丶概念
二丶特点
1.没有缓冲机制,每次操作都会经过系统调用,效率比较低
2.围绕文件描述符进行操作,文件描述符是非负整数,0 1 2 .......,依次分配
3.默认打开三个文件描述符,0(标准输入),1(标准输出),2(标准错误)
4.操作除了目录d以外任意类型的文件bc-lsp
5.可移植性相对较差
答: 还是4,因为4在关闭以后就空闲下来,下次打开新文件默认分配4
问题:一个进程的文件描述符最大到几?最多能打开多少个文件描述符?最多能打开多少个文件?
答: 一个进程的文件描述符最大到1023 (0-1023), 最多能打开1024个文件描述符, 最多能打开1021(1024-3)个文件。
三丶函数
1.打开文件 open
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
功能:打开文件
参数:pathname:文件路径名
flags:打开文件的方式
O_RDONLY:只读
O_WRONLY:只写
O_RDWR:可读可写
O_CREAT:创建
O_TRUNC:清空
O_APPEND:追加
返回值:成功:文件描述符
失败:-1
当第二个参数中有O_CREAT选项时,需要给open函数传递第三个参数,指定创建文件的权限
int open(const char *pathname, int flags, mode_t mode);
最后权限 = mode &(~umask)
例如:指定权限为0666(8进制)
最终权限= 0666 & (~umask) = 0666 &(~0002) = 664
666 => 110 110 110
&775 111 111 101
664 110 110 100
标准IO | 文件IO |
r | O_RDONLY |
r+ | O_RDWR |
w | O_WRONLY|O_CREAT|O_TRUNC |
w+ | O_RDWR|O_TRUNC|O_CREAT |
a | O_WRONLY|O_CREAT|O_APPEND |
a+ | O_RDWR|O_CREAT|O_APPEND |
2.关闭文件 close
int close(int fd);
功能:关闭文件
参数:fd:文件描述符
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int fd;
//1.打开文件
//fd = open("a.c", O_RDONLY); //r
fd = open("a.c", O_WRONLY | O_CREAT | O_TRUNC, 0666); //w
if (fd < 0)
{
perror("open err ");
return -1;
}
printf("fd: %d\n", fd);
//2.关闭文件
close(fd);
return 0;
}
3.读取文件 read
ssize_t read(int fd, void *buf, size_t count);
功能:从一个已打开的可读文件中读取数据
参数: fd 文件描述符
buf 存放位置
count 期望的个数
返回值:成功:实际读到的个数(小于期望值说明实际没这么多)
返回0:表示读到文件结尾
返回-1:表示出错,并设置errno号
4.写入文件 write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:向指定文件描述符中,写入 count个字节的数据。
参数:fd 文件描述符
buf 要写的内容
count 期望写入字节数
返回值:成功:实际写入数据的个数
失败 : -1
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{
if (argc != 3)
{
printf("filename err");
return -1;
}
int m = open(argv[1], O_RDWR);
if (m < 0)
{
printf("argv[1] err");
return -1;
}
int n = open(argv[2], O_CREAT||O_TRUNC|O_WRONLY,0777);
if (n < 0)
{
printf("argv[2] err");
return -1;
}
int buf[64];
int i;
while((i=read(m,buf,64))>0)//记录正确读取的个数,当读不到字符时停止读取
{
write(n,buf,i);//将正确读取的个数写入到n中
}
close(m);
close(n);
return 0;
}
5.文件定位操作
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能:设定文件的偏移位置
参数:fd:文件描述符
offset偏移量
正数:向文件结尾位置移动
负数:向文件开始位置
whence 相对位置
SEEK_SET 开始位置
SEEK_CUR 当前位置
SEEK_END 结尾位置
返回值:成功:文件的当前位置
失败:-1
#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
int main(int argc, char const *argv[])
{
int n;
n=open("test.txt",O_RDWR);
if (n < 0)
{
printf("open err");
return -1;
}
lseek(n,10,0);
write(n,"a",1);
lseek(n,20,1);
write(n,"hello",5);
off_t len=lseek(n,0,2);
printf("%ld\n",len);
return 0;
}
标准IO和文件IO区别
标准IO | 文件IO | |
概念 | 在C库中定义的一组输入输出的函数 | 在posix中定义的一组输入输出的函数 |
特点 | 1. 有缓冲区,减少系统调用,提高效率 2. 围绕流操作,FILE* 3. 默认打开三个流:stdin\stdout\stderr 4. 只操作普通文件 | 1. 没有缓冲区,每次操作都引起系统调用 2. 围绕文件描述符操作 3. 默认打开三个文件描述符:0\1\2 4. 除目录外其他文件 |
函数 | 打开文件:fopen/freopen 关闭文件:fclose 读写文件:fgetc/fputc fgets/fputs fread/fwrite 文件定位:rewind/fseek/ftell | 打开文件:open 关闭文件:close 读写文件:read/write 文件定位:lseek |
四丶获取文件属性
1.stat函数
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
功能:获取文件属性
参数: path:文件路径名
buf:保存文件属性信息的结构体
返回值:成功:0
失败:-1
struct stat {
ino_t st_ino; /* inode号 ls -il */
mode_t st_mode; /* 文件类型和权限 */
nlink_t st_nlink; /* 硬链接数 */
uid_t st_uid; /* 用户ID */
gid_t st_gid; /* 组ID */
off_t st_size; /* 大小 */
time_t st_atime; /* 最后访问时间 */
time_t st_mtime; /* 最后修改时间 */
time_t st_ctime; /* 最后状态改变时间 */
};
文件权限和类型需要通过位操作获取:
st_mode 主要包含了 3 部分信息:
a. 15bit ~ 12bit 保存文件类型
b. 11bit ~ 9bit 保存执行文件时设置的信息(不用管)
c. 8bit ~ 0bit 保存文件访问权限
2.获取文件类型
S_IFMT是一个掩码,它的值是0170000(注意这里用的是八进制前缀为0,二进制0b001111000000000000), 可以用来把st_mode位与上掩码过滤提取出表示的文件类型的那四位(15bit~12bit位),也就是这四位原样获取其他位清零。
判断一个文件是不是普通文件,首先通过掩码S_IFMT把其他无关的部分置0,再与表示普通文件的数值比较,从而判断这是否是一个普通文件:
或者用switch
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
struct stat *st = (struct stat *)malloc(sizeof(struct stat));
if (stat("0.c", st) != 0)
{
printf("stat err\n");
return -1;
}
printf("idode:%ld\n", st->st_ino);
printf("nlink:%ld\n", st->st_nlink);
printf("size:%ld\n", st->st_size);
printf("mode:%#o\n", st->st_mode);
if (st->st_mode & __S_IFMT == __S_IFDIR)
printf("目录\n");
if (st->st_mode & __S_IFMT == __S_IFREG)
printf("普通文件\n");
for (int i = 8; i >= 0; i--)
{
if (st->st_mode & (1 << i))
{
switch (i % 3)
{
case 2:
printf("r");
break;
case 1:
printf("w");
break;
case 0:
printf("x");
break;
}
}
else
printf("-");
}
printf("\n");
return 0;
}
五丶目录操作
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:获得目录流
参数:要打开的目录
返回值:成功:目录流
失败:NULL
struct dirent *readdir(DIR *dirp);
功能:读目录
参数:要读的目录流
返回值:成功:读到的信息
失败或读到目录结尾:NULL
返回值为结构体,该结构体成员为描述该目录下的文件信息
struct dirent {
ino_t d_ino; /* 索引节点号*/
off_t d_off; /*在目录文件中的偏移*/
unsigned short d_reclen; /* 文件名长度*/
unsigned char d_type; /* 文件类型 */
char d_name[256]; /* 文件名 */
};
int closedir(DIR *dirp);
功能:关闭目录
参数:dirp:目录流