Pythonを使用してタッチを実装しますか?


352

touchファイルの変更時刻とアクセス時刻を現在の時刻に設定するUnixユーティリティです。ファイルが存在しない場合は、デフォルトの権限で作成されます。

どのようにPython関数として実装しますか?クロスプラットフォームで完全なものになるようにしてください。

(「python touch file」の現在のGoogleの結果はそれほど優れていませんが、os.utimeをポイントしています。)


4
この機能がPython stdlibに組み込まれているので、受け入れられた回答の更新を検討してください。
マイル

@Miles受け入れられた答えは、質問が要求したとおりのことを行います-実際には、ライブラリを使用する代わりにPythonで関数を実装しました。
発泡スチロールのフライ

5
@styrofoamfly標準ライブラリ Pythonの一部です。質問者が本当に知りたいこと(そしてほとんどの人がGoogle経由でこの質問にアクセスすること)はtouch、Pythonプログラムで同様の機能を実現する方法であって、ゼロから再実装する方法ではない可能性が高いです。それらの人々は、pathlibソリューションまでスクロールダウンすることによって最もよくサービスされます。現在は組み込まれていますが、この回答の「Pythonタッチファイル」のGoogleランキングは、関連するドキュメントよりもはるかに優れています
マイル

@残念ながら、Python 2は(残念ながら)3よりも広く使用されているので、受け入れられた答えのほうが関連性が高いと思います。しかし、あなたのコメントは、2番目の答えを人々に示すのに役立ちます。
itadok 2018年

6
Python 2は今年の終わりにEOLです。
Max Gasner

回答:


304

これはPython 3.4以降では新しいようですpathlib

from pathlib import Path

Path('path/to/file.txt').touch()

これによりfile.txt、パスにが作成されます。

-

Path.touch(mode = 0o777、exist_ok = True)

このパスにファイルを作成します。modeを指定すると、プロセスのumask値と組み合わされて、ファイルモードとアクセスフラグが決定されます。ファイルがすでに存在する場合、exist_okがtrueである場合(およびその変更時刻が現在の時刻に更新されている場合)、関数は成功します。それ以外の場合は、FileExistsErrorが発生します。


3
Python2.7の場合:pip install pathlib
Andre

8
注意事項:編集Path('/some/path').mkdir()するファイルを含むディレクトリがtouch()まだ存在しない場合に使用します。
JacobIRR 2018

1
今はバグ修正のみなので、pathlib2代わりに使用する必要があると思います。したがって、Python 2.7では、次に。pathlibpathlibpip install pathlib2from pathlib2 import Path
Ian Lin、

@IanLin標準ライブラリがすでにサポートしていることを行うためにライブラリをインストールする理由はほとんどありません。bitbucket.org/pitrou/pathlib/src/defaultdocs.python.org/dev/library/pathlib.htmlを混同してますか?
Michael Mrozek

そのコメントは、その標準ライブラリを持たないPython 2.7について話すAndreのコメントへの返信です。pypi.org/project/pathlib2
Ian Lin

242

これは、他のソリューションよりも少しレースフリーになるようにしています。(このwithキーワードはPython 2.5で新しく追加されました。)

import os
def touch(fname, times=None):
    with open(fname, 'a'):
        os.utime(fname, times)

これとほぼ同じです。

import os
def touch(fname, times=None):
    fhandle = open(fname, 'a')
    try:
        os.utime(fname, times)
    finally:
        fhandle.close()

さて、実際にレースフリーにするためにはfutimes、ファイルを開いてからファイル名のタイムスタンプを変更するのではなく、開いているファイルハンドルのタイムスタンプを使用して変更する必要があります(名前が変更されている可能性があります)。残念ながら、Pythonには、同様の処理をfutimes行わずに呼び出す方法が用意されていないようですctypes...


編集

Nate Parsonsが指摘したように、Python 3.3は内部でsyscallの代わりにsyscall を使用するなどの関数にファイル記述子(when )の指定追加 します。言い換えると:os.supports_fdos.utimefutimesutimes

