2010-09-11 19 views
18

विंडोज केस-संवेदी फ़ाइल नाम का उपयोग करता है, तो मैं इन से किसी के साथ एक ही फाइल खोल सकते हैं:पायथन में, मैं फ़ाइल के लिए सही तरीके से कैसा पथ कैसे प्राप्त कर सकता हूं?

r"c:\windows\system32\desktop.ini" 
r"C:\WINdows\System32\DESKTOP.ini" 
r"C:\WiNdOwS\SyStEm32\DeSkToP.iNi" 

आदि इन रास्तों में से किसी को देखते हुए, मैं सच मामला कैसे मिल सकती है? मैं उन सभी का उत्पादन करना चाहते हैं:

r"C:\Windows\System32\desktop.ini" 

os.path.normcase यह नहीं है, यह बस सब कुछ lowercases। os.path.abspath एक पूर्ण पथ देता है, लेकिन इनमें से प्रत्येक पहले से ही पूर्ण है, और इसलिए यह उनमें से कोई भी नहीं बदलता है। os.path.realpath केवल प्रतीकात्मक लिंक को हल करने के लिए उपयोग किया जाता है, जो कि विंडोज़ नहीं है, इसलिए यह विंडोज़ पर abspath जैसा ही है।

क्या ऐसा करने का कोई सीधा तरीका है?

+1

इस तरह लग रहा है http://stackoverflow.com/questions/2113822/python-getting-filename-case के एक dup है -स-स्टोर-इन-विंडोज़, जिसका उत्तर है। –

उत्तर

6

यहाँ एक सरल, stdlib केवल, समाधान है ।

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] 
+1

मुझे यह पसंद है: यह मेरे लिए 'os.walk' करने में' ग्लोब 'की चाल है! –

+1

यह केवल फ़ाइल नाम को ठीक करता है, पिछले उपनिवेश नहीं। मैं इस http://stackoverflow.com/a/14742779/1355726 – xvorsx

+0

पर आधारित एक और उत्तर जोड़ता हूं, यह काम नहीं करता है। साथ ही, यह ग्लोब टोकन वाले वर्णों के साथ फ़ाइल नामों में विफल हो जाएगा। यदि यह एक निर्देशिका स्कैन ट्रिगर करता है, तो यह शायद पैथोलॉजिकल धीमा भी होगा ... –

4

चूंकि एनटीएफएस (या वीएफएटी) फाइल सिस्टम पर "सच्चे मामले" की परिभाषा वास्तव में विचित्र है, ऐसा लगता है कि पथ चलने और os.listdir() के खिलाफ मैच का सबसे अच्छा तरीका होगा।

हां, यह एक प्रदूषित समाधान की तरह लगता है लेकिन एनटीएफएस पथ भी हैं। इस पर परीक्षण करने के लिए मेरे पास एक डॉस मशीन नहीं है।

+0

यह गैर-सीधा समाधान है जो मुझे डर था ... :( –

+0

मेरे विचारों को ठीक से – aaronasterling

1

मैं os.walk का प्रयोग करेंगे, लेकिन मुझे लगता है कि कई निर्देशिका के साथ diskw के लिए यह समय लगता हो सकता है कि:

fname = "g:\\miCHal\\ZzZ.tXt" 
if not os.path.exists(fname): 
    print('No such file') 
else: 
    d, f = os.path.split(fname) 
    dl = d.lower() 
    fl = f.lower() 
    for root, dirs, files in os.walk('g:\\'): 
     if root.lower() == dl: 
      fn = [n for n in files if n.lower() == fl][0] 
      print(os.path.join(root, fn)) 
      break 
7

This python-win32 thread एक जवाब है कि तीसरे पक्ष के संकुल की आवश्यकता नहीं है है या पेड़ चलने:

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 
+1

यह मेरे लिए काम नहीं करता है (W7 पर परीक्षण) – Joril

+0

यह विफल हो सकता है क्योंकि 'पथ' 'GetLongPathNameW के लिए यूनिकोड होना चाहिए 'यूनिकोड (पथ)' – Attila

+0

के साथ 'GetLongPathName (पथ, buf, 260)' कॉल में 'पथ'' को प्रतिस्थापित करने का प्रयास करें। यह 0 काम नहीं करता है। GetLongPathName केवल छोटे फ़ाइल नामों का विस्तार करता है, इसलिए यदि आप इसे " \ Progra ~ 1 "आपको" सी: \ प्रोग्राम फ़ाइलें "मिलेंगी, लेकिन यदि आप इसे" सी: \ प्रोग्राम प्रोग्राम "देते हैं, तो यह पहले से ही एक लंबा पथनाम है इसलिए यह इसे नहीं बदलेगा। –

13

नेड का GetLongPathName उत्तर काफी काम नहीं करता है (कम से कम मेरे लिए नहीं)। GetShortPathname के वापसी मूल्य पर आपको GetLongPathName पर कॉल करने की आवश्यकता है। संक्षिप्तता के लिए pywin32 का उपयोग करना (एक ctypes समाधान नेड के समान लगेगा):

import glob 
def get_actual_filename(name): 
    name = "%s[%s]" % (name[:-1], name[-1]) 
    return glob.glob(name)[0] 
+0

पूरी तरह से काम करता है, धन्यवाद :) – Joril

+0

http://stackoverflow.com/a/2114975/179715 पर मेरी टिप्पणी देखें; यदि लघु फ़ाइल नाम पीढ़ी अक्षम है तो यह काम करने की गारंटी नहीं है। – jamesdlin

