在windows中是文件的东西,在linux中也是文件;其次一些在windows中不是文件的东西,比如进程、磁盘、显示器、键盘这样硬件设备也被抽象成了文件,你可以使用访问文件的方法访问它们获得信息;甚至管道,也是文件;将来我们要学习网络编程中的socket
(套接字)这样的东西,使用的接口跟文件接口也是一致的。
这样做最明显的好处是,开发者仅需要使用一套API和开发工具,即可调取Linux系统中绝大部分的资源。举个简单的例子,Linux中几乎所有读(读文件,读系统状态,读PIPE)的操作都可以用read
函数来进行;几乎所有更改(更改文件,更改系统参数,写PIPE)的操作都可以用write
函数来进行。
缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
fsync
,强制刷新。
fclose
关闭文件的时候也会自动刷新。
printf
等函数,首先写入到用户级缓冲区中,可以通过fflush
刷新到内核级缓冲区。用户级缓冲区的作用是减少系统调用次数,内核级缓冲区的作用是减少IO次数。
标准I/O提供了3种类型的缓冲区。
1024
。stderr
通常是不带缓冲区的,这使得出错信息能够尽快地显示出来。除了上述列举的默认刷新方式,下列特殊情况也会引发缓冲区的刷新:
flush
语句;通过下面这个例子来理解一下缓冲区的刷新:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
//c库函数
printf("hell printf\n");
fprintf(stdout, "hello fprintf\n");
const char *str = "hello fwrite\n";
fwrite(str, 1, strlen(str), stdout);
//系统调用
const char *w = "hello write\n";
write(1, w, strlen(w));
return 0;
}
当我们往显示器上写入时是行刷新,打印顺序和我们代码一致,如果将往显示器上写入重定向到往文件中写入,就不是行刷新了,而是缓冲区满了才刷新,所以最后先刷新了系统调用write
,最后进程结束的时候再自动刷新的用户级缓冲区。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
//c库函数
printf("hell printf\n");
fprintf(stdout, "hello fprintf\n");
const char *str = "hello fwrite\n";
fwrite(str, 1, strlen(str), stdout);
//系统调用
const char *w = "hello write\n";
write(1, w, strlen(w));
//子进程
fork();
return 0;
}
如果我们在最后创建一个子进程,对于往显示器上写入时的行刷新不影响,不过将往显示器上写入重定向到往文件中写入时就和上面不一样了,因为C库函数先将字符串写入到用户级缓冲区中,最后父子进程各自把它们的缓冲区刷新了一遍,所以就有了两份数据,而系统调用write
写入到用户级缓冲区后自己就将数据拷贝到内核级缓冲区了,不等到进程结束再刷新。
我们自己封装一个简单的stdio.h,来深刻理解一下数据写入的过程:
#pragma once
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#define SIZE 1024
#define FLUSH_NONE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2
struct IO_FILE
{
int flag; // 刷新方式
int fileno; //文件描述符
char outbuffer[SIZE];
int size;
int capacity;
};
typedef struct IO_FILE mFILE;
mFILE *mfopen(const char *filename, const char *mode);
int mfwrite(const void *ptr, int num, mFILE *stream);
void mfflush(mFILE *stream);
void mfclose(mFILE *stream);
#include "mystdio.h"
mFILE *mfopen(const char *filename, const char *mode)
{
int fd = -1;
if (strcmp(mode, "r") == 0)
{
fd = open(filename, O_RDONLY);
}
else if (strcmp(mode, "w") == 0)
{
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
}
else if (strcmp(mode, "a") == 0)
{
fd = open(filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
}
if (fd < 0)
{
return NULL;
}
mFILE *mf = (mFILE*)malloc(sizeof(mFILE));
if (mf == NULL)
{
close(fd);
return NULL;
}
mf->flag = FLUSH_LINE;
mf->fileno = fd;
mf->size = 0;
mf->capacity = SIZE;
return mf;
}
void mfflush(mFILE *stream)
{
if (stream->size > 0)
{
//刷新的本质
write(stream->fileno, stream->outbuffer, stream->size);
stream->size = 0;
}
}
int mfwrite(const void *ptr, int num, mFILE *stream)
{
//1、库函数写方法:将数据拷贝到缓冲区
memcpy(stream->outbuffer+stream->size, ptr, num);
stream->size += num;
//2、检测是否刷新
if (stream->flag == FLUSH_LINE && stream->size > 0 && stream->outbuffer[stream->size - 1] == '\n')
{
mfflush(stream);
}
return num;
}
void mfclose(mFILE *stream)
{
if (stream->size > 0)
{
mfflush(stream);
}
close(stream->fileno);
}
文件有被打开的文件和未打开的文件,前面我们介绍的都是被打开的文件,其实对于文件来说未打开的文件是占多数的,未打开的文件在磁盘上。 文件存在就要被访问,访问文件的前提是要打开文件,打开文件的前提是先要找到这个文件,那么对于未打开的文件我们如何找到它,就是文件管理系统需要做的工作。不管是内存中已打开的文件还是磁盘中未打开的文件,都要被文件系统管理起来。整个过程可以类比快递的管理系统。
我们需要讨论下面两个问题:
扇区是磁盘存储数据的基本单位,通常是512KB,所以磁盘也叫块设备。磁盘就是一个元素为扇区的一维数组,数组的下标就是每一个扇区的LBA地址,OS使用磁盘,就可以用一个数字访问磁盘扇区。
inode
,就像进程都有自己的PCB一样,inode
是文件属性数据的集合,是一个结构体,特殊的是文件名属性不在inode
中保存。Linux中,文件内容和文件属性是分开存储的。
inode
编号找的。删除一个文件,只需要把inode Bitmap
和Block Bitmap
中对应的比特位由1置0即可,所以删除一个文件后也是可以恢复的。
Super Block
,一个分区内的多个组中一般只有几个组中存在,且都是一样的,这样做的目的为了备份,防止一整个分区都挂掉。
inode
个数,block
个数都是固定的。inode
以分区为单位,一个分区一套inode
。inode
分配的时候,只需要确定每个组的起始inode
;block
也是统一编号的,和inode
类似。
inode
和block
是怎么映射的?
目录和普通文件类似,也有
inode
和datablock
,其内容是文件名和inode的映射关系。文件的三个时间:
Access
:文件最后访问时间Modify
:文件内容最后修改时间Change
:文件属性最后修改时间ln -s file.txt file-soft.link
:给对应的文件建立软链接。
1、如何理解软硬链接?
inode
,软链接内容保存的是目标文件的路径,就像Windows中的快捷方式。inode
,硬链接本质上就是一组文件名和已经存在的文件的映射关系。2、为什么要有软硬链接?
.
和..
就是硬链接。
unlink
:删除软链接。
本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~