探索文件空洞

1.什么是文件空洞,以及空洞的产生方法

文件空洞是什么?他其实就是操作系统中的文件系统对文件的一种逻辑描述形式。以下是产生文件空洞的方式。

1.通过文件偏移量生成:在UNIX/Linux文件操作中,当我们使用lseek函数设置文件偏移量的时候,当文件偏移量大于文件本身长度的时候。

2.多线程下载或文件预分配:例如,迅雷在下载文件时,如果文件尚未完全下载,但已经占据了全部文件大小的空间,这时就形成了文件空洞。这样做的好处是,在多线程下载时,不同的线程可以写入文件的不同部分,而不会互相干扰,从而提高了下载效率。同样,文件预分配也会生成文件空洞,即预先分配足够的磁盘空间来存储文件,即使文件的实际内容还未完全写入。

2.手动创建一个空洞文件

接下来我们来复现一下,第一种操作产生的一个文件空洞。下面是在linux下的代码操作。

    #include<fcntl.h>
#include<iostream>
#include<unistd.h>
using namespace std;

int main()
{

   char buf_1[]="1234567890";

  int fd_1;
  int fd_2;
  //##############################创建一个有空洞文件#################################

  if((fd_1=creat("file_hole",666))<0)
  {
          std::cout<<"creat file_hole erron";
  return 0;
  }
  if(write(fd_1,buf_1,10)!=10)
  {
          std::cout<<"write file_hole erron";
    return 0;
  }
  //文件偏移 20000个字节
  if(lseek(fd_1,20000,SEEK_SET)==-1)
  {
          std:: cout<<"lseek file_hole erron";
   return 0;
  }


 if(write(fd_1,buf_1,10)!=10)
  {
          std::cout<<"write file_hole erron";
    return 0;
  }


  //*****************************************************************************
  //################################创建没有空洞的文件##############################
   if((fd_2=creat("file_Nohole",666))<0)
  {
          std::cout<<"creat file_Nohole erron";
  return 0;
  }
   if(write(fd_2,buf_1,10)!=10)
  {
          std::cout<<"write file_Nohole erron";
    return 0;
  }
  //写20000个字节,循环20000/10 每次写10字节。 我们忽略单词IO操作所消耗的时间效率
  for(int i=0;i<20000/10;i++)
  {
    if(write(fd_2,buf_1,10)!=10)
    {
      std::cout<<"for wirte filt_Nohole erron";
      return 0;
    }

  }
  //****************************************************************************
return 0;
}

上述代码中,我们创建了两个文件,一个是“file_Nohole”一个是“file_hole”。这两个文件,一个用字符填满,一个中间有一个大概20000字节左右的空洞。我们在linux下面使用g++编译一下这段代码。

在这里插入图片描述

然后运行这个可执行程序后,我们可以看到两个文件已经生成了。接下来我们看一下,这两个文件的详细内容。
在这里插入图片描述

我们可以看到,这两个文件的长度是相同的都是20010.但奇怪的是,他们占用的磁盘块并不相同。有空洞的文件"file_hole",占用的磁盘块是8,而没有空洞的文件“file_Nohole”占用的磁盘块是20.这是为啥呢? 其实原因是,大多操作系统在处理空洞文件的时,并不要求占用存储空间。当我们打开文件,读取的时候,文件的空洞部分读为0.

3.空洞的底层原理

​ 这就又引出了一个新的问题,既然文件的空洞部分并不占用存储空间,那操作系统对于文件的空洞部分是如何记录的呢,当我们读到空洞的时候,它又是如何知道我们读的这块区域是个空洞呢?其实,这些文件的空洞信息,是记录在文件系统的元数据中的。 文件空洞的记录和维护实际上是在操作系统和文件系统的协同作用下完成的。在UNIX或类UNIX系统(如Linux)中,文件空洞的处理方式尤为典型。首先,当文件被创建或修改时,文件系统会跟踪文件的当前长度和已写入的数据。如果文件被扩展(即,文件的位移量大于其当前长度),文件系统并不会立即为扩展的部分分配物理存储空间。相反,它会在文件的元数据中记录这一扩展,但实际的磁盘空间不会被占用,这样就形成了一个空洞。其次,当读取文件时,操作系统会检查文件的元数据,以确定哪些部分是实际的数据,哪些部分是空洞。对于空洞部分,操作系统会返回特定的值(例如0),因为这些部分没有实际的内容。同样地,当写入数据时,如果写入操作导致文件被扩展并创建了新的空洞,文件系统会更新元数据以反映这一变化。此外,不同的文件系统可能采用不同的策略来处理空洞。例如,某些文件系统可能采用特定的数据结构来跟踪空洞的位置和大小,以便更有效地管理磁盘空间。而另一些文件系统可能使用更简洁的方法来标记空洞,只在需要时(如写入新数据时)才进行更详细的处理。最后,需要注意的是,虽然空洞在逻辑上不占用存储空间,但它们仍然会影响文件的大小和某些操作的性能。因此,在设计文件系统和应用程序时,需要仔细考虑如何处理文件空洞,以优化存储空间的利用和性能。也就是说,文件系统会记录文件的一些信息,包括空洞部分和有效数据区域。

4.文件空洞的作用