+0

यदि आप पूर्ण पथ की परवाह करते हैं, तो ध्यान दें कि यह एक ड्राइव अक्षर को अधिक सामान्य ऊपरी-मामले में परिवर्तित नहीं करेगा। –

6

Ethan answer केवल फ़ाइल को सही नाम, पथ पर सबफ़ोल्डर नहीं नाम:

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

मैं एतान और xvorsx की प्रक्रिया अपनाते हैं: यहाँ मेरा अनुमान है। AFAIK, निम्नलिखित भी अन्य प्लेटफार्मों पर नुकसान होगा नहीं:

import os.path 
from glob import glob 

def get_actual_filename(name): 
    sep = os.path.sep 
    parts = os.path.normpath(name).split(sep) 
    dirs = parts[0:-1] 
    filename = parts[-1] 
    if dirs[0] == os.path.splitdrive(name)[0]: 
     test_name = [dirs[0].upper()] 
    else: 
     test_name = [sep + dirs[0]] 
    for d in dirs[1:]: 
     test_name += ["%s[%s]" % (d[:-1], d[-1])] 
    path = glob(sep.join(test_name))[0] 
    res = glob(sep.join((path, filename))) 
    if not res: 
     #File not found 
     return None 
    return res[0] 
2

listdir की एक जोड़ी बंद आधार/उपरोक्त उदाहरण चलना है, लेकिन समर्थन करता है, UNC पथ

def get_actual_filename(path): 
    orig_path = path 
    path = os.path.normpath(path) 

    # Build root to start searching from. Different for unc paths. 
    if path.startswith(r'\\'): 
     path = path.lstrip(r'\\') 
     path_split = path.split('\\') 
     # listdir doesn't work on just the machine name 
     if len(path_split) < 3: 
      return orig_path 
     test_path = r'\\{}\{}'.format(path_split[0], path_split[1]) 
     start = 2 
    else: 
     path_split = path.split('\\') 
     test_path = path_split[0] + '\\' 
     start = 1 

    for i in range(start, len(path_split)): 
     part = path_split[i] 
     if os.path.isdir(test_path): 
      for name in os.listdir(test_path): 
       if name.lower() == part.lower(): 
        part = name 
        break 
      test_path = os.path.join(test_path, part) 
     else: 
      return orig_path 
    return test_path 
1

मैं सिर्फ एक ही साथ संघर्ष कर रहा था मुसीबत। मुझे यकीन नहीं है, लेकिन मुझे लगता है कि पिछले उत्तरों में सभी मामलों को शामिल नहीं किया गया है। मेरी वास्तविक समस्या यह थी कि ड्राइव अक्षर आवरण सिस्टम द्वारा देखे गए एक से अलग था।यहाँ मेरी समाधान भी सही ड्राइव अक्षर आवरण के लिए जाँच करता (win32api का उपयोग) है:

def get_case_sensitive_path(path): 
     """ 
     Get case sensitive path based on not - case sensitive path. 

     Returns: 
     The real absolute path. 

     Exceptions: 
     ValueError if the path doesn't exist. 

     Important note on Windows: when starting command line using 
     letter cases different from the actual casing of the files/directories, 
     the interpreter will use the invalid cases in path (e. g. os.getcwd() 
     returns path that has cases different from actuals). 
     When using tools that are case - sensitive, this will cause a problem. 
     Below code is used to get path with exact the same casing as the 
     actual. 
     See http://stackoverflow.com/questions/2113822/python-getting-filename-case-as-stored-in-windows 
     """ 
     drive, path = os.path.splitdrive(os.path.abspath(path)) 
     path = path.lstrip(os.sep) 
     path = path.rstrip(os.sep) 
     folders = [] 

     # Make sure the drive number is also in the correct casing. 
     drives = win32api.GetLogicalDriveStrings() 
     drives = drives.split("\000")[:-1] 
     # Get the list of the the form C:, d:, E: etc. 
     drives = [d.replace("\\", "") for d in drives] 
     # Now get a lower case version for comparison. 
     drives_l = [d.lower() for d in drives] 
     # Find the index of matching item. 
     idx = drives_l.index(drive.lower()) 
     # Get the drive letter with the correct casing. 
     drive = drives[idx] 

     # Divide path into components. 
     while 1: 
      path, folder = os.path.split(path) 
      if folder != "": 
       folders.append(folder) 
      else: 
       if path != "": 
        folders.append(path) 
       break 

     # Restore their original order. 
     folders.reverse() 

     if len(folders) > 0: 
      retval = drive + os.sep 

      for folder in folders: 
       found = False 
       for item in os.listdir(retval): 
        if item.lower() == folder.lower(): 
         found = True 
         retval = os.path.join(retval, item) 
         break 
       if not found: 
        raise ValueError("Path not found: '{0}'".format(retval)) 

     else: 
      retval = drive + os.sep 

     return retval 
5

यह एक, एकीकृत को घटा देती है और कई दृष्टिकोण ठीक करता है: स्टैंडर्ड lib केवल; सभी पथ भागों को परिवर्तित करता है (ड्राइव अक्षर को छोड़कर); सापेक्ष या पूर्ण पथ; ड्राइव अक्षर या नहीं; tolarant:

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

और यह एक अलावा UNC पथ संभालता है:

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

यह मेरे लिए काम करने वाले इस धागे में एकमात्र ऐसा है। धन्यवाद! – MaVCArt

संबंधित मुद्दे

 संबंधित मुद्दे