パスのターゲットにファイルを作成せずに、パスがPythonで有効かどうかを確認します


98

パス(ディレクトリとファイル名を含む)があります。
ファイル名が有効かどうかをテストする必要があります。たとえば、ファイルシステムでそのような名前のファイルを作成できるかどうかを確認します。
ファイル名にはいくつかのUnicode文字が含まれています。

パスのディレクトリセグメントが有効でアクセス可能であると想定するのは安全です(私は質問をより一般的に適用できるようにしようとしていました、そして明らかに私は行き過ぎです)。

私は非常に私がない限り、何をエスケープする必要がありますする必要はありません持っています。

私が扱っているサンプル文字のいくつかを投稿しますが、どうやらそれらはスタック交換システムによって自動的に削除されます。とにかく、私はのような標準のユニコードエンティティを保持öし、ファイル名で無効なものだけをエスケープしたいと思います。


これがキャッチです。パスのターゲットにファイルがすでに存在する場合と存在しない場合があります。そのファイルが存在する場合は保持する必要があり、存在しない場合はファイルを作成しない必要があります。

基本的に、書き込み用のパスを実際に開かずにパスに書き込むことができるかどうかを確認したいと思います(そして、通常は自動ファイル作成/ファイルクローバーが必要です)。

など:

try:
    open(filename, 'w')
except OSError:
    # handle error here

ここから

触れたくない既存のファイル(そこにある場合)を上書きするか、そうでない場合はそのファイルを作成するため、受け入れられません。

私は私ができることを知っています:

if not os.access(filePath, os.W_OK):
    try:
        open(filePath, 'w').close()
        os.unlink(filePath)
    except OSError:
        # handle error here

しかし、それはでファイルを作成filePath、それを私はしなければならないでしょうos.unlink

結局、6行か7行を費やしてos.isvalidpath(filePath)、同じくらい単純なことをする必要があるようです。


余談ですが、(少なくとも)WindowsとMacOSで実行するにはこれが必要なので、プラットフォーム固有のものは避けたいと思います。


パスが存在し、それに書き込むことができることをテストしたい場合は、他のファイルを作成して削除するだけです。マルチユーザー/マルチスレッドの問題を回避するために、一意の名前(またはできるだけ一意の名前)を付けます。それ以外の場合は、OS固有の混乱に直接陥るパーミッションをチェックすることを検討しています。
トニーホプキンソン2012年

3
@Tony Hopkinson-基本的に、実際には何も書かずにパスに書き込むことができるかどうかを確認したいと思います。
偽の名前

ファイルに書き込むものがない場合、それができるかどうかを知る必要があるのはなぜですか?
Karl Knechtel 2012年

@Karl Knechtel-私がそれに書き込み、そこにすでにファイルがある場合、それは既存のファイルを損傷します。
偽の名前

2
@ FakeName-ここでは常に微妙な競合状態が発生します。ファイルが存在しないが作成できることを確認してからファイルを作成するまでの間に、他のプロセスでファイルが作成される可能性があり、とにかくファイルを壊してしまいます。もちろん、それは...これは現実的な問題であるかどうか、使用状況によって異なります
detly

回答:


153

tl; dr

is_path_exists_or_creatable()以下に定義されている関数を呼び出します。

厳密にはPython3です。それが私たちの役割です。

2つの質問の物語

「パス名の有効性をテストするにはどうすればよいですか。有効なパス名については、それらのパスの存在または書き込み可能性をテストするにはどうすればよいですか?」明らかに2つの別々の質問です。どちらも興味深いものであり、どちらもここで本当に満足のいく答えを受け取っていません...または、まあ、私がgrepできるところならどこでも

