Terapkan sentuhan menggunakan Python?

352

touchadalah utilitas Unix yang menetapkan waktu modifikasi dan akses file ke waktu saat ini. Jika file tidak ada, itu dibuat dengan izin default.

Bagaimana Anda mengimplementasikannya sebagai fungsi Python? Cobalah untuk menjadi lintas platform dan lengkap.

(Hasil Google saat ini untuk "file python touch" tidak terlalu bagus, tetapi arahkan ke os.utime .)

itsadok
sumber
4
Harap pertimbangkan untuk memperbarui jawaban yang diterima sekarang karena fungsi ini dibangun ke dalam stdlib Python.
Miles
@ Miles Jawaban yang diterima tidak persis apa yang ditanyakan pertanyaan - itu benar-benar menerapkan fungsi dalam Python daripada menggunakan perpustakaan.
Terbang styrofoam
5
@styrofoamfly Perpustakaan standar adalah bagian dari Python. Sangat mungkin bahwa apa yang ingin diketahui oleh penanya (dan sebagian besar orang yang tiba di pertanyaan ini melalui Google) adalah bagaimana mencapai touchfungsionalitas -seperti dalam program Python mereka, bukan bagaimana mengimplementasikannya kembali dari awal; orang-orang itu paling baik dilayani dengan menggulir ke bawah ke pathlibsolusi. Meskipun sekarang sudah ada di dalamnya, jawaban ini memiliki peringkat Google yang jauh lebih baik untuk "file python touch" daripada dokumentasi yang relevan .
Miles
@miles Python 2 (sayangnya) masih lebih banyak digunakan daripada 3, jadi saya pikir jawaban yang diterima masih lebih relevan. Tetapi komentar Anda berhasil mengarahkan orang ke jawaban kedua.
itsadok
6
Python 2 adalah EOL pada akhir tahun ini.
Max Gasner

Jawaban:

304

Sepertinya ini baru pada Python 3.4 - pathlib.

from pathlib import Path

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

Ini akan membuat file.txtdi jalan.

-

Path.touch (mode = 0o777, exist_ok = Benar)

Buat file di jalur yang diberikan ini. Jika mode diberikan, itu dikombinasikan dengan nilai umask proses untuk menentukan mode file dan bendera akses. Jika file sudah ada, fungsi berhasil jika exist_ok benar (dan waktu modifikasinya diperbarui ke waktu saat ini), jika tidak FileExistsError dinaikkan.

voidnologo
sumber
3
Pada Python2.7:pip install pathlib
Andre Miras
8
note to self: gunakan Path('/some/path').mkdir()jika direktori yang berisi file yang akan touch()diedit belum ada.
JacobIRR
1
Saya pikir kita harus menggunakan pathlib2bukan pathlibkarena pathlibhanya bugfix sekarang. Oleh karena itu, pada Python 2.7: pip install pathlib2dan kemudian from pathlib2 import Path.
Ian Lin
@IanLin Ada sedikit alasan untuk menginstal pustaka untuk melakukan sesuatu yang sudah didukung pustaka standar. Apakah Anda membingungkan bitbucket.org/pitrou/pathlib/src/default dengan docs.python.org/dev/library/pathlib.html ?
Michael Mrozek
Komentar itu menjawab komentar Andre yang berbicara tentang Python 2.7, yang tidak memiliki perpustakaan standar itu. Jangan ragu untuk membaca dokumen di pypi.org/project/pathlib2
Ian Lin
242

Ini mencoba untuk menjadi sedikit lebih bebas dari solusi yang lain. (Kata withkunci tersebut baru dalam Python 2.5.)

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

Kira-kira setara dengan ini.

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

Sekarang, untuk benar-benar membuatnya bebas perlombaan, Anda perlu menggunakan futimesdan mengubah stempel waktu dari filehandle yang terbuka, alih-alih membuka file dan kemudian mengubah stempel waktu pada nama file (yang mungkin telah diubah namanya). Sayangnya, Python tampaknya tidak menyediakan cara untuk menelepon futimestanpa melalui ctypesatau serupa ...


