连续存储

线性结构:把所有的结点(数组元素)用一根线穿起来。

  1. 连续存储[数组]
  2. 离散存储[链表]
线性结构的两种常见应用之一:栈(函数调用,内存分配)
线性结构的两种常见应用之一:队列(和时间有关的操作)

1.数组
什么叫数组:元素类型相同,大小相等

ArrayList:
#include <stdio.h>
#include <malloc.h>//包含了malloc函数
#include <stdlib.h>//包含了exit函数

/*定义了一个数据类型,该数据类型的名字叫struct Arr
没有变量
*/
struct Arr
{
    int *pBase;//存储的是数组第一个元素的地址
    int len;//数组所能容纳的最大元素的个数
    int cnt;//当前数组有效元素的个数
    int increment;//自动增长因子(每次数组增长的长度)
};

void init_arr(struct Arr * pArr,int length);//分号不能省
bool append_arr(struct Arr * pArr,int val);//追加
bool insert_arr(struct Arr * pArr,int pos,int val);//pos的值从1开始
bool delete_arr(struct Arr * pArr,int pos,int *pVal);//pVal接受返回的值
int get();
bool is_empty(struct Arr * pArr);
bool is_full(struct Arr * pArr);
void sort_arr(struct Arr * pArr);
void show_arr(struct Arr * pArr);
void inverseion_arr(struct Arr * pArr);

int main(void)
{
    struct Arr arr;//已经分配内存
    int val

    init_arr(&arr,6);
    show_arr(&arr);
    bool append_arr(&arr,1);
    show_arr(&arr);
    delete_arr(&arr,1,&val);

    return 0;
}

void init_arr(struct Arr * pArr,int length)
{
    pArr->pBase = (int*)malloc(sizeof(int)*6);
    if(NULL == pArr->pBase)//内存分配失败
    {
     printf("动态内存分配失败!\n");
     exit(-1);//终止整个程序
    }
    else
    {
     pArr->len = length;
     pArr->cnt = 0;
    }
    return;
}
bool is_empty(struct Arr * pArr)
{
    if( 0== pArr->cnt)
       return true;
    else
       return false;
}
bool is_full(struct Arr * pArr)
{
    if(pArr->cnt == pArr->len)
        return true;
}
void show_arr(struct Arr * pArr)
{
    if(is_empty(&pArr))
    {
     printf("数组为空!\n");
    }
    else
    {
        for(int i = 0;i<pArr->cnt;++i)
           printf("%d",pArr->pBase[i]);
	   printf("\n");
    }
}
bool append_arr(struct Arr * pArr,int val)
{   
    //满时返回false
    if(is_full(pArr))
        return false;
    //不满时追加
    pArr->pBase[pArr->cnt] = val;
    (pArr->cnt)++;
    return true;
}
bool insert_arr(struct Arr * pArr,int pos,int val)
{
    int i;
    if(is_full(pArr))
        return false;
    if(pos<1 || pos>pArr->cnt+1)
        return false;
    for(i=pArr->cnt-1;i>=pos-1;i++)
    {
        pArr->pBase[i-1] = pArr->pBase[i];
    }
    pArr->pBase[pos-1] = val;
    return true;
    pArr->cnt++;
}

bool delete_arr(struct Arr * pArr,int pos,int *pVal)
{
    int i;
    if(is_empty(pArr))
        return false;
    if(pos < 1 || pos > pArr->cnt)
        return false;
    *pVal = pArr->pBase[pos-1];
    for(i=pos;i<pArr->cnt;++i)
    {
        pArr->pBase[i-1] = pArr->pBase[i];

    }
    pArr->cnt--;
    return ture;
}
void inverseion_arr(struct Arr * pArr)
{
    int i =0;
    int j = pArr->cnt-1;
    int t;

    while(i<j)
    {
        t = pArr->pBase[i];
	pArr->pBase[i] = pArr->pBase[j];
	pArr->pBase[j] = t;
	++i;
	--j;
    }
    return;
}
void sort_arr(struct Arr * pArr)
{
    int i,j;
    for(i=0;i<pArr->cnt;++i)
    {
        for(j=i+1;j<pArr->cnt;++j)
	{
	    if(pArr->pBase[i] > pArr->pBase[j])
	    {
	        t = pArr->pBase[i];
		pArr->pBase[i] = pArr->pBase[j];
		pArr->pBase[j] = t;
	    }
	}

    }
}



