Скопировать файл с помощью pathlib в 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
... как скопировать файл с помощью pathlib в Python 2.7?
Ответы
Ответ 1
Так что по этому поводу?
import pathlib
import shutil
my_file = pathlib.Path('/etc/hosts')
to_file = pathlib.Path('/tmp/foo')
shutil.copy(str(my_file), str(to_file))
Проблема в том, что pathlib.Path
создайте объект PosixPath
, если вы используете Unix/Linux, WindowsPath
, если вы используете Microsoft Windows.
Но shutil.copy()
принимает строку в качестве аргумента. Так что просто используйте функцию str()
здесь, когда вы используете функцию str()
для объекта Path
, он вернет путь, который объект Path
называет строкой.
Ответ 2
Причина для 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
Вы можете поместить этот код в любом месте, пока он выполняется, до вызова метода .copy
в любом из экземпляров Path
. Аргумент .copy()
может быть файлом или каталогом.
Ответ 3
Начиная с 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_bytes
, read_text
, write_bytes
и write_text
.
Файл будет загружен в память, поэтому этот метод не подходит для файлов, размер которых превышает доступную для машин память.
Согласно комментариям, можно использовать write_bytes
и read_bytes
для копирования текстовых файлов, но если вам нужно иметь дело с кодировкой во время копирования write_text
, read_text
предоставляет преимущество двух дополнительных параметров:
-
encoding
- это имя кодировки, используемой для декодирования или кодирования файла. -
errors
- это необязательная строка, которая определяет, как должны обрабатываться ошибки кодирования и декодирования.
Они оба имеют то же значение, что и в open()
.
Ответ 4
Как shutil
был преобразован для принятия pathlib.Path
объектов в Python 3.6
Как упоминалось в fooobar.com/questions/417004/..., shutil в Python 3.6 может принимать 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, может быть преобразован в путь файловой системы str или bytes путем вызова функции os.fspath(); os.fsdecode() и os.fsencode() могут использоваться для гарантии результата str или bytes, соответственно. Представлено PEP 519.
а затем ссылки на документацию os.PathLike
: https://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
Протестировано в Python 3.6.7, Ubuntu 18.10.
Ответ 5
Вы можете использовать метод переименования pathlib вместо shutil.move().
import pathlib
my_file = pathlib.Path('/etc/hosts')
to_file = pathlib.Path('/tmp/foo')
my_file.rename(to_file)