EDIT

Seperti dicatat oleh Nate Parsons , Python 3.3 akan menambahkan menentukan deskriptor file (kapan os.supports_fd) ke fungsi seperti os.utime, yang akan menggunakan futimessyscall bukan utimessyscall di bawah tenda. Dengan kata lain:

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)
singkat
sumber
Ini adalah solusi nyata - dan ini adalah bagaimana sentuhan (1) dalam coreutils melakukannya, kecuali futimes () tidak tersedia. futimes bukan fungsi portabel dan bahkan tidak ada pada kernel Linux 2.6 yang lebih lama, jadi Anda perlu berurusan dengan ENOSYS dan kembali ke utime bahkan jika Anda menggunakannya.
Glenn Maynard
(Kesalahan pengoreksian ulang di atas: "Ini" = buka ("a") + futimes.) Untungnya, sulit untuk memikirkan kasus di mana kondisi balapan tidak menggunakan futimes sebenarnya penting. Kasus "salah" yang mungkin Anda dapatkan adalah file diubah namanya antara open () dan utime (), dalam hal ini Anda tidak akan membuat file baru atau menyentuh yang lama. Itu bisa berarti, tetapi sebagian besar waktu tidak.
Glenn Maynard
cygwin touch dapat melakukan keajaiban pada file read-only, tetapi kode ini tidak bisa. Namun sepertinya berfungsi jika saya mengelilinginya dengan mencoba: <code> kecuali IOError sebagai e: (periksa e.errno) os.utime (nama file, waktu)
dash-tom-bang
FYI, sepertinya futimes ditambahkan pada 3.3
Nate Parsons
Catatan: filefungsi bawaan dihapus dari Python 3, dan openharus digunakan sebagai gantinya. Saya benar-benar merindukan ini karena penyorotan sintaks editor yang saya gunakan (gedit) masih menargetkan Python 2.
Bart
42
def touch(fname):
    if os.path.exists(fname):
        os.utime(fname, None)
    else:
        open(fname, 'a').close()
SilentGhost
sumber
24
Ada kemungkinan kondisi ras dalam solusi ini: Jika file tidak ada, dan dibuat oleh proses lain sebelum fungsi ini mencapai open()panggilan, maka konten file akan terpotong. Sarankan menggunakan mode 'a'sebagai gantinya.
Greg Hewgill
7
Sepakat. Solusi yang tepat adalah: def touch (fname): open (fname, 'wa').
Close
@Reg, sementara itu memecahkan masalah kondisi balap potensial, open(fname, 'a').close()tidak akan mengubah atime.
SilentGhost
@ SilentGhost: Itu benar, tapi tidak apa-apa karena jika file ada maka baru saja dibuat. Tentu saja Anda akan meninggalkan panggilan os.utime()di sana untuk file yang sudah ada sebelumnya.
Greg Hewgill
4
Mengapa tidak membuka saja untuk memastikan itu ada, lalu menelepon utime?
itsadok
31

Mengapa tidak mencoba ini ?:

import os

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

Saya percaya ini menghilangkan kondisi ras yang penting. Jika file tidak ada maka pengecualian akan dibuang.

Satu-satunya kondisi ras yang mungkin di sini adalah jika file dibuat sebelum open () dipanggil tetapi setelah os.utime (). Tetapi ini tidak masalah karena dalam hal ini waktu modifikasi akan seperti yang diharapkan karena pasti terjadi selama panggilan untuk menyentuh ().

jcoffland
sumber
8

Berikut ini beberapa kode yang menggunakan ctypes (hanya diuji di 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())
eug
sumber
8

Jawaban ini kompatibel dengan semua versi sejak Python-2.5 ketika kata kunci withtelah dirilis.

