Copie el archivo con pathlib en Python

2 minutos de lectura

avatar de usuario
Guettli

Intento copiar un archivo con pathlib

import pathlib
import shutil

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

Obtengo esta excepción:

/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

… ¿cómo copiar un archivo con pathlib en Python 2.7?

  • Esto funciona sin arrojar un error en Python 3.6

    – Antonio

    3 mayo 2017 a las 10:14

  • @Anthon usamos Python 2.7.

    – Guettli

    30 de octubre de 2017 a las 9:27

avatar de usuario
Remi Guan

Usar 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+.

El problema es pathlib.Path crear un PosixPath objeto si está usando Unix/Linux, WindowsPath si está utilizando Microsoft Windows.

Con versiones anteriores de Python, shutil.copy requiere una cadena como sus argumentos. Para ellos, utilice el str función aquí.

  • No lo tome como algo personal: pensé que pathlib se hizo para facilitar las cosas. Supongo que me quedo con el uso de cadenas viejas y sencillas como solía hacer.

    – Guettli

    13 de noviembre de 2015 a las 14:37

  • También habría esperado que Pathlib pudiera copiar un archivo, dado que puede mover/renombrar y desvincular/eliminar archivos.

    – Andrés Wagner

    4 de julio de 2016 a las 12:48

  • @AndrewWagner, la diferencia, si tuviera que adivinar, es que mover y eliminar archivos son operaciones puramente del sistema de archivos, donde solo actualiza los metadatos del sistema de archivos. Copiar implica en realidad escribir nuevos datos, por lo que tal vez la gente de pathlib pensó que estaba fuera de alcance.

    – Tim M.

    19 de junio de 2019 a las 12:00

  • Si alguien se pregunta por qué shutil.move no funciona de la misma manera en Python

    – SwimBikeRun

    16 de junio de 2020 a las 3:53


  • Para información: “Python más antiguo” significa Python 3.7, “Python más nuevo” es Python 3.8 y superior.

    – ac

    31 de mayo de 2021 a las 7:38

avatar de usuario
Antonio

la causa de shutil.copy() no funciona es que no estás usando la última versión de Python, Python 3.6 shutil.copy() pueden resolver Path objetos (o subclases de los mismos). Que para versiones anteriores de Python esto arroje un error se debe a que esas implementaciones de shutil esperar argumentos de cadena para copyy no pathlib.Path argumentos de tipo.

Lo que realmente quieres poder escribir es:

my_file.copy(to_file)

Puede crear una subclase de Path para incluir dicho método y adaptar la creación de my_file. Me resulta más fácil simplemente injertar/parchear/golpear en el existente 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

Puede colocar este código en cualquier lugar que desee, siempre que se ejecute antes de llamar al .copy método en cualquiera de los Path instancias. el argumento a .copy() puede ser un archivo o un directorio.

  • AFAIK esto se llama Monkey-Patching. ¿Por qué pathlib no proporciona esto?

    – Guettli

    1 de noviembre de 2016 a las 15:37

  • Diría que pathlib no proporciona esta funcionalidad porque no es para lo que está destinada, al igual que os.path no fue diseñado para el manejo de archivos en sí. La funcionalidad del módulo es sobre el manejo de archivos y los metadatos del archivo, pero no sobre el manejo de archivos, hasta donde yo sé.

    –Bram Vanroy

    1 oct 2018 a las 9:00

  • @mr.zog No creo que su público objetivo reciba una notificación de que escribió un comentario cuando acaba de poner un nombre. Debe consultar la ayuda sobre el formato de los comentarios donde se indica claramente que debe usar el @ personaje

    – Antonio

    22 de marzo de 2019 a las 19:49

  • @Bram Vanroy “La funcionalidad del módulo trata sobre el manejo de archivos y los metadatos del archivo, pero no sobre el manejo de archivos” es un poco contradictorio. ¿Qué pretendías transmitir?

    – mr.zog

    22 de marzo de 2019 a las 20:06

  • Aunque Path está diseñado principalmente para representar la ruta de un archivo, también proporciona mkdir() y exist() y demás, por lo que es natural esperar que haga mucho de lo que hace shutil. Una separación adecuada de preocupaciones probablemente tendría Ruta, Archivo y Carpeta con Archivo/Carpeta creados a partir de una Ruta y Archivo tiene getPath(), etc. Luego, una vez que tenga un Archivo o Carpeta, es bastante obvio que tiene sentido tener copia(), copytree() etc. en esos objetos en lugar de en Path. Uso Path en todas partes que puedo, por cierto.

    – Óliver

    7 de noviembre de 2019 a las 15:11


