Thực hiện liên lạc bằng Python?


352

touchlà một tiện ích Unix đặt thời gian sửa đổi và truy cập của tệp thành thời gian hiện tại trong ngày. Nếu tệp không tồn tại, nó được tạo với quyền mặc định.

Làm thế nào bạn sẽ thực hiện nó như là một hàm Python? Cố gắng là đa nền tảng và hoàn thành.

(Kết quả hiện tại của Google cho "tệp cảm ứng python" không phải là tuyệt vời, nhưng chỉ đến os.utime .)


4
Vui lòng xem xét cập nhật câu trả lời được chấp nhận ngay bây giờ rằng chức năng này được tích hợp vào stdlib của Python.
Miles

@Miles Câu trả lời được chấp nhận thực hiện chính xác những gì câu hỏi yêu cầu - nó thực sự đã triển khai hàm trong Python thay vì sử dụng thư viện.
xốp bay

5
@styrofoamfly Thư viện chuẩn một phần của Python. Điều thực sự có khả năng là điều mà người hỏi câu hỏi thực sự muốn biết (và hầu hết mọi người đến với câu hỏi này thông qua Google) là cách đạt được touchchức năng giống như trong các chương trình Python của họ, chứ không phải cách triển khai lại từ đầu; những người đó được phục vụ tốt nhất bằng cách cuộn xuống pathlibgiải pháp. Mặc dù hiện đã được tích hợp sẵn, câu trả lời này có thứ hạng Google tốt hơn cho "tệp cảm ứng python" so với tài liệu liên quan .
Miles

@miles Python 2 vẫn (không may) vẫn được sử dụng rộng rãi hơn 3, vì vậy tôi nghĩ rằng câu trả lời được chấp nhận vẫn là câu trả lời phù hợp hơn. Nhưng bình luận của bạn làm tốt công việc hướng mọi người đến câu trả lời thứ hai.
itadok

6
Python 2 là EOL vào cuối năm nay.
Max Gasner

Câu trả lời:


304

Có vẻ như đây là bản mới của Python 3.4 - pathlib.

from pathlib import Path

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

Điều này sẽ tạo ra một file.txtđường dẫn.

-

Path.touch (mode = 0o777, tồn tại_ok = True)

Tạo một tập tin tại đường dẫn này. Nếu chế độ được đưa ra, nó được kết hợp với giá trị umask của quá trình để xác định chế độ tệp và cờ truy cập. Nếu tệp đã tồn tại, hàm sẽ thành công nếu tồn tại là đúng (và thời gian sửa đổi của nó được cập nhật vào thời điểm hiện tại), nếu không thì FileExistsError được nâng lên.


3
Trên Python2.7:pip install pathlib
Andre Miras

8
lưu ý đến bản thân: sử dụng Path('/some/path').mkdir()nếu thư mục chứa tệp cần touch()ed chưa tồn tại.
JacobIRR

1
Tôi nghĩ rằng chúng ta nên sử dụng pathlib2thay pathlibvì bởi vì pathlibbây giờ chỉ có lỗi. Do đó, trên Python 2.7: pip install pathlib2và sau đó from pathlib2 import Path.
Ian Lin

@IanLin Có rất ít lý do để cài đặt thư viện để làm điều gì đó mà thư viện chuẩn đã hỗ trợ. Bạn có nhầm lẫn bitbucket.org/pitrou/pathlib/src/default với docs.python.org/dev/l Library / pathlib.html ?
Michael Mrozek

Nhận xét đó đang trả lời bình luận của Andre khi nói về Python 2.7, không có thư viện chuẩn đó. Vui lòng đọc tài liệu trong pypi.org/project/pathlib2
Ian Lin

242

Điều này cố gắng để có một chút chủng tộc hơn so với các giải pháp khác. ( withTừ khóa mới trong Python 2.5.)

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

Gần như tương đương với điều này.

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

Bây giờ, để thực sự làm cho nó không có chủng tộc, bạn cần sử dụng futimesvà thay đổi dấu thời gian của tệp mở, thay vì mở tệp và sau đó thay đổi dấu thời gian trên tên tệp (có thể đã được đổi tên). Thật không may, Python dường như không cung cấp một cách để gọi futimesmà không thông qua ctypeshoặc tương tự ...


