虚拟地址空间:
linux没运行一个程序(进程)操作系统都会分配一个0~4G的地址空间(虚拟地址空间)
文件描述符:通过文件描述符可以找到磁盘文件
一个进程有一个文件描述符表:1024
前三个被占用,被标准输入,标准输出,标准错误占用
open函数的使用
函数原型:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
参数:
flags
必选项:O_RDONLY,O_WRONLY,O_RDWR
可选项:
创建文件:O_CREAT
创建文件时检测文件是否存在:O_EXCL
如果文件存在,返回-1
必须与O_CREAT一起使用
追加文件: O_APPEND
文件截断:O_TRUNC
设置非阻塞:O_NONBLOCK
mode:是一个八进制数
代码实例
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<unistd.h>
int main()
{
//打开一个文件 hello
int fd = open("hello", O_RDWR|O_CREAT, 0777);//第一个是文件名,第二个参数是指定的操作,第三个参数是给定的权限
if(fd == -1)
{
printf("打开失败\n");
}
close(fd);//关闭文件描述符
return 0;
}
read_write函数
read函数:包含在头文件 <unistd.h>
函数原型:ssize_t read(int fd, void *buf, size_t count);
参数:
fd:open返回值
buf:缓冲区
count:缓冲区能存储的最大字节数
返回值:
-1:表示读取失败
成功:
>0:表示读取的字节数
=0:表示读完了
b. write函数:包含在头文件 <unistd.h>
函数原型:ssize_t write(int fd, const void *buf, size_t count);
参数:
fd:open的返回值
buf:要写到文件的数据
count:buf的有效字节数
返回值:
-1:表示写入失败
>0:写入到文件的字节数
代码实例:
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
int main()
{
int fd = open("text.txt", O_RDONLY);
if(fd == -1)
{
printf("打开失败\n");
}
int fd2 = open("text2.txt", O_WRONLY|O_CREAT, 0777);
char arr[20] = {0};
int len = read(fd, arr, 20);
while(len > 0)
{
int ret = write(fd2, arr, strlen(arr));
len = read(fd, arr, sizeof(arr));
}
close(fd2);
close(fd);
return 0;
}
perror函数:包含的头文件 <errno.h>
函数原型:void perror(const char *s);
作用:输出错误信息
参数s:指定错误信息的标识
lseek 函数:包含在头文件 <sys/types.h> <unistd.h>
函数原型:off_t lseek(int fd, off_t offset, int whence);
参数 whence选项:
SEEK_SET
SEEK_CUR
SEEK_END
使用:
文件指针移动到头部
lseek(fd, 0, SEEK_SET);
获取文件指针当前的位置
int len = lseek(fd, 0, SEEk_CUR);
获取文件长度:
int lne = lseek(fd, 0, SEEK_END);
文件扩展
文件原大小100k 扩展为 1000k
lseek(fd, 1000, SEEK_END);
最后做一次写操作
write(fd, "a", 1);
要实现文件扩展必须执行上面两部
文件扩展代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<fcntl.h>
int main(int argc, const char* argv[])
{
int fd = open("english.txt", O_RDWR);
printf("fd = %d\n", fd);
if(fd == -1)
{
perror("open");
return -1;
}
//文件扩展
int len = lseek(fd, 1000, SEEK_END);//第二个参数表示文件指针移动的位数, 第三个参数表示从末尾开始移动
printf("len = %d\n", len);
write(fd, "a", 1);
close(fd);
return 0;
}
阻塞和非阻塞
取决于文件的属性:
普通文件:默认是非阻塞
终端设备:/dev/tty,默认阻塞
stat和lstat函数:包含的头文件 <sys/types.h> <sys/stat.h> <unistd.h>
函数原型: int stat(const char *pathname, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
两个函数的区别:
lstat:读取的链接文件本身的属性
stat:读取的是链接文件指向的文件的数学
参数pathname:文件路径
参数statbuf:是一个stat结构体对象
stat结构体:
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
blksize_t st_blksize; //块大小(文件系统的I/O缓冲区大小)
blkcnt_t st_blocks; //块数
struct timespec st_atim; //最后一次访问时间
struct timespec st_mtim; //最后一次修改时间
struct timespec st_ctim; //最后一次改变时间(指属性)
};
获取文件各种属性:
文件用16位进制数表示所有的权限:
0-2位:表示其他人的权限
3-5位:表示所属组织的权限
6-8位:表示文件所有者权限
12-15位:表示文件所有者权限
掩码 S_IFMT:0170000 是八进制数,过滤 st_mode 中出文本类型以外的信息
例子:(st_mode & S_IFMT) == S_IFREG
使用代码实例:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
int main()
{
struct stat st;
int ret = stat("english.txt", &st);
if(ret == -1)
{
perror("stat error");
exit(1);
}
//输出文件大小
printf("file size = %d\n", (int)st.st_size);
//文件类型判断--判断是否是普通文件
if((st.st_mode & S_IFMT) == S_IFREG)//S_IFMT 是一个掩码,获取到的文件与上该掩码可以得到一个对应类型的二进制数
{
printf("该文件是普通文件\n");
}
//所有者对文件的操作权限
if(st.st_mode & S_IRUSR)
{
printf(" r\n");
}
if(st.st_mode & S_IWUSR)
{
printf(" w\n");
}
if(st.st_mode & S_IXUSR)
{
printf(" X\n");
}
return 0;
}
access函数:包含在头文件 <unistd.h>
作用:检查文件属性
函数原型:int access(const char *pathname, int mode);
参数 pathname:文件的路径
参数 mode:检查的属性
可选项:R_OK,W_OK以及X_OK
代码实例
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("a.out fileman\n");
exit(1);
}
//检测当前文件是否有写权限
int ret = access(argv[1], W_OK);
if(ret == -1)
{
perror("access");
exit(1);
}
printf("you can write this file.\n");
return 0;
}
chmod和 chown函数
chmod函数的作用:修改文件权限
函数原型:int chmod(const char *pathname, mode_t mode); 包含在头文件 <sys/stat.h>
参数pathname:文件路径
参数mode:文件权限,是一个八进制数
chown函数的作用:修改文件所有者和所属组
函数原型:int chown(const char *pathname, uid_t owner, gid_t group); 包含在头文件 <unistd.h>
参数pathname:文件路径
参数owner:整形值,用户ID
参数group:整型值,组ID
opendir和readdir函数:包含在头文件 <dirent.h>
opendir函数的作用:打开一个目录
opendir函数原型:DIR *opendir(const char *name);
参数 name:目录名
返回值:指向目录的指针
readir函数的作用:读目录
readdir函数的原型:struct dirent *readdir(DIR *dirp);
参数dirp:opendir的返回值
返回值:目录项结构
dirent结构体
struct dirent {
ino_t d_ino; //此目录进入点的inode
off_t d_off; //目录文件开头至此目录进入点的位移
unsigned short d_reclen; //d_name 的长度,不包含NULL 字符
unsigned char d_type; //d_name所指的文件类型
char d_name[256]; // 文件名
};
文件类型:
DT_BLK-块设备
DT_CPR-字符设备
DT_DIR-目录
DT_LNK-软连接
DT_FIFO-爸道
DT_REG-普通文件
DT_SOCK-套接字
DT_UNKNOWN-未知
closedir函数:关闭目录
函数原型:int closedir(DIR *dirp);
程序实例
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<dirent.h>
//定义函数读指定目录中文件的个数
int getfile(const char* root)
{
int total = 0;
DIR* dir = NULL;
dir = opendir(root);
if(dir == NULL)
{
perror("opendir");
exit(0);
}
struct dirent* ptr;
while((ptr = readdir(dir)) != NULL)
{
//不处理 . 和 .. 目录
if(strcmp(".", ptr->d_name) == 0 || strcmp("..", ptr->d_name) == 0)
{
continue;
}
//判断是否是普通文件
if(ptr->d_type == DT_REG)
{
total++;
}
//判断是否是目录
if(ptr->d_type == DT_DIR)
{
//求出子目录
char path[1024] = {0};
sprintf(path, "%s/%s", root, ptr->d_name);//拼接子目录
total += getfile(path);
}
}
//关闭目录
closedir(dir);
return total;
}
int main(int argc, const char* argv[])
{
if(argc < 2)
{
printf("./a.out path\n");
exit(1);
}
int total = getfile(argv[1]);
printf("%s 目录下的普通文件个数:%d\n", argv[1], total);
return 0;
}
dup和dup2函数:包含的头文件 <unistd.h>
dup函数的作用:复制文件描述符
dup函数的函数原型:int dup(int oldfd);
参数oldfd:要复制的文件描述符
返回值:新的文件描述符
dup调用成功:会有两个文件描述符指向同一个文件
返回值:取最小的且没被占用的文件描述
dup2函数的作用:文件描述符重定向
dup2函数的原型:int dup2 (int oldfd, int newfd);
参数oldfd:如果指向 hello
参数newfd:如果指向 world
调用dup2函数会把newfd改为指向oldfd指向的文件,也就是newfd也会指向hello的文件->文件描述重定向
newfd没有被占用的情况下,newfd指向oldfd指向的文件