使用Python中的pathlib复制文件

gue*_*tli 43 python copy file python-2.x pathlib

我尝试复制一个文件 pathlib

import pathlib
import shutil

my_file=pathlib.Path('/etc/hosts')
to_file=pathlib.Path('/tmp/foo')
shutil.copy(my_file, to_file)
Run Code Online (Sandbox Code Playgroud)

我得到这个例外:

/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
Run Code Online (Sandbox Code Playgroud)

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

Kev*_*uan 39

那么这个怎么样?

import pathlib
import shutil

my_file = pathlib.Path('/etc/hosts')
to_file = pathlib.Path('/tmp/foo')
shutil.copy(str(my_file), str(to_file))
Run Code Online (Sandbox Code Playgroud)

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

shutil.copy()需要字符串作为参数.所以只需str()在这里使用,当你str()Path对象上使用函数时,它将返回原始路径.

  • 我也希望Pathlib能够复制文件,因为它可以移动/重命名和取消链接/删除文件. (8认同)
  • 如果有人想知道为什么 Shutil.move 在 Python&lt;3.9 中的工作方式不同,根据我的贡献,这个问题已在 Python3.9 中修复:D (7认同)
  • 不要把这个用于个人:我虽然使用了pathlib来使事情变得更容易.我想我坚持使用像以前一样的普通旧字符串. (5认同)
  • @AndrewWagner 如果我不得不猜测,区别在于移动和删除文件纯粹是文件系统操作,您只需更新文件系统元数据。复制实际上涉及写出新数据,所以也许 pathlib 的人认为它超出了范围。 (4认同)
  • 信息:“旧版 Python”指的是 Python 3.7,“新版 Python”指的是 Python 3.8 及更高版本。 (3认同)

Ant*_*hon 25

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

你真正想要写的是:

my_file.copy(to_file)
Run Code Online (Sandbox Code Playgroud)

您可以将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
Run Code Online (Sandbox Code Playgroud)

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

  • AFAIK这叫做Monkey-Patching.为什么pathlib不提供此功能? (7认同)
  • 我想说pathlib不提供此功能,因为这不是它的含义-正如`os.path'并不意味着文件处理本身一样。据我所知,该模块的功能与文件处理和文件的元数据有关,但与文件处理无关。 (4认同)
  • @Bram Vanroy “该模块的功能与文件处理和文件的元数据有关,但与文件处理无关”有点矛盾。你想传达什么? (3认同)
  • 虽然 Path 主要是为了表示文件路径而设计的,但它也提供了 mkdir() 和 Exists() 等功能,因此很自然地期望它能完成 Shutil 所做的很多事情。适当的关注点分离可能会有路径、文件和文件夹,其中文件/文件夹是从路径创建的,文件有 getPath() 等。那么一旦你有了一个文件或文件夹,很明显有 copy() 是有意义的, copytree() 等在这些对象上而不是在路径上。顺便说一句,我尽可能使用 Path。 (3认同)
  • @mr.zog 我认为您的目标受众不会在您输入姓名时收到您写评论的通知。您应该查阅 [关于注释格式的帮助](https://stackoverflow.com/editing-help#comment-formatting),其中明确指出使用 `@` 字符 (2认同)

Jac*_*din 17

从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
Run Code Online (Sandbox Code Playgroud)

对于Python 2.7,pathlib2提供read_bytes,read_text,write_byteswrite_text方法.

该文件将被加载到内存中,因此该方法不适用于大于机器可用内存的文件.

按照该意见,可以使用write_bytesread_bytes复制文本文件,但如果你需要处理的复印时间编码write_textread_text存在的两个额外的参数的优势:

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

它们都具有相同的含义open().

  • 这会复制文件的_内容_,但不会复制文件权限、所有权、访问策略或其他文件_元数据_。OP 的评论实际上是说她/他想要“复制文件”,而不仅仅是它包含的数据。 (8认同)
  • 使用这种方法,一个足够大的文件会导致 Python 崩溃并出现“MemoryError”。`shutil.copy` 没有这个问题,因为它使用 `shutil.copyfileobj` 将较大的文件缓冲成较小的块。 (3认同)
  • Python 2.7有一些东西,即“ pathlib2”,但是我还没有尝试过。https://pypi.python.org/pypi/pathlib2/。`read_bytes`和`write_bytes`方法在源代码中,因此我认为它们可以工作。 (2认同)

bit*_*nox 9

您可以使用 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)
Run Code Online (Sandbox Code Playgroud)

你可以在githubPyPi上找到它


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


Cir*_*四事件 8

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

/sf/answers/2822335001/所述,Python 3.6中的shutdownil可以接收pathlib.Path对象。

由于这感觉很神奇,因此我决定研究一下它是如何实现的,以查看是否可以在自己的类中重用此魔术。

改进是PEP 519的结果:https : //www.python.org/dev/peps/pep-0519/

这概括了很多stdlib功能,结果并没有持续更新文档,包括shutil从3.7开始的大多数文档仅文档支持单个功能。欢迎来到动态打字的乐趣。

在有文档记录的地方,stlib链接到“类路径对象”的词汇表:https ://docs.python.org/3/glossary.html#term-path-like-object

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

然后链接到以下文档的文档os.PathLikehttps : //docs.python.org/3/glossary.html#term-path-like-object

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

3.6版的新功能。

abstractmethod __fspath__()

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

该方法应仅返回str或bytes对象,首选项为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
Run Code Online (Sandbox Code Playgroud)

已在Ubuntu 3.10,Python 3.6.7中测试。