有没有一种方法可以高效删除多个文件?

问题描述 投票:1回答:3

正如标题中所说,有没有更好的方法可以在python中删除多个文件?目前,我是通过对每个文件进行循环删除。

import os
files = ["test_file.txt", "test_failed.txt"]
for file in files:
    if os.path.exists(file):
        os.remove(file)
python python-3.x
3个回答
0
投票

让我们把这个问题看清楚。

我们从拆解 for-循环进入字节码,使用 dis 模块。

In [23]: dis.dis('for f in files: os.remove(f)')
  1           0 SETUP_LOOP              22 (to 24)
              2 LOAD_NAME                0 (files)
              4 GET_ITER
        >>    6 FOR_ITER                14 (to 22)
              8 STORE_NAME               1 (f)
             10 LOAD_NAME                2 (os)
             12 LOAD_METHOD              3 (remove)
             14 LOAD_NAME                1 (f)
             16 CALL_METHOD              1
             18 POP_TOP
             20 JUMP_ABSOLUTE            6
        >>   22 POP_BLOCK
        >>   24 LOAD_CONST               0 (None)
             26 RETURN_VALUE

这里唯一真正的 "困难"(而且是小困难)是重复查找名称 os.remove. 所以,我们先为它创建一个本地别名来摆脱它。

In [24]: rm = os.remove
Out[24]: <function posix.remove(path, *, dir_fd=None)>

In [25]: dis.dis('for f in files: rm(f)')
  1           0 SETUP_LOOP              20 (to 22)
              2 LOAD_NAME                0 (files)
              4 GET_ITER
        >>    6 FOR_ITER                12 (to 20)
              8 STORE_NAME               1 (f)
             10 LOAD_NAME                2 (rm)
             12 LOAD_NAME                1 (f)
             14 CALL_FUNCTION            1
             16 POP_TOP
             18 JUMP_ABSOLUTE            6
        >>   20 POP_BLOCK
        >>   22 LOAD_CONST               0 (None)
             24 RETURN_VALUE

这样可以节省 单字节码指令 (LOAD_METHOD)每个文件。

一般来说,列表理解 可以 快于 for-循环。但当我尝试使用10个空的但现有的文件的列表时。

In [15]: %timeit -n1 -r1 for f in files: os.remove(f)
71.3 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

与使用本地别名的列表理解相比。

In [32]: %timeit -n1 -r1 [rm(f) for f in files]
71 µs ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)

实际上 没有区别。

在最近的UNIX系统上测量 (FreeBSD 12, UFS文件系统在硬盘上,使用 %timeit 在IPython中)。)

  • os.path.exists() 在一个循环中,每个文件大约需要2 µs。
  • os.remove() 在循环中,每个文件大约需要7-10 µs。

在循环中使用 os.stat 直接而不是通过 exists 并没有太大的区别。而 os.remove 使用 remove(3) C库的调用。所以它的大部分时间都花在了文件系统操作上,而这些操作本质上都是 很慢 与现代CPU相比。

所以除了用C语言写这个东西,直接用系统调用(不是C库函数),可能也没什么好处。


2
投票

你做的事情并没有什么特别低效的地方。

不过如果你想删除整个目录,可以用rmtree。

import shutil
shutil.rmtree('/my-dir/')

0
投票

这个速度的方法不多。文件的最终删除将不得不使用以下方法来完成(至少在Linux上,我猜测你的操作系统是基于文件名的)。unlink(2) 系统调用,一次只能删除一个文件。我猜想文件系统会做一些诡计来给你提供一种并行性,所以可能会通过使用多个进程来获得一些速度的提升。这里有一些其他的建议。

  1. 丢掉 if os.path.exists. 这将运行一个 stat(2) 来检查文件是否存在,而且每次循环的迭代都会增加固定的时间。最好是直接去删除它,如果文件不存在,就抓住异常,忽略它,然后继续前进(原谅而不是权限)。
  2. 如果这些文件都在一个目录中,那么直接调用一些东西(甚至可能是shell out)来删除整个目录可能是有意义的。不过你应该衡量一下。
  3. 如何获得文件列表?这也会很耗费时间。如果要从文件中读取或生成,你也应该在优化中考虑这一点。
© www.soinside.com 2019 - 2024. All rights reserved.