VIKKIさんの答えは、おそらく最も近いhewsが、の顕著な欠点があります。

  • 不必要にファイルハンドルを開く(...そして確実に閉じることができない)。
  • 0バイトのファイルを不必要に書き込みます(...そして信頼できるクローズまたは削除に失敗します)。
  • 無視できない無効なパス名と無視できるファイルシステムの問題を区別するOS固有のエラーを無視します。当然のことながら、これはWindowsでは重要です。(以下を参照してください。
  • テストするパス名の親ディレクトリを同時に(再)移動する外部プロセスに起因する競合状態を無視します。(以下を参照してください。
  • このパス名が古い、遅い、または一時的にアクセスできないファイルシステムに存在することに起因する接続タイムアウトを無視します。これは可能性が潜在的に一般向けサービスを公開DoS攻撃駆動型攻撃。(以下を参照してください。

それをすべて修正します。

質問#0:パス名の有効性は何ですか?

壊れやすい肉のスーツをパイソンがちりばめられた痛みのモシュピットに投げ込む前に、おそらく「パス名の妥当性」が何を意味するのかを定義する必要があります。正確には、何が妥当性を定義しますか?

「パス名の有効性」とは、パスまたはその親ディレクトリが物理的に存在するかどうかに関係なく、現在のシステムのルートファイルシステムに関するパス名の構文上の正確さを意味します。パス名は、ルートファイルシステムのすべての構文要件に準拠している場合、この定義では構文的に正しいです。

「ルートファイルシステム」とは、次のことを意味します。

  • POSIX互換システムでは、ファイルシステムはルートディレクトリ(/)にマウントされます。
  • Windowsでは、マウントされているファイルシステムで%HOMEDRIVE%、現在のWindowsインストールを含むコロン付きのドライブ文字(通常必須ではありませんC:)。

「構文の正確さ」の意味は、ルートファイルシステムのタイプによって異なります。以下のためのext4(そして最もしかしないすべてのPOSIX互換)ファイルシステム、パス名は構文的に正しい場合にのみそのパス名の場合:

  • nullバイトは含まれていません(つまり、\x00Pythonの場合)。これは、すべてのPOSIX互換ファイルシステムにとって厳しい要件です。
  • 255バイトより長いパスコンポーネントは含まれていません('a'*256Pythonなど)。パス成分は全く含まないパス名の最も長いストリングである/文字(例えば、bergtattindi、およびfjeldkamreneパス名で/bergtatt/ind/i/fjeldkamrene)。

構文の正確さ。ルートファイルシステム。それでおしまい。

質問1:パス名の有効性をどのように実行しますか?

Pythonでパス名を検証することは、驚くほど直感的ではありません。私はここで偽の名前にしっかりと同意しています。公式os.pathパッケージは、このためのすぐに使えるソリューションを提供するはずです。未知の(そしておそらく説得力のない)理由のために、そうではありません。幸いなことに、あなた自身のアドホックソリューションをアンロールすることはないこと、腸痛みます...

はい、実際はそうです。毛深いです。それは厄介です。それはおそらく、それが光るにつれて、それがゴロゴロと笑うように鳴きます。しかし、あなたは何をするつもりですか?Nuthin '。

私たちはすぐに低レベルコードの放射性の深淵に降ります。でもまずは高級店の話をしましょう。標準os.stat()およびos.lstat()関数は、無効なパス名が渡されると、次の例外を発生させます。

  • 存在しないディレクトリにあるパス名の場合、のインスタンスFileNotFoundError
  • 既存のディレクトリにあるパス名の場合:
    • Windowsでは、属性が(つまり)でWindowsErrorあるインスタンス。winerror123ERROR_INVALID_NAME
    • 他のすべてのOSでは:
    • nullバイト(つまり、'\x00')を含むパス名の場合、TypeError。のインスタンス。
    • 255バイトより長いパスコンポーネントを含むパス名の場合、OSErrorそのerrcode属性のインスタンスは次のとおりです。
      • SunOSおよび* BSDファミリーのOSでは、errno.ERANGE。(これはOSレベルのバグのようで、POSIX標準の「選択的解釈」とも呼ばれます。)
      • 他のすべてのOSでは、errno.ENAMETOOLONG

重要なことに、これは、既存のディレクトリにあるパス名のみが有効であることを意味します。os.stat()およびos.lstat()機能は、一般的な調達FileNotFoundError渡されたパス名が存在しないディレクトリに存在するとき、それらのパス名が無効であるかどうかに関係なく、例外を。ディレクトリの存在は、パス名の無効よりも優先されます。

これは、存在しないディレクトリにあるパス名が検証できないことを意味しますか?はい–既存のディレクトリに存在するようにこれらのパス名を変更しない限り。しかし、それでも安全に実行可能ですか?パス名を変更すると、元のパス名の検証が妨げられるべきではありませんか?

この質問に答えるには、ext4ファイルシステム上の構文的に正しいパス名に、(A) nullバイトを含むパスコンポーネントまたは(B)長さが255バイトを超えるパスコンポーネントが含まれていないことを上から思い出してください。したがって、ext4パス名は、そのパス名のすべてのパスコンポーネントが有効である場合にのみ有効です。これは、関心のあるほとんどの 実際のファイルシステムに当てはまります

その衒学的洞察は実際に私たちを助けますか?はい。これにより、一挙にフルパス名を検証するという大きな問題が、そのパス名のすべてのパスコンポーネントのみを検証するという小さな問題に軽減されます。任意のパス名は、次のアルゴリズムに従って、クロスプラットフォームの方法で(そのパス名が既存のディレクトリに存在するかどうかに関係なく)検証可能です。

  1. そのパス名をパスコンポーネントに分割します(たとえば、パス名/troldskog/faren/vildをリストに分割します['', 'troldskog', 'faren', 'vild'])。
  2. そのようなコンポーネントごとに:
    1. そのコンポーネントとともに存在することが保証されているディレクトリのパス名を新しい一時パス名(例:)に結合し/troldskogます。
    2. そのパス名をos.stat()またはに渡しos.lstat()ます。そのパス名、したがってそのコンポーネントが無効である場合、この呼び出しは、一般FileNotFoundError的な例外ではなく、無効のタイプを公開する例外を発生させることが保証されています。どうして?そのパス名は既存のディレクトリにあるためです。(循環論理は循環です。)

存在が保証されているディレクトリはありますか?はい。ただし、通常は1つだけです。ルートファイルシステムの最上位ディレクトリ(上記で定義)。

そのディレクトリが以前に存在することがテストされていたとしても、他のディレクトリにある(したがって存在することが保証されていない)パス名を競合状態に渡すos.stat()os.lstat()、競合状態を招きます。どうして?外部プロセスを同時に、そのディレクトリを削除することを防ぐことができないので、後に、そのテストが行われたが、前にそのパス名に渡されるos.stat()、またはos.lstat()。心を揺さぶる狂気の犬を解き放ちます!

上記のアプローチには、セキュリティという大きな副次的な利点もあります(それはいいことではありませんか?)具体的には:

信頼できないソースからの任意のパス名を、サービス拒否(DoS)攻撃やその他のブラックハットシェナニガンに渡すos.stat()os.lstat()、その影響を受けやすいものに渡すだけで検証する前面アプリケーション。悪意のあるユーザーは、古くなっているか遅いことがわかっているファイルシステム(NFS Samba共有など)にあるパス名を繰り返し検証しようとする可能性があります。その場合、着信パス名を盲目的に述べることは、最終的に接続タイムアウトで失敗するか、失業に耐えるあなたの弱い能力よりも多くの時間とリソースを消費する傾向があります。

上記のアプローチは、ルートファイルシステムのルートディレクトリに対してパス名のパスコンポーネントを検証するだけで、これを回避します。(それが古くなっている、遅い、またはアクセスできない場合でもパス名の検証よりも大きな問題が発生します。)

失くした?すごい。さぁ、始めよう。(Python 3を想定。「300の脆弱な希望とは何か、leycec?」を参照)

import errno, os

# Sadly, Python fails to provide the following magic number for us.
ERROR_INVALID_NAME = 123
'''
Windows-specific error code indicating an invalid pathname.

See Also
----------
https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
    Official listing of all such codes.
'''

def is_pathname_valid(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname for the current OS;
    `False` otherwise.
    '''
    # If this pathname is either not a string or is but is empty, this pathname
    # is invalid.
    try:
        if not isinstance(pathname, str) or not pathname:
            return False

        # Strip this pathname's Windows-specific drive specifier (e.g., `C:\`)
        # if any. Since Windows prohibits path components from containing `:`
        # characters, failing to strip this `:`-suffixed prefix would
        # erroneously invalidate all valid absolute Windows pathnames.
        _, pathname = os.path.splitdrive(pathname)

        # Directory guaranteed to exist. If the current OS is Windows, this is
        # the drive to which Windows was installed (e.g., the "%HOMEDRIVE%"
        # environment variable); else, the typical root directory.
        root_dirname = os.environ.get('HOMEDRIVE', 'C:') \
            if sys.platform == 'win32' else os.path.sep
        assert os.path.isdir(root_dirname)   # ...Murphy and her ironclad Law

        # Append a path separator to this directory if needed.
        root_dirname = root_dirname.rstrip(os.path.sep) + os.path.sep

        # Test whether each path component split from this pathname is valid or
        # not, ignoring non-existent and non-readable path components.
        for pathname_part in pathname.split(os.path.sep):
            try:
                os.lstat(root_dirname + pathname_part)
            # If an OS-specific exception is raised, its error code
            # indicates whether this pathname is valid or not. Unless this
            # is the case, this exception implies an ignorable kernel or
            # filesystem complaint (e.g., path not found or inaccessible).
            #
            # Only the following exceptions indicate invalid pathnames:
            #
            # * Instances of the Windows-specific "WindowsError" class
            #   defining the "winerror" attribute whose value is
            #   "ERROR_INVALID_NAME". Under Windows, "winerror" is more
            #   fine-grained and hence useful than the generic "errno"
            #   attribute. When a too-long pathname is passed, for example,
            #   "errno" is "ENOENT" (i.e., no such file or directory) rather
            #   than "ENAMETOOLONG" (i.e., file name too long).
            # * Instances of the cross-platform "OSError" class defining the
            #   generic "errno" attribute whose value is either:
            #   * Under most POSIX-compatible OSes, "ENAMETOOLONG".
            #   * Under some edge-case OSes (e.g., SunOS, *BSD), "ERANGE".
            except OSError as exc:
                if hasattr(exc, 'winerror'):
                    if exc.winerror == ERROR_INVALID_NAME:
                        return False
                elif exc.errno in {errno.ENAMETOOLONG, errno.ERANGE}:
                    return False
    # If a "TypeError" exception was raised, it almost certainly has the
    # error message "embedded NUL character" indicating an invalid pathname.
    except TypeError as exc:
        return False
    # If no exception was raised, all path components and hence this
    # pathname itself are valid. (Praise be to the curmudgeonly python.)
    else:
        return True
    # If any other exception was raised, this is an unrelated fatal issue
    # (e.g., a bug). Permit this exception to unwind the call stack.
    #
    # Did we mention this should be shipped with Python already?

完了。そのコードに目を細めないでください。(噛む。

質問#2:パス名の存在または作成可能性が無効である可能性があります。

無効な可能性のあるパス名の存在または作成可能性をテストすることは、上記の解決策を考えると、ほとんどの場合簡単です。ここでの小さな鍵は、渡されたパスをテストする前に、以前に定義された関数を呼び出すことです。

def is_path_creatable(pathname: str) -> bool:
    '''
    `True` if the current user has sufficient permissions to create the passed
    pathname; `False` otherwise.
    '''
    # Parent directory of the passed path. If empty, we substitute the current
    # working directory (CWD) instead.
    dirname = os.path.dirname(pathname) or os.getcwd()
    return os.access(dirname, os.W_OK)

def is_path_exists_or_creatable(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname for the current OS _and_
    either currently exists or is hypothetically creatable; `False` otherwise.

    This function is guaranteed to _never_ raise exceptions.
    '''
    try:
        # To prevent "os" module calls from raising undesirable exceptions on
        # invalid pathnames, is_pathname_valid() is explicitly called first.
        return is_pathname_valid(pathname) and (
            os.path.exists(pathname) or is_path_creatable(pathname))
    # Report failure on non-fatal filesystem complaints (e.g., connection
    # timeouts, permissions issues) implying this path to be inaccessible. All
    # other exceptions are unrelated fatal issues and should not be caught here.
    except OSError:
        return False

完了しました。完全ではないことを除いて。

質問3:Windowsでのパス名の存在または書き込み可能性が無効である可能性があります

警告があります。もちろんあります。

公式os.access()文書が認めているように:

注: I / O操作はos.access()、成功することを示している場合でも失敗する可能性があります。特に、通常のPOSIXパーミッションビットモデルを超えるパーミッションセマンティクスを持つ可能性のあるネットワークファイルシステムでの操作の場合はそうです。

当然のことながら、ここではWindowsが通常の容疑者です。NTFSファイルシステムでのアクセス制御リスト(ACL)の広範な使用のおかげで、単純なPOSIXパーミッションビットモデルは、基盤となるWindowsの現実にうまく対応していません。これは(おそらく)Pythonのせいではありませんが、それでもWindows互換アプリケーションにとっては問題になる可能性があります。

これがあなたの場合、より堅牢な代替手段が必要です。渡されたパスが存在しない場合は、代わりに、そのパスの親ディレクトリにすぐに削除されることが保証されている一時ファイルを作成しようとします。これは、作成性のより移植性の高い(高価な場合)テストです。

import os, tempfile

def is_path_sibling_creatable(pathname: str) -> bool:
    '''
    `True` if the current user has sufficient permissions to create **siblings**
    (i.e., arbitrary files in the parent directory) of the passed pathname;
    `False` otherwise.
    '''
    # Parent directory of the passed path. If empty, we substitute the current
    # working directory (CWD) instead.
    dirname = os.path.dirname(pathname) or os.getcwd()

    try:
        # For safety, explicitly close and hence delete this temporary file
        # immediately after creating it in the passed path's parent directory.
        with tempfile.TemporaryFile(dir=dirname): pass
        return True
    # While the exact type of exception raised by the above function depends on
    # the current version of the Python interpreter, all such types subclass the
    # following exception superclass.
    except EnvironmentError:
        return False

def is_path_exists_or_creatable_portable(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname on the current OS _and_
    either currently exists or is hypothetically creatable in a cross-platform
    manner optimized for POSIX-unfriendly filesystems; `False` otherwise.

    This function is guaranteed to _never_ raise exceptions.
    '''
    try:
        # To prevent "os" module calls from raising undesirable exceptions on
        # invalid pathnames, is_pathname_valid() is explicitly called first.
        return is_pathname_valid(pathname) and (
            os.path.exists(pathname) or is_path_sibling_creatable(pathname))
    # Report failure on non-fatal filesystem complaints (e.g., connection
    # timeouts, permissions issues) implying this path to be inaccessible. All
    # other exceptions are unrelated fatal issues and should not be caught here.
    except OSError:
        return False

ただし、さえていること、これは十分ではないかもしれません。

ユーザーアクセス制御(UAC)のおかげで、これまでにない模倣可能なWindows Vistaとその後のすべての反復は、システムディレクトリに関連するアクセス許可について露骨に嘘をついています。管理者以外のユーザーが正規C:\WindowsまたはC:\Windows\system32ディレクトリのいずれかにファイルを作成しようとすると、UACは表面的にユーザーに作成を許可し、作成されたすべてのファイルをそのユーザーのプロファイルの「仮想ストア」に実際に分離します。(だましているユーザーが長期的に有害な結果をもたらすと誰が想像できたでしょうか?)

狂ってる。これはWindowsです。

証明する

あえて?上記のテストを試運転する時が来ました。

UNIX指向のファイルシステムのパス名で禁止されている文字はNULLだけなので、それを利用して、冷たくて難しい真実を示しましょう。無視できないWindowsのシェナニガンは無視します。これは、率直に言って、私を同じように退屈させ、怒らせます。

>>> print('"foo.bar" valid? ' + str(is_pathname_valid('foo.bar')))
"foo.bar" valid? True
>>> print('Null byte valid? ' + str(is_pathname_valid('\x00')))
Null byte valid? False
>>> print('Long path valid? ' + str(is_pathname_valid('a' * 256)))
Long path valid? False
>>> print('"/dev" exists or creatable? ' + str(is_path_exists_or_creatable('/dev')))
"/dev" exists or creatable? True
>>> print('"/dev/foo.bar" exists or creatable? ' + str(is_path_exists_or_creatable('/dev/foo.bar')))
"/dev/foo.bar" exists or creatable? False
>>> print('Null byte exists or creatable? ' + str(is_path_exists_or_creatable('\x00')))
Null byte exists or creatable? False

正気を超えて。痛みを超えて。Pythonの移植性に関する懸念があります。


3
うん、それは私だった!クロスポータブルなパス名を検証する正規表現をまとめようとすることは無駄な作業であり、一般的なエッジケースでは失敗することが保証されています。たとえば、Windowsでのパス名の長さについて考えてみます。「実行時にシステムによって「\\?\」プレフィックスがより長い文字列に展開される可能性があるため、最大パス32,767文字は概算であり、この展開は全長に適用されます。 。」それを考えると、有効なパス名のみに一致する正規表現を作成することは実際には技術的に実行不可能です。代わりにPythonに従う方がはるかに合理的です。
セシルカレー

2
ああ。私は(しぶしぶ)わかります。あなたは正規表現をハックするよりもさらに奇妙なことをしています。ええ、それはさらに難しく失敗することが保証されています。また、「Windows固有のベース名から無効な部分文字列を削除するにはどうすればよいですか?」ではない問題の質問に完全に対処できません。(...これは、あなた自身の省略により、解決に失敗します–これもエッジケースのためです)しかし、「パス名の有効性と、有効なパス名については、それらのパスの存在または書き込み可能性をクロスポータブルでテストするにはどうすればよいですか?」
セシルカレー

1
ファイルシステム固有の制約は間違いなく有効な懸念事項ですが、両方の方法を削減します。信頼できないソースからの任意のパス名を消費する前面アプリケーションの場合、盲目的に読み取りを実行することは、せいぜい厄介な提案です。この場合、ルートファイルシステムの使用を強制することは賢明であるだけでなく賢明です。ただし、他のアプリケーションの場合、ユーザーベースは、抑制されていないファイルシステムアクセスを許可するのに十分信頼できる場合があります。それはかなり文脈に依存していると思います。これに注意してくれてありがとう、誰も!上記に警告を追加します。
セシルカレー

2
命名法に関しては、私はテスター名の前にis_。を付けるのが好きです。これは私の性格上の欠陥です。それにもかかわらず、十分に注意してください:あなたは誰もを喜ばせることはできません、そして時々あなたは誰もを喜ばせることができません。;)
セシルカレー

1
Fedora 24、python 3.5.3では、null文字が埋め込まれたパス名は次のようになります。ValueError:埋め込みnullバイト…追加する必要があります: `` `ただし、ValueError as exc:return False```はTypeErrorトラップの前後にあります。
mMerlin 2018年

47
if os.path.exists(filePath):
    #the file is there
elif os.access(os.path.dirname(filePath), os.W_OK):
    #the file does not exists but write privileges are given
else:
    #can not write there

path.exists単に失敗the file is not thereする可能性があるため、含まれているディレクトリが存在するかどうかをテストするなど、より細かいテストを行う必要がある場合があることに注意してください。


OPとの話し合いの結果、主な問題は、ファイル名にファイルシステムで許可されていない文字が含まれている可能性があることが判明しました。もちろん、それらを削除する必要がありますが、OPは、ファイルシステムが許す限り多くの人間の読み取り可能性を維持したいと考えています。

悲しいことに、私はこれに対する良い解決策を知りません。ただし、Cecil Curryの回答では、問題の検出を詳しく調べています。


いいえ。パスにファイルが存在する場合、または作成できる場合はtrueを返す必要があります。パスが無効な場合(Windowsに無効な文字が含まれているため)、falseを返す必要があります。
偽の名前

or can be createdよく私はあなたの質問からそれを読みませんでした。権限の読み取りは、ある程度プラットフォームに依存します。
SEから離れる人はいません。

1
@偽の名前:はい、プラットフォームの依存関係の一部が削除されますが、それでも一部のプラットフォームは他のプラットフォームが提供しないものを提供し、それらすべてにそれをラップする簡単な方法はありません。私は答えを更新しました、そこで見てください。
2012

1
この答えがなぜ賛成されたのか私にはわかりません。核となる質問への対処にリモートで隣接することはありません。簡潔に言うと、「パス名を検証してください」です。ここでは、パスのアクセス許可の検証は補助的な(そしてほとんど無視できる)質問です。toを呼び出すと、os.path.exists(filePath)技術的には無効なパス名で例外が発生しますが、これらの例外を明示的にキャッチして、他の無関係な例外と区別する必要があります。さらに、同じ呼び出しがFalse、現在のユーザーが読み取り権限を持たない既存のパスに戻ります。要するに、悪。
セシルカレー

1
@CecilCurry:質問に答えるには:質問の編集履歴を見てください。ほとんどの質問と同様に、最初はそれほど明確ではなく、今でもタイトルの文言だけがあなたが言った以外の方法で理解されるかもしれません。
2015

9

Python 3では、次の点について説明します。

try:
    with open(filename, 'x') as tempfile: # OSError if file exists or is invalid
        pass
except OSError:
    # handle error here

'x'オプションを使用すると、競合状態についても心配する必要がありません。マニュアルを参照してくださいここに

これで、名前が無効でない限り、非常に短命の一時ファイルがまだ存在しない場合に作成されます。あなたがそれと一緒に暮らすことができれば、それは物事を非常に単純化します。


2
この時点で、これを必要としたプロジェクトは、答えが関連性さえあり、私が実際に答えを受け入れることができないという点をはるかに超えています。
偽の名前

皮肉なことに、実用的な答えは十分ではありません。とにかく、ファイルが存在するかどうかを確認できると思います。含まれている場合は、ファイルを別の場所にコピーしてから、上書きしてみてください。
マット

5
open(filename,'r')   #2nd argument is r and not w

ファイルを開くか、ファイルが存在しない場合はエラーが発生します。エラーがある場合は、パスへの書き込みを試みることができます。できない場合は、2番目のエラーが発生します。

try:
    open(filename,'r')
    return True
except IOError:
    try:
        open(filename, 'w')
        return True
    except IOError:
        return False

また、見ているこちらをWindows上でのアクセス権について


1
テストファイルを明示的にunlink()する必要をなくすために、tempfile.TemporaryFile()スコープ外になると一時ファイルを自動的に破棄するを使用できます。
d_Bye 2012年

@FakeNameコードが異なります。2番目の部分でos.a​​ccessを使用することもできますが、私が提供したリンクをたどると、それは良い考えではないことがわかります。これにより、実際に開こうとするオプションが残ります。書き込みパス。
vikki 2012年

私は自分の道を構築しています os.path.joinので、 `\`エスケープの問題はありません。さらに、私は実際にはディレクトリ権限の問題を抱えていません。ディレクトリ(およびファイル名)の名前に問題があります。
偽の名前

@FakeNameの場合は、試して開くだけで済み(書き込む必要はありません)、filenameに無効な文字が含まれているとpythonでエラーが発生します。私は答えを編集しました
vikki 2012年

1
@HelgaIliashenko書き込み用に開くと、書き込みを行わずにすぐに閉じた場合でも、既存のファイルが上書きされます(空になります)。そのため、私は最初に読み取り用に開いていました。そうすれば、エラーが発生しなければ、既存のファイルがあることがわかります。
vikki 2017

-7

os.path.existsこれを試してみると、パスがチェックされ、True存在する場合と存在しFalseない場合は返されます。


1
いいえ。パスにファイルが存在する場合、または作成できる場合はtrueを返す必要があります。パスが無効な場合(Windowsに無効な文字が含まれているため)、falseを返す必要があります。
偽の名前

どのタイプの無効な文字ですか?
ナイルシュ2012年

Dunno-それはプラットフォーム固有です。
偽の名前

2
実際には、ファイルシステム固有です。
Piotr Kalinowski 2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.