Python: Cómo mover un archivo con un nombre de archivo Unicode a una carpeta Unicode

Estoy teniendo un infierno con mover un archivo con nombre Unicode entre carpetas con nombre Unicode en un script Python en Windows …

¿Qué syntax usaría para encontrar todos los archivos de tipo * .ext en una carpeta y moverlos a una ubicación relativa?

Supongamos que los archivos y carpetas son unicode.

El problema básico es la mezcla no convertida entre Unicode y cadenas de bytes. Las soluciones pueden ser convertir a un solo formato o evitar los problemas utilizando algunos trucos. Todas mis soluciones incluyen la biblioteca estándar glob y shutil .

Por ejemplo, tengo algunos nombres de archivo de Unicode que terminan con ods , y quiero moverlos al subdirectorio llamado א (hebreo Aleph, un carácter de unicode).

Primera solución – expresa el nombre del directorio como una cadena de bytes:

 >>> import glob >>> import shutil >>> files=glob.glob('*.ods') # List of Byte string file names >>> for file in files: ... shutil.copy2(file, 'א') # Byte string directory name ... 

Segunda solución: convierte los nombres de archivo a Unicode:

 >>> import glob >>> import shutil >>> files=glob.glob(u'*.ods') # List of Unicode file names >>> for file in files: ... shutil.copy2(file, u'א') # Unicode directory name 

Crédito a Ezio Melotti, lista de errores de Python .

Tercera solución: evitar el nombre de directorio Unicode de destino

Aunque esta no es la mejor solución en mi opinión, hay un buen truco aquí que vale la pena mencionar.

Cambie su directorio al directorio de destino usando os.getcwd() , y luego copie los archivos en él refiriéndose a él como . :

 # -*- coding: utf-8 -*- import os import shutil import glob os.chdir('א') # CD to the destination Unicode directory print os.getcwd() # DEBUG: Make sure you're in the right place files=glob.glob('../*.ods') # List of Byte string file names for file in files: shutil.copy2(file, '.') # Copy each file # Don't forget to go back to the original directory here, if it matters 

Explicación más profunda

El enfoque directo shutil.copy2(src, dest) falla porque shutil concatena un unicode con una cadena ASCII sin conversiones:

 >>> files=glob.glob('*.ods') >>> for file in files: ... shutil.copy2(file, u'א') ... Traceback (most recent call last): File "", line 2, in  File "/usr/lib/python2.6/shutil.py", line 98, in copy2 dst = os.path.join(dst, os.path.basename(src)) File "/usr/lib/python2.6/posixpath.py", line 70, in join path += '/' + b UnicodeDecodeError: 'ascii' codec can't decode byte 0xd7 in position 1: ordinal not in range(128) 

Como se vio antes, esto puede evitarse cuando se usa 'א' lugar de Unicode u'א'

Es esto un error?

En mi opinión, esto es un error, porque Python no puede esperar que sus nombres se basedir siempre en str , no en unicode . He reportado esto como un problema en la lista de errores de Python , y estoy esperando respuestas.

Otras lecturas

CÓMO oficial de Python en Unicode

Utilice la cadena de Unicode en todas partes:

 # -*- coding: utf-8 -*- # source code ^^ encoding; it might be different from sys.getfilesystemencoding() import glob import os srcdir = u'مصدر الدليل' # <-- unicode string dstdir = os.path.join('..', u'κατάλογο προορισμού') # relative path for path in glob.glob(os.path.join(srcdir, u'*.ext')): newpath = os.path.join(dstdir, os.path.basename(path)) os.rename(path, newpath) # move file or directory; assume the same filesystem 

Hay muchos detalles sutiles en los archivos en movimiento; Ver las funciones de shutit.copy* . Podría usar uno que sea apropiado en su caso particular y eliminar los archivos de origen en caso de éxito, por ejemplo, a través de os.remove() .