<think>我们正在讨论文件在磁盘中的存储方式,特别是是否连续存储的问题。根据用户提供的引用和之前的对话,我们可以总结如下:1.引用[4]提到文件系统存储的基本机制:文件数据被分成多个块(Block),每个块通常是4KB大小。文件系统通过inode来管理这些块,inode中存储了文件数据的块位置信息。2.引用[2]提到磁盘的物理结构和逻辑存储,以及文件系统如何管理文件和目录。其中,逻辑存储结构决定了文件的组织和访问方式。3.引用[1]和[5]则提供了关于磁盘分区和逻辑卷管理的背景信息。现在,针对用户的问题:“文件在磁盘中是否一定连续存储?”,我们需要从文件系统的存储机制来解释。###文件在磁盘中的存储方式在文件系统中,文件的数据并不是一定连续存储在磁盘上的。相反,文件的数据通常被分成多个数据块(Block),这些块在磁盘上可能是分散的(非连续的)。这种存储方式称为非连续存储。####为什么采用非连续存储?1.**磁盘空间管理灵活性**:文件系统需要动态分配和释放磁盘空间。如果要求连续存储,那么在文件增长或新文件写入时,可能找不到足够大的连续空间,导致存储失败或效率低下。非连续存储允许文件系统利用磁盘上的碎片空间。2.**文件大小可变**:文件可以动态增长或缩小,连续存储难以处理这种变化。3.**提高磁盘利用率**:非连续存储可以更好地利用磁盘空间,减少空间浪费。####文件系统如何管理非连续存储?文件系统通过索引结构来管理文件的数据块。在类Unix系统(如Linux)中,通常采用inode(索引节点)结构。每个文件对应一个inode,其中包含:-文件元数据(如大小、权限、时间戳等)-指向文件数据块的指针这些指针可以是:-**直接指针**:直接指向数据块的地址(通常有12个左右)。-**间接指针**:指向一个数据块,该数据块存储的是指向其他数据块的指针(一级间接)。-**双重间接指针**:指向一个指针块,该指针块再指向其他指针块(二级间接)。-**三重间接指针**(如果需要):三级间接。这种多级索引结构允许文件系统将文件的数据块分散在磁盘的任何位置,同时通过索引快速访问。####连续存储的情况虽然非连续存储是常态,但在某些情况下,文件系统也会尽量分配连续的空间:1.**预分配策略**:一些文件系统在创建文件时,会尝试预分配连续的磁盘空间,以减少碎片。2.**碎片整理**:当磁盘碎片严重时,文件系统或用户可以通过碎片整理工具将文件的数据块整理成连续存储,以提高访问效率。###总结-**文件在磁盘中不一定连续存储**,通常是非连续的。-文件系统通过索引结构(如inode)来管理非连续的数据块,实现文件的存储和访问。-连续存储在某些情况下存在(如预分配或碎片整理后),但非连续存储是常态。###补充:磁盘碎片由于文件采用非连续存储,随着文件的创建、删除和修改,磁盘上会产生碎片(空闲空间不连续)。这可能导致:-文件访问效率降低(磁头需要跳转多个位置)-磁盘空间利用率降低因此,一些文件系统会采用技术来减少碎片,如:-块分配策略(如ext4的延迟分配)-定期碎片整理###引用说明上述解释参考了引用[2]和[4]中关于文件系统存储机制的描述[^2][^4]。###相关问题1.文件系统如何减少磁盘碎片?2.inode的结构是怎样的?它是如何指向文件数据块的?3.不同的文件系统(如ext4、NTFS、FAT32)在文件存储方式上有何区别?</think>### 文件在磁盘中的存储方式详解:连续性与非连续存储机制 文件在磁盘中**不一定连续存储**,文件系统的核心设计目标之一就是高效管理**非连续存储空间**。以下是详细机制分析: --- ### 一、文件存储的基本单元 文件系统将磁盘空间划分为固定大小的**块(Block)**,典型大小为 4KB(可通过 `tune2fs -l /dev/sda1` 查看)。文件被拆分为多个块存储,这些块在物理磁盘上**可能连续也可能分散**。 #### 存储单元关系: ```mermaid graph LR A[文件] --> B[逻辑块序列] B --> C[物理块地址] C --> D[磁盘扇区] ``` --- ### 二、文件连续存储的局限性 1. **外部碎片问题** 当多次创建/删除文件后,磁盘会出现大量不连续的小空闲区。例如: ``` 已用空间: [文件A][空闲][文件B][空闲][文件C] 新文件需跨越多个空闲区 → 无法连续存储 ``` 2. **文件动态增长** 文件写入时可能扩大,原连续空间无法容纳(需整体迁移) --- ### 三、非连续存储的实现机制 #### 1. **索引节点(inode)结构** 每个文件对应一个 inode,其中包含: - 直接指针(通常 12 个)→ 指向直接数据块 - 间接指针 → 指向**块地址表**(存储更多块地址) - 双重间接指针 → 二级地址表 - 三重间接指针(大型文件) ```c struct ext4_inode { __le32 i_block[15]; // 块指针数组 // 0-11: 直接块, 12: 一级间接, 13: 二级间接, 14: 三级间接 }; ``` #### 2. **块分配策略** | 策略 | 连续性保证 | 典型文件系统 | |--------------|-----------|------------| | 块位图分配 | ❌ 随机分配 | FAT32 | | Extent分配 | ✅ 局部连续 | ext4/Btrfs | | 延迟分配 | ⚠️ 可能连续 | XFS/ext4 | **Extent 示例**(ext4 特性): ```bash # 查看文件物理块分布 filefrag -v example.txt ``` 输出: ``` Filesystem type is: ext4 File size is 1048576 (256 blocks) ext: logical_offset: 0-255 physical_offset: 20480-20735 ``` → 该文件连续存储在物理块 20480-20735 --- ### 四、连续存储的特殊场景 1. **预分配技术** 通过系统调用强制预留连续空间: ```c posix_fallocate(fd, 0, file_size); // 提前分配连续块 ``` 2. **碎片整理工具** ```bash e4defrag /path/to/file # ext4文件系统的碎片整理 ``` 3. **日志结构文件系统** 如 ZFS/Btrfs 在写入时倾向连续存储新数据 --- ### 五、性能影响对比 | 存储方式 | 读取性能 | 写入性能 | 空间利用率 | |-----------|---------|---------|----------| | 连续存储 | ★★★★★ | ★★☆☆☆ | ★☆☆☆☆ | | 非连续存储 | ★★★☆☆ | ★★★★☆ | ★★★★★ | > **实验验证**: > 创建碎片化文件并测试性能: > ```bash > # 生成碎片文件 > dd if=/dev/urandom of=file1 bs=1M count=100 > rm file1 > > # 测试连续写入 vs 碎片写入 > sudo hdparm -tT /dev/sda1 # 连续读取性能 > sudo filefrag -s /home/* # 查看碎片率 > ``` --- ### 六、关键设计原理 1. **地址映射层** 文件系统通过元数据(如 ext4 的 extent tree)建立逻辑块→物理块的映射: ``` 逻辑块 [0][1][2] → 物理块 [203][951][62] ``` 2. **磁盘调度优化** 即使物理块分散,通过电梯算法(elevator)合并相邻 I/O 请求: ```mermaid graph LR A[块访问请求 1023] --> B[IO调度器] C[块访问请求 1024] --> B D[块访问请求 1025] --> B B --> E[合并为连续请求 1023-1025] ``` 3. **SSD 的影响** SSD 无机械寻道时间,非连续存储的性能影响显著降低(但仍需考虑块擦除问题) --- ### 结论 1. 现代文件系统(ext4/XFS/Btrfs)**默认采用非连续存储** 2. 通过 extent 等机制**保证局部连续性**以优化性能 3. 连续存储仅用于特殊场景(如数据库预分配)[^2][^4] > 最佳实践:关键性能场景使用 `posix_fallocate()` 预分配空间,日常文件依赖文件系统的 extent 分配策略[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值