linux下读写emmc,nand,硬盘下的⽂件(⼀)
⼆、Linux硬盘分区
同Windows⼀样,Linux中同样⽀持MBR格式的硬盘分区。硬盘在Windows中作为⼀个设备接⼝,Windows通过磁盘驱动器与其进⾏交互,在Linux中同样如此。不过由于Linux中⼀切接⽂件,所以这个设备接⼝是以⽂件的形式存在的。
⽆论是实体设备⽐如硬盘还是虚拟设备如云打印机,其设备接⼝⽂件都存在与/dev⽬录下,实体设备接⼝⽂件的通常名字为sd[a-z],虚拟设备接⼝⽂件的通常名字为vd[a-z]。
以实体设备硬盘为例:
形如sda1、sda2、sda3…sdan的⽂件,就是硬盘sda的分区了,类似于Windows系统中的D、E盘的概念。
可以通过下⾯命令查看Linux中的硬盘设备和硬盘分区情况:
1、fdisk -l
从显⽰信息可以看出当前Linux操作系统只有⼀块总容量32.2GB的硬盘,⼀共包含62914560个扇区,每个扇区为512B,且该硬盘有三个主分区sda1、sda2和sda3。
对⽐⼀下Windows系统下的分区,除了有设备驱动⽂件之外,每个分区还关联了⼀个叫做盘符的东西,如下⾯的D、E、F
当在Windows中访问C://开头的资源时,操作系统有根据盘符就能够知道⽬标资源实际位于哪个分区。
同样的Linux中也有类似于盘符的东西,通常被叫做挂载点。使⽤下⾯命令可以看到Linux中的所有挂载点:
2、df -lh
就像结果所显⽰的那样,Linux是直接将路径和分区进⾏关联的,⽐如/boot⽬录下的所有数据都存放在硬盘sda的1号分区中。
Linux中可以通过下⾯命令查看硬盘分区的格式:
3、df -T
红框圈出来的Type列就是分区对应的格式,如硬盘sda的1、3号分区的格式都是xfs,Linux中常见的格式有xfs、ext2、ext3、ext4等。⾄于Linux的分区实战,直接看下⾯实战就好
linux硬盘分区blog.csdn
如果将Linux硬盘分区的步骤对⽐到Windows硬盘分区如下:
新加卷⼤⼩ -> 分配扇区数量
选择分区格式 -> 格式化分区
⽣成盘符 -> 将分区挂载到某个⽬录
三、常见Linux硬盘分区格式——ext2硬盘布局
Linux中常见的硬盘分区格式有xfs、ext2、ext3、ext4等。如果将硬盘本⾝被抽象为⼀个数据仓库,则硬盘分区可以看做仓库中的⼀个个库房,⽽有的库房⽤来存储⼤件物品,数量较少只需要顺序摆放,⽽有的库房⽤来存储⼩件物品,数量较多,需要使⽤货架并且要更细致的编号。硬盘的分区的格式,就可以⽐作库房是如何记录和摆放货物的⽅案。
以ext2格式为例,了解⼀下硬盘分区格式的基本概念:
ext2分区格式结构图
block
上⾯已经介绍了硬盘的物理存储单元为扇区,⽽分区的存储单元是由1个或者多个扇区组成的逻辑存储单元,通常被称为block(块)。block的⼤⼩可以在分区格式化的时候由操作者指定,通常为1024B或者4096B,转换成扇区通常就是2个扇区或者8个扇区⼤⼩。虽然同是ext2格式的不同分区,block的⼤⼩可能不同,但是同⼀个分区内的所有block的⼤⼩⼀定是相同的。
boot block
boot block(引导块)是位于分区最开始的⼀个block,可以⽤来存储类似于硬盘唯⼀的MBR表中boot loader,即通常被⽤于在同⼀个计算机中安装多个操作系统。
block group
block group(块组)是ext2分区格式中⽤于组织和管理block的逻辑划分。每个block group由super block(超级块)、GDT(group descriptor table 组描述符表)、block bitmap(块位图)、inode bitmap(索引节点位图)、inode table(索引节点表)、data blocks(数据块区)组成。之所以划分block group,可以理解为库房太⼤,将库房划分成了⼏个类似的区域分别管理。
super block
super block(超级块)是位于每个block group的最开始的⼀个block,其⽤于描述当前block group所
在分区的元数据信息,⽐如每个block的⼤⼩、block的总数量、空闲可⽤的block数量等。
super block部分内容
GDT(group descriptor table)
GDT位于super block之后,通常占据连续的n(>= 1)个block。GDT中主要保存了当前block group的元数据,主要当前block group中其他部分的指针以及block数量相关信息:
GDT部分内容
block bitmap
block bitmap(块位图),其本⾝占据⼀个block的⼤⼩,记录当前block group的data blocks区域中哪些块是已经被使⽤的,哪些块是未被使⽤的。block bitmap将data blocks区域中所有块以线性地址组织起来啊,每⼀个块⽤⼀位来记录信息,⽐如块位图有1024B,则⼀共有1024 * 8 = 8192bit,则其最多能记录8192个block的使⽤情况。假如当前block bitmap状态为10…(8190个0),则说明data blocks区域中,只有第⼀个block被使⽤了,其他的都是空闲状态。
inode bitmap
inode bitmap(索引节点位图),本⾝占据⼀个block⼤⼩,功能类似于block bitmap。inode bitmap⽤
于记录inode table区域中哪些inode是已经被使⽤的,记录⽅法和block bitmap相同。
inode Table
inode Table(索引节点表)中包含了需要indoe,每个inode记录了⽂件的元数据,⽐如⽂件类型,权限,⽂件⼤⼩等(没有⽂件名),即通过
ls -l
命令可以查看的内容都是记录在inode上的。系统中的每⼀个⽂件都可以到⼀个inode与与之对应,⼀个inode本⾝⼤⼩通常是128B或者256B。inode中还存储了与其相关的block的指针,以便于通过inode可以快速取出当前inode对应的⽂件的所有存储在block中的数据。
data blocks
data blocks(数据库区域)就是⼀组逻辑上连续的block的数组,主要⽤来存储⽂件的数据部分。在进⾏⽂件存储时,⼀个block只能被⼀个⽂件持有,即只能被⼀个inode所关联。即使block默认为1KB,但是⽂件只有1B⼤⼩,该⽂件依然会独占当前block空间,另外999B会浪费掉。
拓展
在简单了解了ext2格式的硬盘布局之后,我们⾄少可以知道,在硬盘分区设置inode数量时,要结合实际的场景来进⾏设定。假如当前分区更多的⽤来存储⼩⽂件,则最好将block设置的⼩⼀点,inode的数量设置的多⼀点,以免发⽣inode数量不⾜或者⼤量浪费硬盘空间的情况。假如当前分区更多的⽤来存储⼤⽂件,则可以将block设置的⼤⼀些,inode的数量此时可以相应的少⼀些。
④挂载磁盘:mount /dev/dx_ramdisk /dx_tmp1
三、在linux环境下常⽤⽂件接⼝函数:open、close、write、read、lseek。
1、⽂件操作的基本步骤分为:
a、在linux系统中要操作⼀个⽂件,⼀般是先open打开⼀个⽂件,得到⼀个⽂件扫描描述符,然后对⽂件进⾏读写操作(或其他操作),最后关闭⽂件即可。
b、对⽂件进⾏操作时,⼀定要先打开⽂件,然后再进⾏对⽂件操作(打开⽂件不成功的话,就操作不了),最后操作⽂件完毕后,⼀定要关闭⽂件,否则可能会造成⽂件损坏
c、⽂件平时是存放在块设备中的⽂件系统中的,我们把这个⽂件叫做静态⽂件,当我们去打开⼀个⽂件时,linux内核做的操作包括:内核在进程中建⽴了⼀个打开⽂件的数据结构,
记录下我们打开的这个⽂件,内核在内存中申请⼀段内存,并且将静态⽂件的内容从块设备中读取到内存中特定地址管理存放(叫动态⽂件)
d、打开⽂件后,以后对这个⽂件的读写操作,都是针对内存中这⼀份动态⽂件的,⽽不是针对静态⽂件的。
当我们对动态⽂件进⾏读写后,此时内存中的动态⽂件和块设备中的静态⽂件就不同步了,
当我们close 关闭动态⽂件时,close内部内核将内存中的动态⽂件的内容去更新(同步)块设备中的静态⽂件。
2、为什么是这样操作?
以块设备本⾝有读写限制(回忆Nandflash、SD、等块设备的读写特征),本⾝对块设备进⾏操作⾮常不灵活。⽽内存可以按字节为单位来操作。⽽且进⾏随机操作。
3、⽂件描述符是什么?
a、⽂件描述符:它其实实质是⼀个数字,这个数字在⼀个进程中表⽰⼀个特定的含义,当我们open打开⼀个⽂件时,操作系统在内存中构建了⼀些数据结构来表⽰这个动态⽂件,然后返回给应⽤程序
⼀个数字作为⽂件描述符,这个数字就和我们内存中维护这个动态⽂件的这些数据结构挂钩绑定上了。以后我们应⽤程序如果要操作这⼀个动态⽂件,只需要⽤这个⽂件描述符进⾏区分。简单来说,它是来区分多个⽂件的(在打开多个⽂件的时候)。
b、⽂件描述的作⽤域就是当前的进程,出了这个当前进程,这个⽂件描述符就没有意义了。
4、代码实现:
1、打开⽂件:
1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <unistd.h>
6int main(int argc,char*argv[])
7{
8//第⼀步:打开⽂件
9int fd=-1;//fd是⽂件描述符(在linux中的⽂件描述符fd
linux内核文件放在哪10的合法范围是0或者是⼀个正数,不可能是负数)
11 fd=open("/dev/",O_RDWR);//O_RDWR表⽰⽂件可读可写,这个可以
12⽤man ⼿册查看open函数的使⽤⽅法⾥⾯有它的说明
13if(-1==fd)或者(fd<0)
14{
15printf("⽂件打开错误\n");
16}
17else
18{
19printf("⽂件打开成功\n");
20}
21//读写⽂件
22//关闭⽂件
23close(fd);//关闭刚才打开的⽂件
24return0;
25}
2、读⽂件操作:
1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <unistd.h>
6int main(int argc,char*argv[])
7{
8int fd =-1;
9int ret=-1;
10char buf[100]={0};
11 fd=open("/dev/",O_RDWR);
12if(-1==fd)
13{
14printf("the open the file is failure \n");
15}
16else
17{
18printf("the open the file is successful,fd=%d.\n",fd);
19}
20 ret=read(fd,buf,20);//20表⽰读取的字节
21
22if(ret<-1)
23{
24printf("read失败\n");
25}
26else
27{
28printf("成功读取了%d字节\n",ret);
29printf("⽂件内容是:[%s]\n",buf);
30}
31close(fd);
32return0;
四、缓存
缓存是⽤来减少⾼速设备访问低速设备所需平均时间的组件,⽂件读写涉及到计算机内存和磁盘,内存操作速度远远⼤于磁盘,如果每次调⽤read,write都去直接操作磁盘,⼀⽅⾯速度会被限制,⼀⽅⾯也会降低磁盘使⽤寿命,因此不管是对磁盘的读操作还是写操作,操作系统都会将数据缓存起来。
Page Cache
页缓存(Page Cache)是位于内存和⽂件之间的缓冲区,它实际上也是⼀块内存区域,所有的⽂件IO(包括⽹络⽂件)都是直接和页缓存交互,操作系统通过⼀系列的数据结构,⽐如inode, address_space, struct page,实现将⼀个⽂件映射到页的级别,这些具体数据结构及之间的关系我们暂且不讨论,只需知道页缓存的存在以及它在⽂件IO中扮演着重要⾓⾊,很⼤⼀部分程度上,⽂件读写的优化就是对页缓存使⽤的优化
Dirty Page
页缓存对应⽂件中的⼀块区域,如果页缓存和对应的⽂件区域内容不⼀致,则该页缓存叫做脏页(Dirty Page)。对页缓存进⾏修改或者新建页缓存,只要没有刷磁盘,都会产⽣脏页
查看页缓存⼤⼩
linux上有两种⽅式查看页缓存⼤⼩,⼀种是free命令
$ free
total used free shared buffers cached
Mem: 20470840 1973416 18497424 164 270208 1202864
-/+ buffers/cache: 500344 19970496
Swap: 0 0 0
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论