100

How do I get the absolute paths of all the files in a directory that could have many sub-folders in Python?

I know os.walk() recursively gives me a list of directories and files, but that doesn't seem to get me what I want.

alex
  • 6,818
  • 9
  • 52
  • 103
madCode
  • 3,733
  • 5
  • 26
  • 31

11 Answers11

106

os.path.abspath makes sure a path is absolute. Use the following helper function:

import os

def absoluteFilePaths(directory):
    for dirpath,_,filenames in os.walk(directory):
        for f in filenames:
            yield os.path.abspath(os.path.join(dirpath, f))
Danny Varod
  • 17,324
  • 5
  • 69
  • 111
phihag
  • 278,196
  • 72
  • 453
  • 469
  • 4
    I think it is nicer to do the abspath just once, on the `os.walk` line, than to do it N times inside the loop – wim Mar 22 '12 at 05:29
  • 1
    That works, but only by "accident". Reading `os.path.join`'s contract, I cannot find any place that guarantees that the result is absolute if one of the arguments is, although that's a sensible assumption. – phihag Mar 22 '12 at 05:32
  • 1
    @phihag That's reliable. It is not "accident", and the language is not so formal as to have any notion of "contracts" in the docs. It's documented that *if a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.* Python cannot invisibly transform into a relative path here, and it would be impossible to modify the behavior without a huge backwards breaking change. If still not convinced, you can even just read the source of `os.path.join`, which is short and simple. – wim Mar 14 '19 at 15:33
36

If the argument given to os.walk is absolute, then the root dir names yielded during iteration will also be absolute. So, you only need to join them with the filenames:

import os

for root, dirs, files in os.walk(os.path.abspath("../path/to/dir/")):
    for file in files:
        print(os.path.join(root, file))
wim
  • 338,267
  • 99
  • 616
  • 750
  • Okay, I see what you mean, just I didn't want the files, but wanted specific subdirs. I've posted the solution below. – Eamonn Kenny Feb 19 '16 at 10:25
34

You can use stdlib pathlib (or the backport if you have Python version < 3.4):

import pathlib
for filepath in pathlib.Path(directory).glob('**/*'):
    print(filepath.absolute())
wim
  • 338,267
  • 99
  • 616
  • 750
MSeifert
  • 145,886
  • 38
  • 333
  • 352
10

Try:

import os

for root, dirs, files in os.walk('.'):
    for file in files:
        p=os.path.join(root,file)
        print p
        print os.path.abspath(p)
        print
the wolf
  • 34,510
  • 13
  • 53
  • 71
9

You can use os.path.abspath() to turn relative paths into absolute paths:

file_paths = []

for folder, subs, files in os.walk(rootdir):
  for filename in files:
    file_paths.append(os.path.abspath(os.path.join(folder, filename)))
Blender
  • 289,723
  • 53
  • 439
  • 496
  • 1
    doesn't this join the `cwd` to `filename`, when you want to join the `folder`?! – wim Mar 22 '12 at 05:27
8

Starting with python 3.5 the idiomatic solution would be:

import os

def absolute_file_paths(directory):
    path = os.path.abspath(directory)
    return [entry.path for entry in os.scandir(path) if entry.is_file()]

This not just reads nicer but also is faster in many cases. For more details (like ignoring symlinks) see original python docs: https://docs.python.org/3/library/os.html#os.scandir

Titusz
  • 1,435
  • 1
  • 22
  • 30
5

All files and folders:

x = [os.path.abspath(os.path.join(directory, p)) for p in os.listdir(directory)]

Images (.jpg | .png):

x = [os.path.abspath(os.path.join(directory, p)) for p in os.listdir(directory) if p.endswith(('jpg', 'png'))]
Abhijeet Kasurde
  • 3,937
  • 1
  • 24
  • 33
user3041840
  • 352
  • 4
  • 8
3
from glob import glob


def absolute_file_paths(directory):
    return glob(join(directory, "**"))
MBT
  • 21,733
  • 19
  • 84
  • 102
AmjadHD
  • 163
  • 6
  • 6
    While this code might answer the question you still might consider adding a few explanatory sentences as this increases the value of your answer for other users. – MBT May 22 '18 at 11:38
  • 1
    This only works when you also import `join` from the `os` module, like so: `from os.path import join`. Doesn't do folders recursively. – martin-martin Apr 30 '20 at 15:45
1

Try:

from pathlib import Path
path = 'Desktop'
files = filter(lambda filepath: filepath.is_file(), Path(path).glob('*'))
for file in files:
   print(file.absolute())
Pygirl
  • 12,969
  • 5
  • 30
  • 43
  • Your import statement imports `Path` directly, but then you call `pathlib.Path()` in the code. Currently doesn't run unless you fix that. Otherwise nice and clean solution @Pygirl. – martin-martin Apr 30 '20 at 15:49
  • In this example, there is no need to make `list` out of those files, filter returns a generator. – MaLiN2223 May 01 '20 at 07:02
  • 1
    @MaLiN2223: Yeah it's true but I want to store the file list because when the generator is exhaust then files will give none. Anyway I have updated my answer :) – Pygirl May 01 '20 at 07:17
-1
for root, directories, filenames in os.walk(directory):
 for directory in directories:
         print os.path.join(root, directory)
 for filename in filenames:
     if filename.endswith(".JPG"):
        print filename
        print os.path.join(root,filename)
Robert A
  • 337
  • 4
  • 3
  • 2
    While this might answer the authors question, it lacks some explaining words and links to documentation. Raw code snippets are not very helpful without some phrases around it. You may also find [how to write a good answer](https://stackoverflow.com/help/how-to-answer) very helpful. Please edit your answer. – hellow Sep 27 '18 at 13:44
-2

Try This

pth=''
types=os.listdir(pth)
for type_ in types:
     file_names=os.listdir(f'{pth}/{type_}')
     file_names=list(map(lambda x:f'{pth}/{type_}/{x}',file_names))
     train_folder+=file_names
Tom Huang
  • 9
  • 3