2009-12-04 7 views
5

Existe-t-il un moyen simple d'obtenir le chemin sensible à la casse "réel" à partir d'un chemin en minuscules. Comme l'inverse de os.path.normcase.Inverser os.path.normcase sous Windows

Par exemple, considérons le répertoire:

c:\StackOverFlow 

Si je l'extrait suivant, comment obtenir 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')' vous donne 'c: stackoverflow', * pas *' c: \ stackoverflow', comme cela est expliqué dans la documentation (= chemin relatif au répertoire actuel sur le lecteur spécifié). –

+0

Oui, je n'ai pas vérifié mon code d'exemple. Je vais le réparer. Merci. – pkit

Répondre

0

approche bidouille,

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

glob.glob (d + '*') renvoie une liste vide sur Windows (au moins pour moi) – jhwist

+0

@jhwist, je l'ai testé sur Windows et ça marche. Qu'avez-vous utilisé pour 'd'? –

+0

Hmmm, pourrait être un mélange de chemins de style cygwin, mon 'd =" c:/existing_file "' – jhwist

1

Je ne considère pas cette solution simples, mais ce que vous pouvez est:

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) 

Il est probablement pas efficace (selon le nombre de fichiers dans le répertoire). Il a besoin de peaufiner pour les composants de chemin (ma solution ne corrige vraiment le cas du nom de fichier et ne se soucie pas des noms de répertoires). Aussi, peut-être que os.walk pourrait être utile pour traverser l'arbre.

-1

Certainement laid, mais amusant:

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

Bien sûr:

  • fonctionne uniquement avec dirs
  • sera bogué si dir ne peut pas être ouvert pour une autre raison

Mais peut toujours être utile si vous n'en avez pas besoin pour le type de code "vie ou mort".

Essayé de grep la lib standard pour trouver comment ils ont trouvé le chemin réel, mais ne pouvait pas le trouver. Doit être en C.

Ce fut le sale hack de la journée, la prochaine fois que nous allons utiliser une expression rationnelle sur le stacktrace juste parce que nous pouvons :-)

+0

Ne fonctionne pas ... – schlamar

0

Vous pouvez le faire en enchaînant GetShortPathName et GetLongPathName. Cela peut en théorie ne pas fonctionner parce que vous pouvez désactiver les noms de fichiers courts sur Windows avec certains paramètres de configuration. Voici quelques exemples de code utilisant 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

Cela fonctionne tout simplement EXCEPTE que le lecteur ou le composant réseau d'un chemin peut toujours être un cas arbitraire. J'ai trouvé utile d'ajouter 'parts = os.path.splitdrive (os.path.normcase (chemin))' 'chemin = parties [0] .upper() + parties [1]' au début de la fonction de sorte que j'aurais des lettres de lecteur majuscules et des chemins de réseau en minuscules. – garlon4

+0

Remarque: Pour cette solution dépendant du système de fichiers, vérifiez d'abord si ** la génération de nom court ** est désactivée sur les volumes Windows (fsutil.exe 8dot3name query C: ') - qui est recommandée pour les performances à moins que les applications 16bit festoient encore. – kxr

1

Utilisation lib standard uniquement, celui-ci fonctionne sur toutes les parties chemin/subdirs (sauf lettre de lecteur):

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

Et celui-ci gère les chemins UNC en plus:

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, les fichiers sont le cas d'utilisation principal. Impossible de reproduire le problème. Exemple? Connu: il ne met pas en majuscule une lettre de lecteur possible (et le nom du service UNC); ne convertit pas les barres obliques -> barre oblique inverse. il ne fait rien sur les fichiers/répertoires qui n'existent pas vraiment (existence d'un chemin partiel). Ou peut-être avez-vous utilisé un chemin de test avec un backslash faux/faux qui s'échappe ou un préfixe de chaîne brute manquant r - par exemple. '" certains \\ faux \ rawpath.txt "'. – kxr

+0

Je ne peux plus reproduire cela non plus. Cela fonctionne parfaitement, je pense que c'est une solution très soignée. Je vais supprimer mon autre commentaire. Merci! – Alecz