如何使用 python 从文件的开头和结尾删除特定数量的字节?

How can I remove a specific number of bytes from the beginning and end of a file using python?

我有一个文件夹,里面装满了需要修改的文件,以便以真实格式提取真实文件。

我需要从文件的开头和结尾删除一定数量的字节,以便提取我要查找的数据。

如何在 python 中执行此操作?

如果您能提供任何帮助或指导,我将不胜感激。

  1. 对文件进行递归迭代os.walk
  2. 更改文件中的位置:f.seek
  3. 获取文件大小:os.stat
  4. 从当前位置删除数据到文件末尾:f.truncate

所以,基本逻辑:

  1. 遍历文件
  2. 获取文件大小。
  3. 打开文件('rb+' 我想)
  4. 从您想要读取文件的位置寻找位置
  5. 读到要删除的字节数 (f.read(file_size - top_dropped - bottom_dropped ))
  6. 寻找(0)
  7. 将读取的文本写入文件
  8. 截断文件

你的问题结构很糟糕,但由于这是一些高级的东西,我会为你提供一个代码。

您现在可以使用 os.walk() 递归遍历您想要的目录并应用我的 slicefile() 函数。

此代码执行以下操作:

  1. 检查开始和结束参数的有效性后,它会在打开的文件之上创建一个内存映射。 mmap() 创建一个内存映射对象,在这种情况下,映射文件系统的一部分,文件将在其上写入。该对象通过一些额外的方法(如 move())公开了一个类似字符串和类似文件的接口。因此,您可以将内存映射视为字符串或文件,或使用 size()、move()、resize() 或您需要的任何其他方法。

  2. 我们计算开始和结束之间的距离,即这是我们最终将拥有多少字节。

  3. 我们移动字节流,end-start long,从我们的起始位置开始到 0 位置,即我们将它们向后移动起始点指示的字节数。

  4. 我们丢弃文件的其余部分。 IE。我们将其大小调整为结束-开始字节。所以,剩下的就是我们的新字符串了。

文件越大操作时间越长。不幸的是,您对此无能为力。如果文件很大,这是最好的选择。该过程与从内存数组的 start/middle 中删除项目时的过程相同,只是必须对其进行缓冲(以块为单位)以免过多填充 RAM。

如果您的文件小于空闲 RAM 的三分之一 space,您可以使用 f.read() 将其整个加载到一个字符串中,然后对加载的内容执行字符串切片( s = s[start:end] ),然后通过再次打开并执行 f.write(s) 将其写回文件。 如果你有足够的磁盘space,你可以打开另一个文件,在原始文件中寻找你想要的起点,然后分块读取并写入新文件。甚至可能使用 shutil.copyfileobj()。之后,您删除原始文件并使用 os.rename() 将新文件放回原来的位置。这些是您仅有的 3 个选项。 整个文件进入内存;通过向后缓冲然后调整大小来移动;并且,复制到另一个文件,然后重命名它。第二个选项是最通用的,无论大小文件都不会让您失望。所以我用了。

OK,不止3个选项。还有第四种选择。通过使用低级操作操纵文件系统本身,可以从文件开头截断 N 个字节。编写一种截断开头而不是结尾的 truncate() 函数。但这无异于自杀。最后会发生内存碎片,整个混乱会出现。反正你不需要这样的速度。在您的脚本完成之前,您将耐心等待。 :D

为什么我使用 mmap()?

因为它使用了 OS 中实现的内存映射,而不是全新的代码。这减少了处理打开的文件所需的系统调用次数。一半的工作都交给了操作系统,让Python松了一口气。

因为它主要是用 C 语言编写的,这使得它比纯 Python 实现要快一些。

因为它实现了我们需要的 move()。缓冲和所有内容都已写入,因此不需要笨重的 while 循环,这将是替代(手动)解决方案。

等等...


from mmap import mmap

def slicefile (path, start=0, end=None):
    f = open(path, "r+b") # Read and write binary
    f.seek(0, 2)
    size = f.tell()
    start = 0    if start==None else start
    end   = size if end==None   else end
    start = size+start if start<0 else start
    end   = size+end   if end<0   else end
    end   = size if end>size else end
    if (end==size and start==0) or (end<=start):
        f.close()
        return
    # If start is 0, no need to move anything, just cut off the rest after end
    if start==0:
        f.seek(end)
        f.truncate()
        f.close()
        return
    # Modify in place using mapped memory:
    newsize = end-start
    m = mmap(f.fileno(), 0)
    m.move(0, start, newsize)
    m.flush()
    m.resize(newsize)
    m.close()
    f.close()