1

I'm trying to write some code to recursively renaming files in python. I've got a root folder which has another folder inside it, and yet another folder inside that folder. Each of this folders has a file named "Name.txt" and I would like to change them to "Test.txt", in order to understand how os.walk() and os.rename() work. I've written this code:

# -*- coding: utf-8 -*-

import os


def renamefiles(path):

    rootstructure=os.walk(path,topdown=False)
    for root,dirs,files in os.walk(rootstructure):

        for filenames in files:

        fullfilename=os.path.abspath(filenames)

        os.rename(fullfilename,"Test.txt")



renamefiles(".")

However, I get this error:

File "/usr/lib/python2.7/os.py", line 278, in walk
names = listdir(top)
TypeError: coercing to Unicode: need string or buffer, generator found

What am I doing wrong?

Thanks in advance.

Alberto
  • 21
  • 2
  • You're not using `os.walk` properly, see (http://stackoverflow.com/questions/10989005/do-i-understand-os-walk-right) – TemporalWolf Jun 25 '16 at 18:11
  • You shouldn't be posting answers with your updated code. Edit the original question with your updates and delete the "answers", as they don't answer the question. – TemporalWolf Jun 25 '16 at 20:01

3 Answers3

0

os.rename can be destructive. Use it carefully.

You had rootstructure initialised to os.walk for somereason. You need to initialize it to the path of the current directory.

import os

def renamefiles(path):
    rootstructure=os.path.abspath(path)

    for root,dirs,files in os.walk(rootstructure):
        for filenames in files:
            fullfilename=os.path.abspath(filenames)
            print(fullfilename)
            # Use this carefuly, it can wipe off your entire system
            # if not used carefully
            os.rename(fullfilename,"Test.txt")

renamefiles(".")
oxalorg
  • 2,768
  • 1
  • 16
  • 27
0

You need to pass a string representing a path to os.walk. Currently, you are passing rootstructure, which is a generator object.

def renamefiles(path):
    for root,dirs,files in os.walk(path):
        for filenames in files:
            fullfilename=os.path.abspath(filenames)

            # YOU PROBABLY WANT TO CHECK THE FILENAME BEFORE RENAMING!
            # WHAT IF THE FILE IS NOT Name.txt !
            os.rename(fullfilename,"Test.txt")

renamefiles(".")
Jordan Bonitatis
  • 1,527
  • 14
  • 12
0

Summary

The suggested changes are as follows:

  • Use os.getcwd() instead of "." since it doesn't seem to be resolved the way you want. This will be illustrated in the diagnostics function.
  • Use relative path renaming by os.chdir(root). Of course using correct absolute paths also works, but IMHO relative paths are just more elegant.
  • Pass an unambiguous string into os.walk() as others have mentioned.

Also note that topdown=False in os.walk() doesn't matter. Since you are not renaming directories, the directory structure will be invariant during os.walk().

Code Sample

Original file structure:

bill@Bill-deb:/mnt/ramdisk/test$ tree .
.
├── outer
│   ├── inner
│   │   └── innermost.txt
│   └── inner.txt
├── outer.txt
└── rename.py

Code:

# -*- coding: utf-8 -*-

import os

def renamefiles(path):

    for root, dirs, files in os.walk(path, topdown=False):
        for f in files:
            # chdir before renaming
            os.chdir(root)  
            if f != "rename.py":  # avoid renaming this file
                os.rename(f, "renamed.txt")  # relative path, more elegant


renamefiles(os.getcwd())  # pass an unambiguous string

Resulted file structure:

bill@Bill-deb:/mnt/ramdisk/test$ tree .
.
├── outer
│   ├── inner
│   │   └── renamed.txt
│   └── renamed.txt
├── renamed.txt
└── rename.py

Tested under debian 8.6 64-bit, python 2.7.12 (Anaconda 4.1.1).

For Diagnostics

# -*- coding: utf-8 -*-

import os

def renamefiles_check(path):

    for root, dirs, files in os.walk(path, topdown=False):

        for f in files:
            print "========="
            print "os.getcwd() = {}".format(os.getcwd())
            print "root = {}".format(root)
            print "f = {}".format(f)
            print "os.path.abspath(f) = {}".format(os.path.abspath(f))
            print "os.path.join(root, f) = {}".format(os.path.join(root, f))

# renamefiles_check(".")
# renamefiles_check(os.getcwd())

The first few lines of renamefiles_check(".") are shown here:

os.getcwd() = /mnt/ramdisk/test
root = ./outer/inner
f = innermost.txt
os.path.abspath(f) = /mnt/ramdisk/test/innermost.txt
os.path.join(root, f) = ./outer/inner/innermost.txt

You can verify that:

  • The behavior os.path.abspath(f) is not desired (not to say it's wrong). It always binds to the parameter path that was passed into os.walk() instead of the path containing file f.

  • When "." is passed as path, the dot in os.path.join(root, f) is still not fully resolved.

The sample code avoids these ambiguities.

Bill Huang
  • 4,491
  • 2
  • 13
  • 31