The Python Oracle

In Python, how can I get the correctly-cased path for a file?

This video explains
In Python, how can I get the correctly-cased path for a file?

--

Become part of the top 3% of the developers by applying to Toptal
https://topt.al/25cXVn

--

Music by Eric Matyas
https://www.soundimage.org
Track title: Ancient Construction

--

Chapters
00:00 Question
00:58 Accepted answer (Score 7)
01:13 Answer 2 (Score 13)
01:44 Answer 3 (Score 9)
01:59 Answer 4 (Score 9)
02:33 Thank you

--

Full question
https://stackoverflow.com/questions/3692...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #windows #filenames

#avk47



ANSWER 1

Score 13


Ned's GetLongPathName answer doesn't quite work (at least not for me). You need to call GetLongPathName on the return value of GetShortPathname. Using pywin32 for brevity (a ctypes solution would look similar to Ned's):

>>> win32api.GetLongPathName(win32api.GetShortPathName('stopservices.vbs'))
'StopServices.vbs'



ANSWER 2

Score 9


Ethan answer correct only file name, not subfolders names on the path. Here is my guess:

def get_actual_filename(name):
    dirs = name.split('\\')
    # disk letter
    test_name = [dirs[0].upper()]
    for d in dirs[1:]:
        test_name += ["%s[%s]" % (d[:-1], d[-1])]
    res = glob.glob('\\'.join(test_name))
    if not res:
        #File not found
        return None
    return res[0]



ANSWER 3

Score 9


This one unifies, shortens and fixes several approaches: Standard lib only; converts all path parts (except drive letter); relative or absolute paths; drive letter'ed or not; tolarant:

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

And this one handles UNC paths in addition:

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



ANSWER 4

Score 7


This python-win32 thread has an answer that doesn't require third-party packages or walking the tree:

import ctypes

def getLongPathName(path):
    buf = ctypes.create_unicode_buffer(260)
    GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
    rv = GetLongPathName(path, buf, 260)
    if rv == 0 or rv > 260:
        return path
    else:
        return buf.value