2010-04-07 18 views
9

Estoy intentando ejecutar subprocess.call() con el nombre de archivo Unicode, y aquí se simplifica:problema Unicode nombre de archivo para subprocess.call pitón()

n = u'c:\\windows\\notepad.exe ' 
f = u'c:\\temp\\nèw.txt' 

subprocess.call(n + f) 

que eleva famoso error:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe8'

La codificación de utf-8 produce el nombre de archivo incorrecto, y mbcs pasa el nombre de archivo como new.txt sin acento

No puedo leer más sobre este tema confuso y giró en círculo. He encontrado aquí muchas respuestas para muchos problemas diferentes en el pasado, así que pensé para unirse y pedir ayuda a mí mismo

Gracias

+0

Dependiendo de su sistema operativo, ¿qué ocurre si usa latin-1 o cp1252 como su codificación? –

+1

¿Ha especificado la codificación del archivo fuente? –

+0

el archivo fuente está codificado en utf: # - * - codificación: utf-8 - * - Utilizo el truco con latin-1 de vez en cuando pero no puedo en este caso: 1. También necesito otros caracteres que no están en latin-1 2. Desafortunadamente no funciona con el subproceso - el mismo error se produce, codifiqué ambas cadenas con la misma codificación de latin-1 Gracias por todas las respuestas – otrov

Respuesta

0

no tengo una respuesta para usted, pero he hecho una buena cantidad de investigación sobre este problema Python convierte todos los resultados (incluidas las llamadas al sistema) en el mismo carácter que el terminal en el que se ejecuta. Los terminales de Windows usan páginas de códigos para el mapeo de caracteres; la página de códigos predeterminada es 437, pero se puede cambiar con el comando chcp. chcp 65001 teóricamente cambiará la página de códigos a utf-8, pero hasta donde sé Python no sabe qué hacer con esto, por lo que eres SOL.

1

Parece que para hacer esto funcione, el código de subproceso tendría que modificarse para usar una versión de carácter ancho de CreateProcess (suponiendo que exista). Hay un PEP que analiza el mismo cambio realizado para el objeto de archivo en http://www.python.org/dev/peps/pep-0277/. Quizás podría investigar las llamadas de Windows C y proponer un cambio similar para el subproceso.

+0

I no se siente a la altura de la tarea de investigar sobre este problema, es gracioso ver que es autor (Neil), que acaba de lanzar SciTE 2.10 con soporte para acceso de nombre de archivo Unicode (ancho de char) – otrov

0

Puede intente abrir el archivo como:

subprocess.call((n + f).encode("cp437")) 

o cualquier página de códigos chcp informes que se utilizan en una ventana de símbolo del sistema. Si intentas chcp 65001 como Starbuck sugirió, tendrás que editar el archivo stdlib coddings \ aliases.py y agregar cp65001 como un alias a 'utf-8' de antemano. Es un problema abierto en la fuente de Python.

ACTUALIZACIÓN: dado que este es un escenario de destino múltiple, antes de ejecutar dicho comando, asegúrese primero de ejecutar un solo comando chcp, analice la salida y recupere la página de códigos de "Símbolo del sistema" (DOS) actual. Posteriormente, use la página de códigos descubierta para codificar el argumento subprocess.call.

+0

Estoy en cp1251, pero el programa es se supone que se ejecuta en diferentes máquinas con configuración regional arbitraria – otrov

+0

cp1251 es la página de códigos de Windows. Al ejecutar comandos con subproceso, debe utilizar la página de códigos del "DOS"/símbolo del sistema. – tzot

+0

@tzot: es incorrecto a menos que se refiera a la codificación 'mbcs' (puede ver su valor usando' locale.getpreferredencoding() ') y OP ya dijo que' mbcs' en su sistema no admite los caracteres requeridos.'chcp' puede devolver una codificación diferente. – jfs

0

Como se mencionó ΤΖΩΤΖΙΟΥ y starbuck, el problema está en la página de códigos de la consola que está en su caso 866 (en la localización rusa de ventanas) y no en 1251. Simplemente ejecute chcp en la consola.

El problema es el mismo que cuando desea generar unicode a la consola de Windows. Desafortunadamente, necesitará al menos volver a necesitar alias para unicode como 'cp866' en codificaciones \ aliases.py (o hacerlo programáticamente en el inicio del script) y cambiar la página de códigos de la consola a 65001 antes de ejecutar el bloc de notas y volver a configurarlo después .