BIÊN TẬP

Theo ghi nhận của Nate Parsons , Python 3.3 sẽ thêm chỉ định một bộ mô tả tệp (khi os.supports_fd) vào các chức năng như os.utime, nó sẽ sử dụng tòa nhà futimeschọc trời thay vì tòa nhà utimesdưới mui xe. Nói cách khác:

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)

Đây là giải pháp thực sự - và đây là cách cảm ứng (1) trong coreutils thực hiện, trừ khi không có sẵn Futimes (). Futimes không phải là một chức năng di động và thậm chí không tồn tại trên các nhân Linux cũ hơn 2.6, vì vậy bạn cần phải xử lý ENOSYS và quay lại sử dụng ngay cả khi bạn sử dụng nó.
Glenn Maynard

(Lỗi đọc lại ở trên: "Điều này" = mở ("a") + tương lai.) May mắn thay, thật khó để nghĩ đến trường hợp điều kiện cuộc đua không sử dụng tương lai thực sự có vấn đề. Trường hợp "sai" mà bạn có thể kết thúc là tệp được đổi tên giữa open () và utime (), trong trường hợp đó bạn sẽ không tạo tệp mới cũng như không chạm vào tệp cũ. Điều đó có thể quan trọng, nhưng hầu hết thời gian nó sẽ không.
Glenn Maynard

Cygwin touch có thể thực hiện phép thuật của mình trên các tệp chỉ đọc, nhưng mã này không thể. Tuy nhiên, nó có vẻ hoạt động nếu tôi bao quanh nó bằng thử: <code> ngoại trừ IOError là e: (kiểm tra e.errno) os.utime (tên tệp, thời gian)
dash-tom-bang

FYI, có vẻ như Futimes đã được thêm vào trong 3.3
Nate Parsons

Lưu ý: filechức năng tích hợp đã bị xóa khỏi Python 3 và openphải được sử dụng thay thế. Tôi hoàn toàn bỏ lỡ điều này vì cú pháp tô sáng của trình soạn thảo tôi đang sử dụng (gedit) vẫn đang nhắm mục tiêu Python 2.
Bart

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

24
Có một điều kiện chủng tộc tiềm năng trong giải pháp này: Nếu tệp không tồn tại và được tạo bởi một quy trình khác trước khi chức năng này thực hiện open()cuộc gọi, thì nội dung của tệp sẽ bị cắt ngắn. Đề nghị sử dụng chế độ 'a'thay thế.
Greg Hewgill

7
Đã đồng ý. Giải pháp phù hợp chỉ là: def touch (fname): open (fname, 'wa'). Close ()
stepancheg

@Greg, trong khi nó giải quyết vấn đề điều kiện đua xe tiềm năng, open(fname, 'a').close()sẽ không thay đổi.
SilentGhost

@SilentGhost: Điều đó đúng, nhưng không sao vì nếu tệp tồn tại thì nó mới được tạo. Tất nhiên, bạn để lại cuộc gọi đến os.utime()đó cho các tập tin có sẵn.
Greg Hewgill

4
Tại sao không chỉ mở để đảm bảo nó tồn tại, sau đó gọi utime?
itadok

31

Tại sao không thử điều này?:

import os

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

Tôi tin rằng điều này giúp loại bỏ bất kỳ điều kiện chủng tộc nào quan trọng. Nếu tập tin không tồn tại thì một ngoại lệ sẽ được ném ra.

Điều kiện cuộc đua duy nhất có thể ở đây là nếu tệp được tạo trước khi open () được gọi nhưng sau os.utime (). Nhưng điều này không quan trọng bởi vì trong trường hợp này, thời gian sửa đổi sẽ như mong đợi vì nó phải xảy ra trong khi gọi để chạm ().


8