我名搞明白了文件的空洞产生,和文件系统对空洞的维护,那么空洞有什么实际作用吗?有!主要有以下几个方面。

  1. 提高压缩效率:许多压缩程序使用空洞机制来标记文件中的零字节,从而显著减少文件大小并提高压缩效率。这是因为压缩算法通常会产生大量的零字节,而空洞机制可以有效地将这些零字节标记为“空洞”,避免不必要的存储占用。
  2. 优化数据库性能:数据库经常需要处理大量的数据,空洞机制在这里可以发挥重要作用。它可以使数据库更快地读取和写入数据,降低磁盘使用率,并提高性能。此外,当某个数据项被删除时,空洞机制可以释放该数据项占用的空间,避免碎片化,从而保持数据库的高效运行。
  3. 处理大型文件:对于超大的文件,如视频和音频文件,空洞机制可以大幅度提高文件的效率。通过避免大型文件的碎片化,空洞技术可以确保文件在读取和写入时保持高效和稳定。
  4. 共享内存:当两个文件需要共享内存时,空洞文件发挥了关键作用。由于不知道需要共享内存的大小,因此需要在文件创建后设置文件的大小。这时,可以使用空洞文件机制来设置文件大小,通过lseek和write操作来创建一个指定大小的空洞文件。
  5. 多线程下载:以迅雷下载文件为例,当文件还未完全下载时,就已经占据了全部文件大小的空间。这是通过空洞文件实现的。没有空洞文件,多线程下载时文件只能从一个地方写入,无法发挥多线程的优势。而有了空洞文件,可以从不同的地址写入,从而实现多线程下载的并行化。
    全下载时,就已经占据了全部文件大小的空间。这是通过空洞文件实现的。没有空洞文件,多线程下载时文件只能从一个地方写入,无法发挥多线程的优势。而有了空洞文件,可以从不同的地址写入,从而实现多线程下载的并行化。
### 空洞卷积的技术定义 空洞卷积(Dilated Convolution),也称为扩张卷积,是一种扩展传统卷积感受野而不增加参数量的方法。与常规卷积不同的是,空洞卷积在卷积核中引入了一个超参数——**空洞率(dilation rate)**,该参数决定了卷积核采样的间隔大小。当空洞率为1时,空洞卷积退化为普通的卷积操作;而随着空洞率增大,卷积核的感受野也随之扩大[^1]。 具体来说,假设有一个 \( K \times K \) 的卷积核和输入特征图,则对于某个特定的空洞率 \( r \),实际参与运算的位置由下式决定: \[ (x, y)_{actual} = (x + i \cdot r, y + j \cdot r), \quad i,j \in [-K/2, K/2] \] 这种设计使得模型能够在保持较低计算成本的同时捕捉更大范围的空间上下文信息,尤其适用于高分辨率图像处理任务,如语义分割、目标检测等。 ### 频率自适应空洞卷积的特点及其解决方案 为了进一步优化传统的空洞卷积方法并减少其潜在缺陷,频率自适应空洞卷积(FADC: Frequency-Adaptive Dilated Convolution)应运而生。相比于其他改进策略(例如可变形卷积通过引入非对称偏移来调整采样网格位置),FADC仅需为每个像素点指定单一数值作为对应的空洞率,从而显著降低内存消耗以及简化实现过程。 以下是基于上述原理构建的一个简单示例代码片段展示如何动态设置不同的 dilation rates 来模拟 FADC 行为: ```python import torch.nn as nn class AdaptiveDilatedConv(nn.Module): def __init__(self, in_channels, out_channels, kernel_size=3): super(AdaptiveDilatedConv, self).__init__() # 定义基础卷积层 self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, padding=(kernel_size//2)*2) def forward(self, x, dilations): """ :param x: 输入张量 shape=[batch_size,C,H,W] :param dilations: 动态稀疏因子列表长度等于 batch size 和 H*W 尺寸匹配即可 即shape=[BHW],其中 B=batch_size;H=W=image height&width """ results = [] for b_idx in range(len(dilations)): result_b = nn.functional.conv2d( input=x[b_idx].unsqueeze(dim=0), weight=self.conv.weight, bias=self.conv.bias, stride=self.conv.stride, padding=dilations[b_idx]*(self.conv.kernel_size[0]-1)//2, dilation=dilations[b_idx]) results.append(result_b) return torch.cat(results,dim=0) ``` 此模块允许传入一组随样本变化的 `dilations` 参数控制局部区域内的膨胀程度,进而达到更灵活地适配各类场景需求的目的。 ### 时间维度上的应用实例 另外值得注意的是,在某些特殊领域比如金融反欺诈分析里头也会利用到类似的思路来进行模式识别工作。举例而言,“24小时资金闭环循环”的探测可以借助时间序列数据配合上适当配置好的空洞卷积结构完成高效挖掘可疑交易链条的任务[^3]: ```python for t in range(0, T, 24): net_flow_volatility = sliding_window_calculate_net_fund_flows(data[t:t+window]) if detect_anomaly(net_flow_volatility): flag_suspicious_activity() ``` 这里采用每隔一天滑动一次窗口的方式评估一段时间区间内部的资金流入流出情况是否存在异常剧烈波动现象,并据此作出相应标记动作。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值