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 ループで、 current_pathfromdirpathと を正しく構築します。filename切り捨て for ループfileでは、現在のディレクトリで開こうとする を使用するだけです。

  • あなたは古いスタイルのクラスを作成しています。私は常に新しいクラスを新しいスタイルにします:

    class TruncateOldFiles(オブジェクト): ....

  • self各メソッドにパラメーターが必要です。そうしないとコードが機能しないため、 aslogを呼び出すことができますself.log()TruncateOldFiles.log()

  • ログのフォーマット情報がどこから入力されるのかわかりません。書き込みます(呼び出し方法を修正した後、各ファイルlog()の行のみがstarting to truncate .....追加情報なしで切り捨てられます。

  • カウントは初期化されておらず、インクリメントされているだけです。実行する必要がありますcount = 0

  • ルート パス、日数を渡し、クラスの作成にパラメーターのサイズを切り詰めます。後者の 2 つはおそらくデフォルトです。

  • この種の破壊的で元に戻せない操作については、クラスの作成に引数を追加して、ロギング以外は何もせずに実行できるようにします。おそらくそれがテストの目的donotdelete.txtですが、それは何もログに記録しないため、プログラムが何をしているのかログに示されません。

  • 多くのクラスについて、エラーを見つけるのに役立つ詳細な引数があります。これは対話型の実行用であり、ログとは異なります

  • truncate_size を使用する代わりに 1024 がハードコードされており、不要な truncate_size よりも小さいファイルを開いて切り捨てています。

  • for ループと with ステートメントの両方で (python キーワード) を変数名として使用するfileと、おそらく機能しますが、スタイルがあまり良くなく、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 に答える