1

我正在编写一个脚本,需要从我们公司的数据库中删除大量电影/媒体文件。我正在 Mac 和 Python 环境中进行开发,这两种环境对我来说都是新的。我正在尝试使其尽可能具有弹性,因为它可能会破坏当前生产中的所有项目的数据库,而不是淘汰的旧项目。

想知道,如果有任何严重的逻辑缺陷,我是否正确登录等。以及任何其他建议,以使其尽可能健壮和谨慎,我们将不胜感激。

import os.path 
import shutil 
import datetime
import logging

root_path = "blah"
age_in_days = 2
truncate_size = 1024


class TruncateOldFiles():
    def delete_files(root_path):
        if os.path.exists(root_path):
            for dirpath, dirnames, filenames in os.walk(root_path):

                for file in filenames:
                    current_path = os.path.join(dirpath, file)
                    file_modified_time  = datetime.date(os.path.getmtime(current_path))

                    if ((datetime.datetime.now() - file_modified_time) > datetime.timedelta(days = age_in_days)):
                        count += 1


                if count == len(files) and not os.path.isfile("donotdelete.txt"):
                    for file in filenames:
                        try:
                            with open (file, 'w+') as file:
                                file.truncate(1024)

                            log()

                        except IOError:
                            pass



    def log():
        format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        logging.basicConfig(filename='myapp.log', level=logging.INFO, format = format)
        logging.info('Starting to truncate all files...')

此外,我只能在终端中编译它,但不太知道如何从中调试逻辑错误。我习惯于在 IDE 中使用 C++ 和 Java 进行编码,在这里我使用的 Xcode 似乎不利于我的开发风格。

谢谢你。

4

1 回答 1

0

我不确定提到的数据库在哪里发挥作用,您似乎只是在处理文件系统中的文件名。

  • 您正在使用os.path.isfile()它,我只会使用它来测试存在的东西是否是文件(而不是目录、链接等)。如果文件系统中不存在该名称,它会返回 False(我必须查一下),所以它可以工作。但我原以为它会引发 IOError。我的建议是os.path.exists()改用。

  • 比较date()和时要小心datetime(),它们是不一样的。并datetime()从时间戳使用.fromtimestamp

  • 我希望您意识到脚本总是在您启动脚本的目录中查找“donotdelete.txt”。os.walk不做os.chdir。如果这不是您想要的(并且donotdelete.txt通过在每个目录中设置一个不截断来保护某些特定目录,您应该测试os.path.exists(os.path.join(dirpath, 'donotdelete.txt'))

  • len(files)? 您的意思是len(filenames),通过比较来查看目录中的所有文件是否足够旧count

  • 您在测试年龄的 for 循环中正确地构造了 acurrent_pathdirpaththe 。filename在截断 for 循环中,您只需使用file,它将尝试在当前目录中打开。

  • 你正在制作一个旧式课程,我总是会制作新式新课程

    类 TruncateOldFiles(object): ....

  • 您应该self在每个方法中都有参数,然后您可以调用logas self.log(),因为除非您这样做,否则您的代码将无法工作TruncateOldFiles.log()

  • 我不确定日志中的格式信息是从哪里填写的。它写入(在更正了如何log()调用之后,只有starting to truncate .....每个文件的行才会被截断而没有额外的信息。

  • count 没有初始化,只是递增,你需要做count = 0

  • 我会将根路径、天数和截断大小参数传递给类创建。后两者可能是默认值。

  • 对于这种破坏性的不可逆操作,我在类创建中添加了一个参数,以便能够让它运行而无需执行任何操作,除了日志记录。也许这就是测试的donotdelete.txt目的,但它不会记录任何东西,所以你在日志中没有任何迹象表明程序会做什么。

  • 对于许多类,我有一个详细的参数来帮助查找错误,这是用于交互式运行并且与日志不同

  • 您有 1024 硬编码而不是使用 truncate_size,并且您正在打开和截断小于 truncate_size 的文件,这是不必要的。

  • 您在 for 循环和 with 语句中都使用file(python 关键字)作为变量名,它可能有效,但它不是很好的样式,并且在您扩展 for 循环中的代码时必然会导致问题。

我的课更像(但log()仍需要修复):

class TruncateOldFiles():
    def __init__(self, age_in_days=2, truncate_size=1024,
                 verbose=0, for_real=True):
        self._age = datetime.timedelta(days = age_in_days)
        self._truncate_size = truncate_size
        self._verbose = verbose
        self._for_real = for_real

    def delete_files(self, root_path):
        if not os.path.exists(root_path):
            if self._verbose > 1:
                print 'root_path', self._root_path, 'does not exists'
            return
        for dirpath, dirnames, filenames in os.walk(root_path):
            count = 0
            for filename in filenames:
                current_path = os.path.join(dirpath, filename)
                file_modified_time  = datetime.datetime.fromtimestamp(os.path.getmtime(current_path))
                if self._verbose > 0:
                    print file_modified_time, current_path
                if ((datetime.datetime.now() - file_modified_time) > self._age):
                    count += 1
            if count == len(filenames) and not os.path.exists(os.path.join(dirpath, "donotdelete.txt")):
                for filename in filenames:
                    current_path = os.path.join(dirpath, filename)
                    if os.path.getsize(current_path) <= self._truncate_size:
                        if self._verbose > 0:
                            print 'not big enough:', current_path
                        continue
                    try:
                        if self._verbose > 0:
                            print 'truncating:', file
                        if self._for_real:
                            with open (current_path, 'w+') as fp:
                                fp.truncate(self._truncate_size)
                        self.log()
                    except IOError:
                        pass

    def log(self):
        format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        logging.basicConfig(filename='myapp.log', level=logging.INFO, format = format)
        logging.info('Starting to truncate all files...')

以及测试它的代码:

tof = TruncateOldFiles(verbose=1, for_real=False)
tof.delete_files('blah')
于 2013-03-27T15:08:29.917 回答