62

I have a folder with ten files in it which I want to loop through. When I print out the name of the file my code works fine:

import os
indir = '/home/des/test'
for root, dirs, filenames in os.walk(indir):
    for f in filenames:
        print(f)

Which prints:

1
2
3
4
5
6
7
8
9
10

But if I try to open the file in the loop I get an IO error:

import os
indir = '/home/des/test'
for root, dirs, filenames in os.walk(indir):
    for f in filenames:
        log = open(f, 'r')

Traceback (most recent call last):
File "/home/des/my_python_progs/loop_over_dir.py", line 6, in <module>
log = open(f, 'r')
IOError: [Errno 2] No such file or directory: '1'
>>> 

Do I need to pass the full path of the file even inside the loop to open() them?

smci
  • 26,085
  • 16
  • 96
  • 138
balcoder
  • 709
  • 1
  • 7
  • 13
  • 1
    Are you trying to traverse a directory tree, or are you just interested in the regular files in a specific directory/folder? – Levon Aug 03 '12 at 18:52
  • I know this question is four years old, but it still doesn't have an accepted answer. – user327301 Jan 24 '17 at 18:54
  • Yes. Related: [Python open() gives IOError: Errno 2 No such file or directory](https://stackoverflow.com/questions/12201928/python-open-gives-ioerror-errno-2-no-such-file-or-directory) – smci Sep 12 '18 at 07:36

5 Answers5

92

If you are just looking for the files in a single directory (ie you are not trying to traverse a directory tree, which it doesn't look like), why not simply use os.listdir():

import os  
for fn in os.listdir('.'):
     if os.path.isfile(fn):
        print (fn)

in place of os.walk(). You can specify a directory path as a parameter for os.listdir(). os.path.isfile() will determine if the given filename is for a file.

Alice Purcell
  • 11,478
  • 6
  • 42
  • 55
Levon
  • 118,296
  • 31
  • 184
  • 178
  • the OP's loop doesn't only print the files in one directory. It prints the files (recursively) in every directory undearneath the input directory as well. – mgilson Aug 03 '12 at 18:35
  • @mgilson I must be missing that in looking at OP's code (OP only refers to filenames not directories) and part of the question read "folder with ten files in it which i want to loop through." .. did I skip some information? – Levon Aug 03 '12 at 18:37
  • If the OP has the directory structure :`.` contains `file1`,`directory1` and `directory1` contains `file2`. the OP's code will print `file1`,`file2` whereas your solution would print `file1`, `directory1`. (sorry, this is really hard to explain in comments). – mgilson Aug 03 '12 at 18:40
  • @mgilson No I trust you, let me look it over and make corrections or delete the answer if it's not appropriate - thanks for the heads up. – Levon Aug 03 '12 at 18:41
  • @mgilson I adjusted my answer to only deal with regular files. – Levon Aug 03 '12 at 18:50
  • closer. But your answer still doesn't recuse into sub-directories the way `os.walk` does. But I suppose you covered that with "if you are just looking for files in a single directory"... – mgilson Aug 03 '12 at 18:51
  • @mgilson I don't see OP doing this (traversing a directory tree), OP ignores 2 of the 3 return values from os.walk and only uses the filename. In any case, I asked OP for a clarification. – Levon Aug 03 '12 at 18:53
  • Reading the OP's question (not code) and your answer again, I think I agree that this is the way to do it. (+1). – mgilson Aug 03 '12 at 18:53
  • @mgilson I think the use of os.walk() is misleading/unnecessary for this purpose unless I misunderstood the question totally. I guess OP will know. – Levon Aug 03 '12 at 18:57
  • I now agree. (I was mislead by it ;). We're on the same page now. – mgilson Aug 03 '12 at 18:58
  • What does `fn` represent? File name? – Ethan Bierlein Mar 28 '15 at 16:34
  • @EthanBierlein yes, that's right, `fn` is short for filename, each time it iterates through the list of filenames in the current directory, this variable will take on a different filename. – Levon Mar 28 '15 at 20:25
  • Dont forget adding the full path to fn if you are iterating over some else than '.' .... – Steinfeld Oct 13 '16 at 12:14
  • 1
    To be more general, change '.' to `path` (variable), and update the if line to `if os.path.isfile(os.path.join(path, fn)):`. – Keir Simmons Jun 05 '17 at 14:08
26

Yes, you need the full path.

log = open(os.path.join(root, f), 'r')

Is the quick fix. As the comment pointed out, os.walk decends into subdirs so you do need to use the current directory root rather than indir as the base for the path join.

koblas
  • 21,274
  • 6
  • 35
  • 42
8

You have to specify the path that you are working on:

source = '/home/test/py_test/'
for root, dirs, filenames in os.walk(source):
    for f in filenames:
        print f
        fullpath = os.path.join(source, f)
        log = open(fullpath, 'r')
Mustafa
  • 81
  • 1
  • 2
4

The examples to os.walk in the documentation show how to do this:

for root, dirs, filenames in os.walk(indir):
    for f in filenames:
        log = open(os.path.join(root, f),'r')

How did you expect the "open" function to know that the string "1" is supposed to mean "/home/des/test/1" (unless "/home/des/test" happens to be your current working directory)?

abarnert
  • 313,628
  • 35
  • 508
  • 596
4

Here's a snippet that will walk the file tree for you:

indir = '/home/des/test'
for root, dirs, filenames in os.walk(indir):
    for f in filenames:
        print(f)
        log = open(indir + f, 'r')
Joe C
  • 3,278
  • 2
  • 18
  • 32
Markos F
  • 215
  • 3
  • 3