chcp 65001 & c:\WINDOWS\notepad.exe nèw.txt & chcp 866 

Por cierto, para ser capaz de ejecutar el comando en la consola y ver el nombre de archivo correctamente, tendrá que cambiar la fuente de la consola a Lucida Console en propiedades de la ventana de la consola.

Podría ser aún peor: tendrá que cambiar la página de códigos del proceso actual. Para hacer eso, necesitará ejecutar chcp 65001 justo antes del inicio del script o usar pywin32 para hacerlo dentro del script.

+0

Gracias por todos los esfuerzos chicos, muy apreciado :) Lamentablemente no puedo hacerlo funcionar. Cadena pasada a subproceso(), o más precisamente CreateProcess() se imprime como "chcp 65001 & c: \ windows \ notepad.exe nèw.txt" que arroja el error "el sistema no puede encontrar el archivo especificado". Tal vez lo estoy haciendo mal, pero probé lo que entiendo No tengo problemas para pegar el nombre de archivo unicode en la consola de Windows en mi CP actual, que se puede ver aquí: http://img402.imageshack.us/img402/ 9875/sshot1x.png – otrov

6

Si su archivo existe, puede usar short filename (también conocido como 8.3 nombre). Este nombre se define para los archivos existentes, y no debe causar ningún problema a los programas no compatibles con Unicode cuando se pasa como argumento.

Una manera de obtener una (Pywin32 necesita para ser instalado):

import win32api 
short_path = win32api.GetShortPathName(unicode_path) 

Como alternativa, también se puede utilizar ctypes:

import ctypes 
import ctypes.wintypes 

ctypes.windll.kernel32.GetShortPathNameW.argtypes = [ 
    ctypes.wintypes.LPCWSTR, # lpszLongPath 
    ctypes.wintypes.LPWSTR, # lpszShortPath 
    ctypes.wintypes.DWORD # cchBuffer 
] 
ctypes.windll.kernel32.GetShortPathNameW.restype = ctypes.wintypes.DWORD 

buf = ctypes.create_unicode_buffer(1024) # adjust buffer size, if necessary 
ctypes.windll.kernel32.GetShortPathNameW(unicode_path, buf, len(buf)) 

short_path = buf.value 
+2

jeje, eso es absolutamente repugnante! práctico, sin embargo. – jambox

0

Uso os.startfile con la operación de edición. Esto funcionará mejor, ya que abrirá la aplicación predeterminada para su extensión.

6

Encontré una buena solución, es un poco complicada, pero funciona.

subprocess.call va a pasar el texto en su propia codificación al terminal, que puede ser o no el que está esperando. Como desea hacerlo portátil, deberá conocer la codificación de la máquina en tiempo de ejecución.

La siguiente

notepad = 'C://Notepad.exe' 
subprocess.call([notepad.encode(sys.getfilesystemencoding())]) 

intentos de averiguar la codificación actual y por lo tanto se aplica a la correcta subprocess.call

Como anotación al margen, también he descubierto que si se intenta componer una cadena con el directorio actual, usando

os.cwd() 

Python (o el sistema operativo, no lo sé) estropeará los directorios con caracteres acentuados. Para evitar esto, he encontrado lo siguiente para trabajar:

os.cwd().decode(sys.getfilesystemencoding()) 

Que es muy similar a la solución anterior.

Espero que ayude.

+0

OP dice: * "mbcs pasa el nombre de archivo como new.txt sin acento" *. 'mbcs' es' sys.getfilesystemencoding() 'en Windows, es decir,' .encode (sys.getfilesystemencoding()) 'no funciona en este caso. – jfs

+0

@ J.F.Sebastian no vemos el mismo OP;) El archivo 'nèw.txt' está con acentos. – Kpym

+0

@Kpym: es una cita directa de la pregunta que significa que la codificación de un nombre Unicode con acento ('nèw.txt') usando la página de códigos ANSI de Windows (' mbcs') puede perder el acento en el sistema OP, por ejemplo, 'u 'nèw.txt'.encode (' ascii ',' ignorar ') '->' b'new.txt'' (la página de códigos actual no es ascii) – jfs

Cuestiones relacionadas