Đây là một số mã sử dụng ctypes (chỉ được thử nghiệm trên 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

Câu trả lời này tương thích với tất cả các phiên bản kể từ Python-2.5 khi từ khóa withđược phát hành.

1. Tạo tập tin nếu không tồn tại + Đặt thời gian hiện tại
(chính xác như lệnh 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

Một phiên bản mạnh mẽ hơn:

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. Chỉ cần tạo tệp nếu không tồn tại
(không cập nhật thời gian)

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

3. Chỉ cập nhật thời gian truy cập / sửa đổi tệp
(không tạo tệp nếu không tồn tại)

import os

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

Sử dụng os.path.exists()không đơn giản hóa mã:

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)

Phần thưởng: Cập nhật thời gian của tất cả các tệp trong một thư mục

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

Lỗi : with open(fn,'a'): passhoặc thay thế open(fn, 'a').close()không thay đổi thời gian đã sửa đổi bằng Python 2.7.5 trên Red Hat 7 (hệ thống tệp là XFS). Trên nền tảng của tôi, các giải pháp này chỉ tạo một tệp trống nếu không tồn tại. : - /
olibre

3

Đơn giản:

def touch(fname):
    open(fname, 'a').close()
    os.utime(fname, None)
  • Các openĐảm bảo có một tập tin có
  • những utimeđảm bảo rằng các timestamps được cập nhật

Về mặt lý thuyết, có khả năng ai đó sẽ xóa tệp sau đó open, khiến cho không thể đưa ra một ngoại lệ. Nhưng có thể cho rằng điều đó ổn, vì điều gì đó tồi tệ đã xảy ra.


1

Phức tạp (có thể là lỗi):

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)

Điều này cũng cố gắng cho phép thiết lập thời gian truy cập hoặc sửa đổi, như GNU touch.


1

Có vẻ hợp lý khi tạo một chuỗi với các biến mong muốn và chuyển nó đến os.system:

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

Điều này không đầy đủ theo một số cách (ví dụ: nó không xử lý khoảng trắng), vì vậy đừng làm điều đó.

Một phương pháp mạnh mẽ hơn là sử dụng quy trình con:

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

Mặc dù điều này tốt hơn nhiều so với việc sử dụng một lớp con (với os.system), nhưng nó vẫn chỉ phù hợp với các tập lệnh nhanh và bẩn; sử dụng câu trả lời được chấp nhận cho các chương trình đa nền tảng.


Điều này không an toàn: điều gì xảy ra khi có một khoảng trắng trong tên tệp?
ayke

5
subprocess.call(['touch', os.path.join(dirname, fileName)])là tốt hơn nhiều so với việc sử dụng một subshell (với os.system). Tuy nhiên, chỉ sử dụng điều này cho các tập lệnh nhanh và bẩn, sử dụng câu trả lời được chấp nhận cho các chương trình đa nền tảng.
ayke

1
touchkhông phải là một lệnh có sẵn đa nền tảng (ví dụ: Windows)
Mike T

1

"open (file_name, 'a'). close ()" không hoạt động với tôi trong Python 2.7 trên Windows. "os.utime (file_name, Không có)" hoạt động tốt.

Ngoài ra, tôi có nhu cầu chạm đệ quy tất cả các tệp trong một thư mục có ngày cũ hơn một số ngày. Tôi đã tạo hte sau dựa trên phản ứng rất hữu ích của 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

Tại sao bạn không thử: newfile.py

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

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

python newfile.py foobar.txt

hoặc là

sử dụng quy trình con:

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

0

Sau đây là đủ:

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

Nếu bạn muốn đặt thời gian cụ thể cho cảm ứng, hãy sử dụng os.utime như sau:

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

Ở đây, cả atime và mtime đều phải là int / float và nên bằng với thời gian epoch tính bằng giây với thời gian bạn muốn đặt.


0

Nếu bạn không phiền thì hãy thử - ngoại trừ ...

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

Mặc dù vậy, một điều cần lưu ý, nếu một tệp tồn tại cùng tên thì nó sẽ không hoạt động và sẽ thất bại trong âm thầm.


0

write_text()từ pathlib.Pathcó thể được sử dụng.

>>> from pathlib import Path
>>> Path('aa.txt').write_text("")
0
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.