2009-12-04 11 views
5

¿Existe una forma simple de obtener la ruta "real" que distingue entre mayúsculas y minúsculas de una ruta en minúsculas? Al revés de os.path.normcase.Invertir de os.path.normcase en Windows

Por ejemplo, considere el directorio:

c:\StackOverFlow 

si tengo el siguiente fragmento, de cómo obtener d_real?

>>> import os 
>>> d = os.path.normcase('C:\\StackOverFlow') # convert to lower case 
>>> d 
'c:\\stackoverflow' 
>>> d_real = ... # should give 'C:\StackOverFlow' with the correct case 
+0

'os.path.join ('c:', 'stackoverflow')' 'le da c: stackoverflow', * no *' c: \ stackoverflow', como se explica en la documentación (= ruta relativa al directorio actual en la unidad especificada). –

+0

Sí, no revisé mi código de ejemplo. Lo arreglaré. Gracias. – pkit

Respuesta

0

enfoque truco sucio,

import glob 
... 
if os.path.exists(d): 
    d_real = glob.glob(d + '*')[0][:len(d)] 
+0

glob.glob (d + '*') devuelve una lista vacía en Windows (al menos para mí) – jhwist

+0

@jhwist, lo probé en Windows y funciona. ¿Qué usaste para 'd'? –

+0

Hmmm, podría ser una mezcla de rutas de estilo cygwin, mi 'd =" c:/existing_file "' – jhwist

1

no consideraría esta solución sencilla, pero lo que usted puede decir:

import os 
d = os.path.normcase('C:\\StackOverFlow') 
files = os.listdir(os.path.dirname(d)) 
for f in files: 
    if not d.endswith(f.lower()): 
    continue 
    else 
    real_d = os.path.join(os.path.dirname(d), f) 

Probablemente no sea eficiente (dependiendo la cantidad de archivos en el directorio). Es necesario ajustar los componentes del camino (mi solución realmente solo corrige el caso del nombre del archivo y no le importan los nombres del directorio). Además, tal vez os.walk podría ser útil para recorrer el árbol.

-1

Definitivamente feo, pero divertido:

def getRealDirPath(path): 
    try: 
     open(path) 
    except IOError, e: 
     return str(e).split("'")[-2] 

Por supuesto:

  • funciona sólo con directorios
  • va a tener errores si dir no puede ser abierta por otra razón

Pero aún puede ser útil si no lo necesita para el tipo de código de "vida o muerte".

Probé a grep la lib estándar para encontrar cómo encontraron la ruta real pero no pudieron encontrarla. Debe estar en C.

Ese era el truco sucio del día, la próxima vez vamos a utilizar una expresión regular en la StackTrace sólo porque podemos :-)

+0

No funciona ... – schlamar

0

Usted puede hacer esto por el encadenamiento de GetShortPathName y GetLongPathName. En teoría, esto no puede funcionar porque puede deshabilitar nombres de archivos cortos en Windows con alguna configuración. He aquí algunos ejemplos de código utilizando ctypes:

def normcase(path): 
    import ctypes 
    GetShortPathName = ctypes.windll.kernel32.GetShortPathNameA 
    GetLongPathName = ctypes.windll.kernel32.GetLongPathNameA 
    # First convert path to a short path 
    short_length = GetShortPathName(path, None, 0) 
    if short_length == 0: 
     return path 
    short_buf = ctypes.create_string_buffer(short_length) 
    GetShortPathName(path, short_buf, short_length) 
    # Next convert the short path back to a long path 
    long_length = GetLongPathName(short_buf, None, 0) 
    long_buf = ctypes.create_string_buffer(long_length) 
    GetLongPathName(short_buf, long_buf, long_length) 
    return long_buf.value 
+0

Esto funciona de maravilla, EXCEPTO que el disco o el componente de red de una ruta todavía puede ser un caso arbitrario. Me pareció útil agregar 'parts = os.path.splitdrive (os.path.normcase (path))' 'path = parts [0] .upper() + parts [1]' al comienzo de la función para que tuviera letras mayúsculas y minúsculas. – garlon4

+0

Nota: Para esta solución dependiente del sistema de archivos primero compruebe si ** generación de nombre de archivo ** está desactivada en volúmenes de Windows ('fsutil.exe 8dot3name consulta C:'), que mientras tanto se recomienda para el rendimiento a menos que las aplicaciones de 16 bits todavía estén festejando. – kxr

1

utilizando sólo lib estándar, éste funciona en todas trayectoria partes/subdirectorios (excepto letra de la unidad):

def casedpath(path): 
    r = glob.glob(re.sub(r'([^:/\\])(?=[/\\]|$)', r'[\1]', path)) 
    return r and r[0] or path 

Y éste maneja rutas UNC, además:

def casedpath_unc(path): 
    unc, p = os.path.splitunc(path) 
    r = glob.glob(unc + re.sub(r'([^:/\\])(?=[/\\]|$)', r'[\1]', p)) 
    return r and r[0] or path 
+0

@Alecz, los archivos son el caso de uso principal. No se puede reproducir el problema. ¿Ejemplo? Conocido: no mayúscula una posible letra de unidad (y el nombre del servicio UNC); no convierte barra inclinada -> barra invertida. no hace nada en los archivos/directorios que en realidad no existen ahora (existe solo una ruta parcial). O quizás usó una ruta de prueba con falsa barra invertida fallando/faltando o faltando el prefijo de cadena sin procesar r - e.g. '" some \\ false \ rawpath.txt "'. – kxr

+0

Ya no puedo reproducir esto tampoco. Funciona perfectamente, creo que esta es una solución muy clara. Eliminaré mi otro comentario. ¡Gracias! – Alecz