Как получить абсолютный путь к файлу в Python?

Я прочитал довольно много ссылок на сайте, в которых говорится об использовании «os.path.abspath (# filename)». Этот метод не совсем работает для меня. Я пишу программу, которая сможет искать в данном каталоге файлы с определенными расширениями, сохранять имя и абсолютный путь как ключи и значения (соответственно) в словаре, а затем использовать абсолютный путь для открытия файлов и создания необходимые правки. У меня проблема в том, что когда я использую os.path.abspath(), он не возвращает полный путь.

Допустим, моя программа находится на рабочем столе. У меня есть файл, хранящийся в "C:\Users\Travis\Desktop\Test1\Test1A\test.c". Моя программа может легко найти этот файл, но когда я использую os.path.abspath(), она возвращает «C:\Users\Travis\Desktop\test.c», что является абсолютным путем, где хранится мой исходный код, но не файл, который я искал.

Мой точный код:

import os
Files={}#Dictionary that will hold file names and absolute paths
root=os.getcwd()#Finds starting point
for root, dirs, files in os.walk(root):
    for file in files:
        if file.endswith('.c'):#Look for files that end in .c
            Files[file]=os.path.abspath(file)

Любые советы или рекомендации относительно того, почему он может это делать и как я могу это исправить? Заранее спасибо!


person Walter Kovacs    schedule 16.05.2014    source источник
comment
os.path поощряет множество подверженных ошибкам шаблонов в вашем коде. Вам, вероятно, следует избегать этого настолько, насколько это возможно. Рассмотрите одну из лучших сторонних библиотек путей (например, pypi.python.org/pypi/filepath или даже pypi.python.org/pypi/strpath)   -  person Jean-Paul Calderone    schedule 16.05.2014
comment
@Jean-PaulCalderone: Это чепуха. Люди не всегда понимают, что является относительным, а что абсолютным, но утверждать, что os.path поощряет множество подверженных ошибкам шаблонов, нелепо.   -  person Martijn Pieters    schedule 16.05.2014
comment
@Jean-PaulCalderone: и если вы хотите порекомендовать объектно-ориентированный подход к обработке путей, почему бы не pathlib? Начиная с Python 3.4, это теперь часть стандартной библиотеки.   -  person Martijn Pieters    schedule 16.05.2014
comment
@MartijnPieters Думаю, это потому, что я нелепый.   -  person Jean-Paul Calderone    schedule 16.05.2014


Ответы (3)


os.path.abspath() делает относительный путь абсолютным относительно текущего рабочего каталога, а не исходного местоположения файла. Путь — это просто строка, Python не может узнать, откуда взялось имя файла.

Вам нужно предоставить каталог самостоятельно. Когда вы используете os.walk, каждая итерация перечисляет указанный каталог (root в вашем коде), список подкаталогов (только их имена) и список имен файлов (опять же, только их имена). Используйте root вместе с именем файла, чтобы сделать абсолютный путь:

Files={}
cwd = os.path.abspath(os.getcwd())
for root, dirs, files in os.walk(cwd):
    for file in files:
        if file.endswith('.c'):
            Files[file] = os.path.join(root, os.path.abspath(file))

Обратите внимание, что ваш код записывает только один путь для каждого уникального имени файла; если у вас есть foo/bar/baz.c и foo/spam/baz.c, это зависит от порядка, в котором ОС перечислила подкаталоги bar и spam, какой из двух путей выигрывает.

Вместо этого вы можете собрать пути в список:

Files={}
cwd = os.path.abspath(os.getcwd())
for root, dirs, files in os.walk(cwd):
    for file in files:
        if file.endswith('.c'):
            full_path = os.path.join(root, os.path.abspath(file))
            Files.setdefault(file, []).append(full_path)
person Martijn Pieters    schedule 16.05.2014
comment
Есть ли способ отредактировать приведенный выше код, чтобы иметь возможность находить файлы с одинаковым именем в разных каталогах? Также были бы сложности, если бы два файла имели одинаковое имя, но разные расширения в одном каталоге? - person Walter Kovacs; 16.05.2014
comment
@WalterKovacs: вы уже фильтруете по расширению, так что это не будет проблемой. Используйте список для хранения полных путей; Files.setdefault(file, []).append(os.path.join(root, os.path.abspath(file))) собирает найденные пути в список по имени файла. - person Martijn Pieters; 16.05.2014

Согласно документации для os.path.join ,

Если какой-либо компонент является абсолютным путем, все предыдущие компоненты (в Windows, включая предыдущую букву диска, если она была) отбрасываются.

Так, например, если второй аргумент является абсолютным путем, первый путь '/a/b/c' отбрасывается.

In [14]: os.path.join('/a/b/c', '/d/e/f')
Out[14]: '/d/e/f'

Следовательно,

os.path.join(root, os.path.abspath(file))

отбросит root независимо от того, что это такое, и вернет os.path.abspath(file), который прикрепит file к текущему рабочему каталогу, который не обязательно будет таким же, как root.

Вместо этого, чтобы сформировать абсолютный путь к файлу:

fullpath = os.path.abspath(os.path.join(root, file))

На самом деле, я считаю, что os.path.abspath не нужен, так как я считаю, что root всегда будет абсолютным, но мои рассуждения об этом зависят от исходный код os.walk, а не только задокументированное (гарантированное) поведение os.walk. Поэтому, чтобы быть абсолютно уверенным (каламбур), используйте os.path.abspath.


import os
samefiles = {}
root = os.getcwd()
for root, dirs, files in os.walk(root):
    for file in files:
        if file.endswith('.c'):
            fullpath = os.path.join(root, file)
            samefiles.setdefault(file, []).append(fullpath) 

print(samefiles)
person unutbu    schedule 16.05.2014

Glob полезен в этих случаях, вы можете сделать:

files = {f:os.path.join(os.getcwd(), f) for f in glob.glob("*.c")}

чтобы получить тот же результат

person galinden    schedule 16.05.2014
comment
Glob не пересекает подкаталоги. Вам все равно придется использовать os.walk(), и в этом случае вы можете использовать fnmatch для фильтрации имен файлов, но для простой проверки суффикса подойдет проверка filename.endswith('.c'). - person Martijn Pieters; 16.05.2014