在 Python 中使用 pathlib 复制文件

Copy file with pathlib in Python

我尝试使用 pathlib

复制文件
import pathlib
import shutil

my_file=pathlib.Path('/etc/hosts')
to_file=pathlib.Path('/tmp/foo')
shutil.copy(my_file, to_file)

我得到这个异常:

/home/foo_egs_d/bin/python /home/foo_egs_d/src/test-pathlib-copy.py
Traceback (most recent call last):
  File "/home/foo_egs_d/src/test-pathlib-copy.py", line 6, in <module>
    shutil.copy(my_file, to_file)
  File "/usr/lib/python2.7/shutil.py", line 117, in copy
    if os.path.isdir(dst):
  File "/home/foo_egs_d/lib/python2.7/genericpath.py", line 41, in isdir
    st = os.stat(s)
TypeError: coercing to Unicode: need string or buffer, PosixPath found

Process finished with exit code

...如何在 Python 2.7 中使用 pathlib 复制文件?

使用shutil.copy:

import pathlib
import shutil

my_file = pathlib.Path('/etc/hosts')
to_file = pathlib.Path('/tmp/foo')

shutil.copy(str(my_file), str(to_file))  # For Python <= 3.7.
shutil.copy(my_file, to_file)  # For Python 3.8+.

问题是 pathlib.Path 如果您使用 Unix/Linux 创建一个 PosixPath 对象,如果您使用 Microsoft Windows WindowsPath

对于旧版本的 Python,shutil.copy 需要一个字符串作为其参数。对于他们,请在此处使用 str 功能。

shutil.copy()不工作的原因是你没有使用最新的Python,Python3.6shutil.copy()can 处理 Path 个对象(或其子类)。对于旧版本的 Python 这会引发错误,因为 shutil 的那些实现需要 copy 的字符串参数,而不是 pathlib.Path 类型的参数。

你真正想写的是:

my_file.copy(to_file)

您可以将 Path 子类化以包含这样的方法,并适应 my_file 的创建。我发现在现有 pathlib.Path

上 graft/monkey-patch/duck-punch 它更容易
from pathlib import Path


def _copy(self, target):
    import shutil
    assert self.is_file()
    shutil.copy(str(self), str(target))  # str() only there for Python < (3, 6)

Path.copy = _copy

您可以将此代码放在任何您喜欢的地方,只要它在对任何 Path 实例调用 .copy 方法之前执行即可。 .copy() 的参数可以是文件或目录。

您可以使用 pathlib 重命名方法代替 shutil.move()

import pathlib

my_file = pathlib.Path('/etc/hosts')
to_file = pathlib.Path('/tmp/foo')
my_file.rename(to_file)

从 Python 3.5 开始,无需导入 shutil,您可以:

from pathlib import Path

dest = Path('dest')
src = Path('src')
dest.write_bytes(src.read_bytes()) #for binary files
dest.write_text(src.read_text()) #for text files

对于 Python 2.7,pathlib2 提供了 read_bytesread_textwrite_byteswrite_text 方法。

文件会加载到内存中,所以这种方法不适合大于机器可用内存的文件。

根据评论,可以使用 write_bytesread_bytes 来复制文本文件,但是如果您需要在复制时处理编码 write_textread_text 展示两个额外参数的优势:

  • encoding是用于解码或编码文件的编码名称
  • errors 是一个可选字符串,指定如何处理编码和解码错误

它们的含义与open()相同。

如何在 Python 3.6

中将 shutil 转换为接受 pathlib.Path 个对象

所述,Python 3.6 中的 shutil 可以接收 pathlib.Path 个对象。

因为这感觉很神奇,所以我决定稍微调查一下它是如何实现的,看看我是否能够自己重用这个魔法 类。

改进是 PEP 519 的结果。

这概括了许多 stdlib 功能,因此文档没有持续更新,包括从 3.7 only documents support in a single function 开始的大部分 shutil。欢迎体验动态类型的乐趣。

在记录的地方,stlib 链接到 glossary for "path-like objects"

An object representing a file system path. A path-like object is either a str or bytes object representing a path, or an object implementing the os.PathLike protocol. An object that supports the os.PathLike protocol can be converted to a str or bytes file system path by calling the os.fspath() function; os.fsdecode() and os.fsencode() can be used to guarantee a str or bytes result instead, respectively. Introduced by PEP 519.

然后链接到 os.PathLike 的文档:

An abstract base class for objects representing a file system path, e.g. pathlib.PurePath.

New in version 3.6.

abstractmethod __fspath__()

Return the file system path representation of the object.

The method should only return a str or bytes object, with the preference being for str.

关键实现提交似乎是:

如果你想实现你自己的类路径类,你可以这样做:

#!/usr/bin/env python3

class MyPath:
    def __init__(self, path):
        self.path = path
    def __fspath__(self):
        return self.path

with open(MyPath('f'), 'w'):
    pass

在 Python 3.6.7、Ubuntu 18.10 中测试。

您可以使用 pathlib3x - 它提供了最新的向后移植(在撰写此答案的日期 Python 3.11.a0)Python Python 3.6 或更新版本的 pathlib,以及一些附加功能,例如 copycopy2 等...

$> python -m pip install pathlib3x
$> python
>>> import pathlib3x as pathlib
>>> my_file = pathlib.Path('/etc/hosts')
>>> to_file = pathlib.Path('/tmp/foo')
>>> my_file.copy(to_file)

您可以在 github or PyPi

上找到它

免责声明:我是 pathlib3x 库的作者。