import os
def touch(fname, mode=0o666, dir_fd=None, **kwargs):
    flags = os.O_CREAT | os.O_APPEND
    with os.fdopen(os.open(fname, flags=flags, mode=mode, dir_fd=dir_fd)) as f:
        os.utime(f.fileno() if os.utime in os.supports_fd else fname,
            dir_fd=None if os.supports_fd else dir_fd, **kwargs)

これが本当の解決策です。futimes()が利用できない場合を除き、coreutilsのtouch(1)がこれを行う方法です。futimesは移植可能な関数ではなく、古い2.6 Linuxカーネルにも存在しないため、ENOSYSを処理し、使用してもutimeにフォールバックする必要があります。
グレンメイナード

(上記の校正エラー: "This" = open( "a")+ futimes。)幸いにも、futimesを使用しないという競合状態が実際に重要である場合を考えるのは困難です。最終的に「間違った」ケースは、open()とutime()の間でファイル名が変更されることです。この場合、新しいファイルを作成したり、古いファイルを変更したりすることはありません。それは重要なことですが、ほとんどの場合は問題ではありません。
グレンメイナード

cygwin touchは、読み取り専用ファイルに対して魔法をかけることができますが、このコードはできません。しかし、それをtry:<code>として囲むと機能するようです:IOErrorをe:(e.errnoをチェック)os.utime(filename、times)
dash-tom-bang

参考までに、3.3でfutimesが追加されたようです
Nate Parsons

注:組み込みfile関数はPython 3から削除され、open代わりに使用する必要があります。私は(geditのを)使用していますエディタのシンタックスハイライトはまだPythonの2を目標としているので、私は完全にこれを逃した
バート

42
def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()

24
このソリューションには潜在的な競合状態があります。ファイルが存在せず、この関数がopen()呼び出しに到達する前に別のプロセスによって作成された場合、ファイルの内容は切り捨てられます。'a'代わりにモードの使用を提案してください。
グレッグヒューギル

7
同意した。適切な解決策は次のとおりです:def touch(fname):open(fname、 'wa')。close()
stepancheg

@Gregは潜在的なレース状態の問題を解決しますが、open(fname, 'a').close()変更されることはありません。
SilentGhost 2009

@SilentGhost:そのとおりですが、ファイルが存在する場合は作成されただけなので問題ありません。もちろん、os.utime()既存のファイルについては、このままにしておく必要があります。
グレッグ

4
それが存在することを確認するために単に開いてから、utimeを呼び出すのはなぜですか?
イタドック2009

31

これを試してみませんか?:

import os

def touch(fname):
    try:
        os.utime(fname, None)
    except OSError:
        open(fname, 'a').close()

これにより、重要な競合状態が解消されると思います。ファイルが存在しない場合は、例外がスローされます。

ここで考えられる唯一の競合状態は、open()が呼び出される前に、os.utime()の後にファイルが作成された場合です。ただし、この場合はtouch()の呼び出し中に変更時刻が発生しているはずなので、変更時刻は予想どおりになるため、これは問題になりません。


8

以下は、ctypesを使用するコードです(Linuxでのみテスト済み)。

from ctypes import *
libc = CDLL("libc.so.6")

#  struct timespec {
#             time_t tv_sec;        /* seconds */
#             long   tv_nsec;       /* nanoseconds */
#         };
# int futimens(int fd, const struct timespec times[2]);

class c_timespec(Structure):
    _fields_ = [('tv_sec', c_long), ('tv_nsec', c_long)]

class c_utimbuf(Structure):
    _fields_ = [('atime', c_timespec), ('mtime', c_timespec)]

utimens = CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf))
futimens = CFUNCTYPE(c_int, c_char_p, POINTER(c_utimbuf)) 