1. Buat file jika tidak ada + Atur waktu sekarang
(persis sama dengan perintah 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

Versi yang lebih kuat:

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. Cukup buat file jika tidak ada
(tidak memperbarui waktu)

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

3. Cukup perbarui akses file / waktu yang dimodifikasi
(tidak membuat file jika tidak ada)

import os

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

Penggunaan os.path.exists()tidak menyederhanakan kode:

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)

Bonus: Perbarui waktu semua file dalam direktori

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)
olibre
sumber
4
with open(file_name,'a') as f: 
    pass
Matt
sumber
Gagal : with open(fn,'a'): passatau alternatif open(fn, 'a').close()tidak mengubah waktu yang dimodifikasi menggunakan Python 2.7.5 pada Red Hat 7 (filesystem adalah XFS). Di platform saya, solusi ini hanya membuat file kosong jika tidak ada. : - /
olibre
3

Sederhana:

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • The openmemastikan tidak ada file
  • yang utimememastikan bahwa cap waktu diperbarui

Secara teoritis, ada kemungkinan seseorang akan menghapus file setelahnya open, menyebabkan utime memunculkan eksepsi. Tapi bisa dibilang itu tidak masalah, karena sesuatu yang buruk memang terjadi

itsadok
sumber
1

Kompleks (mungkin bermasalah):

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)

Ini mencoba juga memungkinkan pengaturan waktu akses atau modifikasi, seperti sentuhan GNU.

itsadok
sumber
1

Tampaknya logis untuk membuat string dengan variabel yang diinginkan, dan meneruskannya ke os.system:

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

Ini tidak memadai dalam beberapa cara (misalnya, tidak menangani spasi putih), jadi jangan lakukan itu.

Metode yang lebih kuat adalah dengan menggunakan subproses:

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

Meskipun ini jauh lebih baik daripada menggunakan subkulit (dengan osistem), itu masih hanya cocok untuk skrip cepat dan kotor; gunakan jawaban yang diterima untuk program lintas platform.

belacqua
sumber
Ini tidak terlalu aman: apa yang terjadi ketika ada ruang dalam nama file?
ayke
5
subprocess.call(['touch', os.path.join(dirname, fileName)])jauh lebih baik daripada menggunakan subshell (with os.system). Tapi tetap saja, gunakan ini hanya untuk skrip cepat dan kotor, gunakan jawaban yang diterima untuk program lintas platform.
ayke
1
touchbukan perintah lintas platform yang tersedia (mis. Windows)
Mike T
1

"open (file_name, 'a'). close ()" tidak bekerja untuk saya di Python 2.7 di Windows. "os.utime (file_name, None)" bekerja dengan baik.

Juga, saya memiliki kebutuhan untuk secara rekursif menyentuh semua file dalam direktori dengan tanggal yang lebih tua dari tanggal tertentu. Saya membuat hte berikut berdasarkan respon ephemient yang sangat membantu.

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)
Cadvena
sumber
1

Mengapa Anda tidak mencoba: newfile.py

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

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

python newfile.py foobar.txt

atau

gunakan subproses:

import subprocess
subprocess.call(["touch", "barfoo.txt"])
suresh Palemoni
sumber
0

Berikut ini sudah cukup:

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

Jika Anda ingin mengatur waktu tertentu untuk disentuh, gunakan os.utime sebagai berikut:

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

Di sini, atime dan mtime keduanya harus int / float dan harus sama dengan waktu zaman dalam detik dengan waktu yang ingin Anda atur.

Amar chand Dargad
sumber
0

Jika Anda tidak keberatan dengan coba-kecuali ...

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

Satu hal yang perlu diperhatikan, jika ada file dengan nama yang sama maka tidak akan berfungsi dan akan gagal diam-diam.

Manusia gua
sumber
0

write_text()dari pathlib.Pathbisa digunakan.

>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0
SuperNova
sumber