2013-01-17 35 views
1

我在写一个脚本,需要从我们公司的数据库中删除大量的电影/媒体文件。我正在开发Mac和Python环境,这两者对我来说都是新手。我试图尽可能地提高弹性,因为它可能会破坏当前正在生产的所有项目的数据库,而不是已经退役的旧项目的数据库。截断文件并在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对于我的开发风格似乎不太有利。

谢谢。

回答

0

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

  • 您正在使用os.path.isfile()其中如果存在的东西是一个文件(而不是目录,链接等),我只会用于测试。它返回假(如果名称不存在于文件系统中,我必须查看),因此它可以工作。但是我会预料它会抛出一个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

  • 您正确地构建从dirpath一个current_path,并在for循环,你测试年龄filename。在for循环截断你只需要使用file,这会尝试在当前目录中打开。

  • 您制作的是旧式类我总是会做出新的类new style

    类TruncateOldFiles(对象): ....

  • 你应该在每个self参数方法,那么你可以调用logself.log(),因为除非你做TruncateOldFiles.log()

  • 您的代码将无法正常工作,我不知道在哪里的日志格式信息得到填补从。它写(修正如何log()被调用时,只有线starting to truncate .....它会截断没有附加信息的每个文件之后。

  • 数将不会被初始化,只是递增,你需要做的count = 0

  • 我会通过在根路径中,days和truncate size是创建类的参数,后两者可能是默认值。

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

  • 对于许多类我有一个详细的说法,与发现错误帮助,这是一个互动的运行,从日志不同

  • 你有1024硬编码,而不是使用truncate_size,和你打开和截断小于truncate_size的文件是不必要的。

  • 您使用file(蟒关键字)作为变量名都在for循环以及在with语句,它可能工作,但它是不是很好的风格和必然导致的问题,当你扩展代码在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')