# from /usr/include/i386-linux-gnu/bits/stat.h
UTIME_NOW  = ((1l << 30) - 1l)
UTIME_OMIT = ((1l << 30) - 2l)
now  = c_timespec(0,UTIME_NOW)
omit = c_timespec(0,UTIME_OMIT)

# wrappers
def update_atime(fileno):
        assert(isinstance(fileno, int))
        libc.futimens(fileno, byref(c_utimbuf(now, omit)))
def update_mtime(fileno):
        assert(isinstance(fileno, int))
        libc.futimens(fileno, byref(c_utimbuf(omit, now)))

# usage example:
#
# f = open("/tmp/test")
# update_mtime(f.fileno())

8

この回答は、キーワードwithがリリースされたときのPython-2.5以降のすべてのバージョンと互換性があります。

1.存在しない場合はファイルを作成+現在の時刻を設定
(コマンドとまったく同じtouch

import os

fname = 'directory/filename.txt'
with open(fname, 'a'):     # Create file if does not exist
    os.utime(fname, None)  # Set access/modified times to now
                           # May raise OSError if file does not exist

より堅牢なバージョン:

import os

with open(fname, 'a'):
  try:                     # Whatever if file was already existing
    os.utime(fname, None)  # => Set current time anyway
  except OSError:
    pass  # File deleted between open() and os.utime() calls

2.存在しない場合はファイルを作成するだけ
(時間を更新しない場合

with open(fname, 'a'):  # Create file if does not exist
    pass

3.ファイルのアクセス/変更時刻を更新するだけです
(存在しない場合はファイルを作成しません)

import os

try:
    os.utime(fname, None)  # Set access/modified times to now
except OSError:
    pass  # File does not exist (or no permission)

を使用os.path.exists()してもコードは単純化されません。

from __future__ import (absolute_import, division, print_function)
import os

if os.path.exists(fname):
  try:
    os.utime(fname, None)  # Set access/modified times to now
  except OSError:
    pass  # File deleted between exists() and utime() calls
          # (or no permission)

ボーナス:ディレクトリ内のすべてのファイルの更新時間

from __future__ import (absolute_import, division, print_function)
import os

number_of_files = 0

#   Current directory which is "walked through"
#   |     Directories in root
#   |     |  Files in root       Working directory
#   |     |  |                     |
for root, _, filenames in os.walk('.'):
  for fname in filenames:
    pathname = os.path.join(root, fname)
    try:
      os.utime(pathname, None)  # Set access/modified times to now
      number_of_files += 1
    except OSError as why:
      print('Cannot change time of %r because %r', pathname, why)

print('Changed time of %i files', number_of_files)

4
with open(file_name,'a') as f: 
    pass

失敗with open(fn,'a'): passまたはopen(fn, 'a').close()、Red Hat 7でPython 2.7.5を使用して変更時間を変更しない(ファイルシステムはXFS)。私のプラットフォームでは、これらのソリューションは存在しない場合は空のファイルを作成するだけです。:-/
olibre 2017

3

単純化:

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • openそこにファイルがあることを保証
  • これutimeにより、タイムスタンプが確実に更新されます

理論的には、誰かがの後にファイルを削除し、openutimeが例外を発生させる可能性があります。しかし、何か悪いことが起こったので、おそらくそれは大丈夫です。


1

複雑(バグがある可能性があります):

def utime(fname, atime=None, mtime=None)
    if type(atime) is tuple:
        atime, mtime = atime

    if atime is None or mtime is None:
        statinfo = os.stat(fname)
        if atime is None:
            atime = statinfo.st_atime
        if mtime is None:
            mtime = statinfo.st_mtime

    os.utime(fname, (atime, mtime))


def touch(fname, atime=None, mtime=None):
    if type(atime) is tuple:
        atime, mtime = atime

    open(fname, 'a').close()
    utime(fname, atime, mtime)

これは、GNU touchのように、アクセスまたは変更時刻の設定も許可しようとします。


1

必要な変数を含む文字列を作成し、それをos.systemに渡すことは論理的に思えるかもしれません。

touch = 'touch ' + dir + '/' + fileName
os.system(touch)

これはいくつかの点で不十分です(たとえば、空白を処理できない)ので、それを行わないでください。

より堅牢な方法はサブプロセスを使用することです:

subprocess.call(['touch', os.path.join(dirname, fileName)])

これはサブシェル(os.systemを使用)を使用するよりもはるかに優れていますが、それでもなお、迅速でダーティなスクリプトにのみ適しています。クロスプラットフォームプログラムには、受け入れられた回答を使用してください。


これは安全ではありません。ファイル名にスペースが含まれているとどうなりますか?
ayke

5
subprocess.call(['touch', os.path.join(dirname, fileName)])(でos.system)サブシェルを使用するよりもはるかに優れています。しかし、それでも、これは迅速で汚いスクリプトにのみ使用し、クロスプラットフォームプログラムには受け入れられた回答を使用してください。
ayke

1
touchはクロスプラットフォームで利用できるコマンドではありません(例:Windows)
Mike T

1

「open(file_name、 'a')。close()」は、WindowsのPython 2.7では機能しませんでした。「os.utime(file_name、None)」は問題なく動作しました。

また、ある日付より古い日付のディレクトリ内のすべてのファイルを再帰的に操作する必要がありました。ephemientの非常に役立つ回答に基づいてフォローを作成しました。

def touch(file_name):
    # Update the modified timestamp of a file to now.
    if not os.path.exists(file_name):
        return
    try:
        os.utime(file_name, None)
    except Exception:
        open(file_name, 'a').close()

def midas_touch(root_path, older_than=dt.now(), pattern='**', recursive=False):
    '''
    midas_touch updates the modified timestamp of a file or files in a 
                directory (folder)

    Arguements:
        root_path (str): file name or folder name of file-like object to touch
        older_than (datetime): only touch files with datetime older than this 
                   datetime
        pattern (str): filter files with this pattern (ignored if root_path is
                a single file)
        recursive (boolean): search sub-diretories (ignored if root_path is a 
                  single file)
    '''
    # if root_path NOT exist, exit
    if not os.path.exists(root_path):
        return
    # if root_path DOES exist, continue.
    else:
        # if root_path is a directory, touch all files in root_path
        if os.path.isdir(root_path):
            # get a directory list (list of files in directory)
            dir_list=find_files(root_path, pattern='**', recursive=False)
            # loop through list of files
            for f in dir_list:
                # if the file modified date is older thatn older_than, touch the file
                if dt.fromtimestamp(os.path.getmtime(f)) < older_than:
                    touch(f)
                    print "Touched ", f
        # if root_path is a file, touch the file
        else:
            # if the file modified date is older thatn older_than, touch the file
            if dt.fromtimestamp(os.path.getmtime(f)) < older_than:
                touch(root_path)

1

やってみませんか:newfile.py

#!/usr/bin/env python
import sys
inputfile = sys.argv[1]

with open(inputfile, 'w') as file:
    pass

python newfile.py foobar.txt

または

サブプロセスを使用:

import subprocess
subprocess.call(["touch", "barfoo.txt"])

0

以下で十分です。

import os
def func(filename):
    if os.path.exists(filename):
        os.utime(filename)
    else:
        with open(filename,'a') as f:
            pass

タッチに特定の時間を設定する場合は、os.utimeを次のように使用します。

os.utime(filename,(atime,mtime))

ここで、atimeとmtimeはどちらもint / floatであり、エポック時間(秒単位)から設定したい時間に等しい必要があります。


0

あなたがtry-exceptを気にしないなら...

def touch_dir(folder_path):
    try:
        os.mkdir(folder_path)
    except FileExistsError:
        pass

ただし、同じ名前のファイルが存在する場合、そのファイルは機能せず、警告なしに失敗します。


0

write_text()からpathlib.Path使用できます。

>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.