Rename files to instead being in sub-directories,

2020-05-02 02:50发布

Create a copy of the CarItems tree called CarItemsCopy where all files, instead of being in directories named after years, rather have the year as part of the filename, and the year directories are entirely absent. Instead of some of these examples:

CarItems/Chevrolet/Chevelle/2011/parts.txt
CarItems/Chevrolet/Chevelle/1982/parts.txt
CarItems/Chevrolet/Volt/1994/parts.txt

it should look like this:

CarItemsCopy/Chevrolet/Chevelle/parts-2011.txt
CarItems/Chevrolet/Chevelle/parts-1982.txt
CarItems/Chevrolet/Volt/parts-1994.txt

Do this using Python (you can't create the copy by manually rearranging things). You may use the os module's walk generator. Hint: You might find the os.path module's split function to be helpful. You don't have to use it though.

This is the code I have got so far:

def create_dir(dir_path):
""" Creates a new directory.

This function is used to create a new directory.

Positional Input Parameter:
    directory: Car
Keyword Input Parameters:
    None    
"""
    if not os.path.exists(dir_path):
        former_path, sub_dir = os.path.split(dir_path)

        if os.path.exists(former_path) or former_path == "":
            os.mkdir(dir_path)
        else:
            create_dir(former_path)
            os.mkdir(dir_path) 

    for dirpath, dirname, filename in os.walk("CarItems"):
        if len(filename) > 0:
            sub_path, year = os.path.split(dirpath)

        for i in filename:
            name, suffix = os.path.splitext(i)
            new_file = name + "-" + year + suffix

            new_path = sub_path.replace("CarItems", "CarItemsCopy")
            create_dir(new_path)

            file_path = os.path.join(dirpath, i)
            new_file_path = os.path.join(new_path, new_file)

            shutil.copy2(file_path, new_file_path)

FileNotFoundError: [Errno 2] No such file or directory: '' this is the error I'm getting on a Mac, on a windows it works perfectly. My question, why is that, and what adjustment would need to be made for it to work on a mac? Thanks!

2条回答
神经病院院长
2楼-- · 2020-05-02 03:34

In the what it should look like section I think you made a mistake. Only one directory will exist under CarItemsCopy, the other will be renamed where they're located.

Task:

Create a copy of the CarItems tree called CarItemsCopy where all files, instead of being in directories named after years, rather have the year as part of the filename, and the year directories are entirely absent.

The path, shutil, and os modules should simplify the task:

from pathlib import Path
import os
from shutil import copy2

# Place this script in the CarItems folder.    

# The full path to our CarItems folder.
script_dir = Path(os.path.dirname(os.path.abspath(__file__)))
source_dir = script_dir.joinpath("Caritems")

for folder in source_dir.iterdir():
    for subfolder in folder.iterdir():
        subfolder_with_parts = subfolder.joinpath("parts.txt")
        if subfolder_with_parts.exists(): # Only continue if parts.txt exists.
            ext = subfolder_with_parts.suffix # In this case .txt
            parts = Path(f"CarItemsCopy//{folder.stem}//parts-{subfolder.stem}{ext}")
            car_copy = script_dir.joinpath(parts)
            car_copy.parent.mkdir(parents=True, exist_ok=True)
            copy2(subfolder_with_parts, car_copy) # Will attempt to copy the metadata.
查看更多
等我变得足够好
3楼-- · 2020-05-02 03:38

You do need the walk to get to all the filenames, though you can directly figure out the new filenames.

The psuedocode:

# Make a list of filenames with os.walk
# For each filename in that list:
#    If the filename matches a regex of ending with four digits, slash, name
#        make the new filename
#        use os.rename to move the original file to the new file.

You need to make a separate list rather than just for name in os.walk... because we will be changing the contents as we go.

Creating a regex with Regex101, we get a solution. You may want to try it yourself before looking at this:

import os
import re


pattern = r'(.*)(\\|/)(\d\d\d\d)(\\|/)(\w+)(\.txt)'
             # Note r'..' means raw, or take backslashes literally so the regex is correct.
filenames = [ os.path.join(dir_, name)
              for (dir_, _, names) in os.walk('.')
                  for name in names ]
             # Note 'dir_' because dir is reserved word
             # Note '_' as pythonic way of saying 'an ignored value'
             # Note for loops are in same order in list comprehension as they would be in code

for filename in filenames:
    m = re.match(pattern, filename)
    if m:
        front, sep1, year, sep2, name, ext = m.groups()
        new_filename = f'{front}{sep1}{name}-{year}{ext}'
        # print(f'rename {filename} to {new_filename}')
        os.rename(filename, new_filename)

Keep Hacking! Keep notes.

查看更多
登录 后发表回答