在 Python 中使用 pathlib 复制文件

我尝试用 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 复制文件?

103361 次浏览

使用 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+.

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

对于旧版本的 Python,shutil.copy需要一个字符串作为参数。

shutil.copy()无法工作的原因是您没有使用最新的 Python,Python 3.6 shutil.copy() 可以处理 Path对象(或其子类)。对于旧版本的 Python,这会抛出一个错误,因为那些 shutil实现期望的是 copy的字符串参数,而不是 pathlib.Path类型参数。

你真正想写的是:

my_file.copy(to_file)

您可以通过子类 Path 来包含这样的方法,并适应 my_file的创建。我发现在现有的 pathlib.Path上移植/猴子贴片/鸭子打孔更容易

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_text一个 read_text提供了两个额外参数的优点:

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

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

如何在 Python 3.6中将 shutil转换为接受 pathlib.Path对象

正如在 在这个答案中中提到的,Python 3.6中的 shutil 可以使用 pathlib.Path对象。

由于这感觉相当神奇,我决定稍微研究一下它是如何实现的,看看我是否能够在我自己的类上重用这种神奇。

这种改善是 PEP 519的结果。

这扩展了许多 stdlib 功能,结果导致文档没有得到一致的更新,包括 shutil的大部分内容(截至3.7 只支持单个函数中的文档)。欢迎来到动态类型的乐趣。

在文档中,stlib 链接到 “类路径对象”的术语表

表示文件系统路径的对象。类路径对象是表示路径的 str 对象或字节对象,或者是实现操作系统的对象。路径协议。支持操作系统的对象。PathLike 协议可以通过调用 os.fspath ()函数转换为 str 或字节文件系统路径; os.fsdecode ()和 os.fsencode ()可以分别用于保证 str 或字节结果。由 PEP 519引入。

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

表示文件系统路径的对象的抽象基类,例如 pathlib.PurePath。

3.6版本新增。

abstractmethod __fspath__()

返回对象的文件系统路径表示形式。

该方法应该只返回一个 str 或字节对象,首选项为 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 3.6或更新版本的 Python 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派派上找到它


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