2

INPUT: I want to add increasing numbers to file names in a directory sorted by date. For example, add "01_", "02_", "03_"...to these files below.

test1.txt (oldest text file)
test2.txt
test3.txt
test4.txt (newest text file)

Here's the code so far. I can get the file names, but each character in the file name seems to be it's own item in a list.

import os
for file in os.listdir("/Users/Admin/Documents/Test"):
if file.endswith(".txt"):
      print(file)

The EXPECTED results are:

   01_test1.txt
   02_test2.txt
   03_test3.txt
   04_test4.txt

with test1 being the oldest and test 4 being the newest.

How do I add a 01_, 02_, 03_, 04_ to each file name?

I've tried something like this. But it adds a '01_' to every single character in the file name.

new_test_names = ['01_'.format(i) for i in file]
print (new_test_names)
cs95
  • 379,657
  • 97
  • 704
  • 746
StacyM
  • 1,036
  • 5
  • 23
  • 41
  • Are you looking to have an independent counter that does not relate to the existing number in your filename? Or are you looking to use the number in the file name and set it at the beginning of the file as well? – idjaw Aug 08 '17 at 00:32
  • There are python solutions in the marked duplicates, they should help. – cs95 Aug 08 '17 at 00:35
  • Yes independent counter. It would start with the oldest text file in the folder and increase with the most recently created file as the highest counted file. – StacyM Aug 08 '17 at 00:38
  • @StacyM How are you determining oldest to newest? Is it going to be sorted by date? Or are you relying on order based on the existing numerical value in the filename? – idjaw Aug 08 '17 at 00:42
  • Yes sorted by date in the folder. Sorry I shouldn't have put any numbers in the text file name. It made it confusing. The numbers in the text file name are irrelevant. – StacyM Aug 08 '17 at 00:44
  • 1
    If you want them renamed by order of age, you'll need `os.listdir` followed by `sorted` on `os.path.getmtime`. Hmm... I might need to reopen this if that is indeed your requirement, however you didn't make that clear in your question so that bit's on you. – cs95 Aug 08 '17 at 00:44
  • Yes sorry! I know. I forgot to put the order by age as a requirement. I assumed it. – StacyM Aug 08 '17 at 00:47
  • 1
    @StacyM Add that explicitly to your question, and make it a bit clearer. I will reopen it. – cs95 Aug 08 '17 at 00:56
  • Add your input and expected output, maybe a clearer example would help. – cs95 Aug 08 '17 at 00:56
  • 1
    Also be clear on whether it is JUST `.txt` files or EVERYTHING inside a particular directory. Details are important. – cs95 Aug 08 '17 at 00:58
  • Yes, JUST .txt files. I updated the Input and Expected output. Please don't ban me or delete this post. I'm still studying the answers! – StacyM Aug 08 '17 at 00:59

5 Answers5

5
  1. If you want to number your files by age, you'll need to sort them first. You call sorted and pass a key parameter. The function os.path.getmtime will sort in ascending order of age (oldest to latest).

  2. Use glob.glob to get all text files in a given directory. It is not recursive as of now, but a recursive extension is a minimal addition if you are using python3.

  3. Use str.zfill to strings of the form 0x_

  4. Use os.rename to rename your files

import glob
import os

sorted_files = sorted(
    glob.glob('path/to/your/directory/*.txt'), key=os.path.getmtime)

for i, f in enumerate(sorted_files, 1):
    try:
        head, tail = os.path.split(f)            
        os.rename(f, os.path.join(head, str(i).zfill(2) + '_' + tail))
    except OSError:
        print('Invalid operation')

It always helps to make a check using try-except, to catch any errors that shouldn't be occurring.

cs95
  • 379,657
  • 97
  • 704
  • 746
  • 2
    Your formatting is a little wrong. I'd recommend `'{:02d}_{}'.format(i, f)` anyway, but yours could be fixed with something like `str(i).zfill(2) + '_' + f`. – user94559 Aug 08 '17 at 01:11
  • @smarx Oh, that's simpler. Thank you! – cs95 Aug 08 '17 at 01:12
  • If i have more than 99 files in my directory, won't the code break? How do I handle an unlimited number of files? – StacyM Aug 08 '17 at 01:15
  • 1
    @StacyM It doesn't break. It just won't append `0` anymore. That's how zfill works. If you are accounting for more than 99 files, I recommend `.zfill(3)` instead of 2. – cs95 Aug 08 '17 at 01:15
  • 1
    @StacyM Convert it to a list: `list((os.path.basename(x) for x in sorted_files))` – cs95 Aug 08 '17 at 15:51
  • The `os,rename...` still results in `FileNotFoundError: [WinError 2] The system cannot find the file specified: 'test1 - Copy (2).txt' -> '01_test1 - Copy (2).txt'` I get a list of base names, but it doesn't seem to help the error. – StacyM Aug 08 '17 at 15:57
  • 1
    @StacyM Ohhhh now I understand the problem. _Don't_ use `os.path.basename` like that. `os.rename` needs the full path. I've made an edit to my answer. Hopefully that'll do it. – cs95 Aug 08 '17 at 16:10
  • That worked! Yay. Thanks. I found python documentation on `os.path.split` and `head, tail` – StacyM Aug 08 '17 at 16:37
3

This should work:

import glob

new_test_names = ["{:02d}_{}".format(i, filename) for i, filename in enumerate(glob.glob("/Users/Admin/Documents/Test/*.txt"), start=1)]

Or without list comprehension:

for i, filename in enumerate(glob.glob("/Users/Admin/Documents/Test/*.txt"), start=1):
    print("{:02d}_{}".format(i, filename))

Three things to learn about here:

  1. glob, which makes this sort of file matching easier.
  2. enumerate, which lets you write a loop with an index variable.
  3. format, specifically the 02d modifier, which prints two-digit numbers (zero-padded).
user94559
  • 59,196
  • 6
  • 103
  • 103
1

The easiest way is to simply have a variable, such as i, which will hold the number and prepend it to the string using some kind of formatting that guarantees it will have at least 2 digits:

import os

i = 1
for file in os.listdir("/Users/Admin/Documents/Test"):
  if file.endswith(".txt"):
        print('%02d_%s' % (i, file)) # %02d means your number will have at least 2 digits
        i += 1

You can also take a look at enumerate and glob to make your code even shorter (but make sure you understand the fundamentals before using it).

Matheus Portela
  • 2,420
  • 1
  • 21
  • 32
1

two methods to format integer with leading zero.

1.use .format

import os
i = 1
for file in os.listdir("/Users/Admin/Documents/Test"):
    if file.endswith(".txt"):
        print('{0:02d}'.format(i) + '_' + file)
        i+=1

2.use .zfill

import os
i = 1
for file in os.listdir("/Users/Admin/Documents/Test"):
    if file.endswith(".txt"):
        print(str(i).zfill(2) + '_' + file)
        i+=1
Wonjin
  • 432
  • 3
  • 11
0
test_dir = '/Users/Admin/Documents/Test'
txt_files = [file
             for file in os.listdir(test_dir)
             if file.endswith('.txt')]
numbered_files = ['%02d_%s' % (i + 1, file)
                  for i, file in enumerate(txt_files)]
J_H
  • 17,926
  • 4
  • 24
  • 44