avatar de usuario
jacques gaudin

Desde Python 3.5, sin importar shutiltu puedes hacer:

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

Para Python 2.7, pathlib2 proporciona el read_bytes, read_text, write_bytes y write_text métodos.

El archivo se cargará en la memoria, por lo que este método no es adecuado para archivos más grandes que la memoria disponible de la máquina.

Según los comentarios, uno puede usar write_bytes y read_bytes para copiar archivos de texto, pero si necesita lidiar con la codificación en el momento de la copia write_text un read_text presentan la ventaja de dos parámetros adicionales:

  • encoding es el nombre de la codificación utilizada para decodificar o codificar el archivo
  • errors es una cadena opcional que especifica cómo se deben manejar los errores de codificación y decodificación

Ambos tienen el mismo significado que en open().

  • ¿Hay alguna manera de hacer esto con Python 2.7?

    – Guettli

    27 de octubre de 2017 a las 7:37

  • Hay algo para Python 2.7, a saber pathlib2 pero no lo he probado. pypi.python.org/pypi/pathlib2. los read_bytes y write_bytes los métodos están en el código fuente, así que supongo que funcionan.

    – Jacques Gaudin

    27/10/2017 a las 15:41


  • @GeorgeSovetov Gracias, lo agregué a la respuesta.

    – Jacques Gaudin

    17 de enero de 2018 a las 14:23

  • Con este método, un archivo lo suficientemente grande bloquearía Python con un MemoryError. shutil.copy no tiene este problema porque usa shutil.copyfileobj que almacena archivos más grandes en fragmentos más pequeños.

    –Steven Rumbalski

    27/03/2018 a las 20:31


  • Esto copia el archivo contenidopero no permisos de archivos, propiedad, políticas de acceso u otros archivos. metadatos. El comentario de OP en realidad dice que quiere “copiar el archivo”, no solo los datos que contiene.

    – patrick-mooney

    10 oct 2019 a las 16:29

avatar de usuario
Ciro Santilli Путлер Капут 六四事

Cómo shutil se convirtió para aceptar pathlib.Path objetos en Python 3.6

Como se menciona en esta respuesta, shutil en Python 3.6 puede tomar pathlib.Path objetos.

Como esto se sentía bastante mágico, decidí investigar un poco cómo se implementó para ver si podría reutilizar esta magia en mis propias clases.

La mejora fue el resultado de PEP 519.

Esto generalizó una gran cantidad de funciones de stdlib y, como resultado, la documentación no se actualizó constantemente, incluida la mayoría de shutil que a partir de 3.7 solo soporte de documentos en una sola función. Bienvenido a los placeres de la escritura dinámica.

Donde esté documentado, el stlib enlaza con el glosario de “objetos similares a caminos”.

Un objeto que representa una ruta del sistema de archivos. Un objeto similar a una ruta es un objeto str o bytes que representa una ruta, o un objeto que implementa el protocolo os.PathLike. Un objeto que admita el protocolo os.PathLike se puede convertir en una ruta del sistema de archivos str o bytes llamando a la función os.fspath(); os.fsdecode() y os.fsencode() se pueden usar para garantizar un resultado de str o bytes, respectivamente. Introducido por PEP 519.

y que luego enlaza con la documentación de os.PathLike:

Una clase base abstracta para objetos que representan una ruta del sistema de archivos, por ejemplo, pathlib.PurePath.

Nuevo en la versión 3.6.

abstractmethod __fspath__()

Devuelve la representación de ruta del sistema de archivos del objeto.

El método solo debe devolver un objeto str o bytes, con preferencia por str.

Los compromisos de implementación clave parecen ser:

Si desea implementar sus propias clases similares a rutas, puede hacerlo así:

#!/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

Probado en Python 3.6.7, Ubuntu 18.10.

avatar de usuario
bitranox

Puede usar pathlib3x: ofrece un backport del último (a la fecha de escribir esta respuesta Python 3.11.a0) Python pathlib para Python 3.6 o posterior, y algunas funciones adicionales como copy, copy2etc …

$> 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)

puedes encontrarlo en github o PyPi


Descargo de responsabilidad: soy el autor de la biblioteca pathlib3x.

avatar de usuario
Neurona

Puedes usar pathlib cambiar el nombre del método en lugar de shutil.move().

import pathlib

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

¿Ha sido útil esta solución?