将文件名称更改为父文件夹名称

Changing name of the file to parent folder name

我的目录中有一堆文件夹。其中每个都有一个文件,您可以在下面看到:

不管文件扩展名是什么,我都希望这个文件的名称与其父文件夹完全相同,即在考虑文件夹 2023-10-18 时,我希望将文件放在里面 2023-10-18而不是掩星....

我尝试使用此线程重命名多个文件:

这里

https://pynative.com/python-rename-file/#:~:text=Use%20rename()%20method%20of,function%20to%20rename%20a%20file.

但不幸的是,在应用了这样的代码之后:

 import os
 from pathlib import Path
 pth = Path(__file__).parent.absolute()
 files = os.listdir(pth)

 for file in files:
 os.rename(os.pth.join(pth, file), os.pth.join(pth, '' + file + '.kml'))

我有一个错误:

AttributeError: 模块 'os' 没有属性 'pth'

此处描述:

AttributeError: 'module' object has no attribute

这对我来说只是一点点,因为我是 Python 的新手。

如何自动更改这些目录中所有文件的名称?我需要与目录名相同的文件名。可能吗?

更新:

经过下面的提示,我的代码现在看起来像这样:

 import os
 from pathlib import Path
 pth = Path(__file__).parent.absolute()
 files = os.listdir(pth)

 for file in files:
  os.rename(os.path.join(pth, file), os.path.join(pth, '' + file + '.kml'))

但不是更改文件夹列表中的文件名,而是将给定目录中的所有文件更改为 .kml。 如何访问文件夹列表中的各个文件?

您需要将它保存到一个文件中(例如,rename.py)并使用带有附加参数的 python 解释器调用它——您要访问的父目录的名称重命名其子目录中的文件。例如:“python rename.py parent_dir”。目录名可以是绝对的或相对的。作为附加参数,您还可以在重命名文件时指定用于保存扩展名的密钥(0 - 不保存,1 - 保存)。默认情况下不保存扩展名。这是保存扩展名的示例:“python rename.py parent_dir 1”.

rename.py 中的脚本:

import os
import sys

def rename_first_file_in_dir(dir_path, new_file_name, keep_extension = False):
  for current_file_name in os.listdir(dir_path):
    current_file_path = os.path.join(dir_path, current_file_name) # full or relative path to the file in dir
    if not os.path.isfile(current_file_path):
      break
    # rename only base name of file to the name of directory
    if keep_extension:
      file_extension = os.path.splitext(current_file_name)[1]
      if len(file_extension) > 0:
        new_file_name = new_file_name + file_extension 
        
    new_file_path = os.path.join(dir_path, new_file_name)
    print("File " + current_file_name + " renamed to " + new_file_name + " in " + os.path.basename(dir_path) + " directory");
    os.rename(current_file_path, new_file_path)
    # exit after first processed file
    break

if len(sys.argv) < 2:
  print("Usage: python " + os.path.basename(__file__) + " <directory> [keep_files_extensions]") # help for usage
  exit(0)
scan_dir = sys.argv[1]
keep_extension = False if len(sys.argv) < 3 else not (int(sys.argv[2]) == 0) # optional parameter 0 - False, 1 - True, by default - False
if not os.path.exists(scan_dir):
  print("Error: directory " + scan_dir + " does not exists")
  exit(-1)
if not os.path.isdir(scan_dir):
  print("Error: file " + scan_dir + " is not a directory")
  exit(-1)
print("Scanning directory " + scan_dir)
for file_name in os.listdir(scan_dir): # walk through directory
  file_path = os.path.join(scan_dir, file_name)
  if os.path.isdir(file_path):
    rename_first_file_in_dir(file_path, file_name, keep_extension)

这里是使用 pathlib 模块的示例代码。一定要修改base_folder.

解决方案 1

"""
rename_filename.py

Rename filename inside the folders.




Example:

base_folder
F:/Tmp/s13/

sub_folders
F:/Tmp/s13/2022-05-01
F:/Tmp/s13/2022-08-01

files under subfolder
F:/Tmp/s13/2022-05-01/aa.txt
F:/Tmp/s13/2022-08-01/bb.txt


Usage:

Be sure to modify first the "base_folder" value in the main()

command lines:
python rename_filename.py or
python3 rename_filename.py
"""

from pathlib import Path  # python version >= 3.4


def rename_file(base_folder):
    """
    Rename the filename of the file under the sub-folders of the base_folder.
    """
    base_path = Path(base_folder).glob('*/*')

    # Get the file path in every sub-folder.
    for file in base_path:
        # print(file)
        sub_folder_abs_path = file.parent  # sub-folder path, F:/Tmp/s13/2022-05-01
        sub_folder_name = file.parent.name  # sub-folder name, 2022-05-01

        # Rename the file to sub-folder name.
        new_file = Path(sub_folder_abs_path, sub_folder_name)
        file.rename(new_file)


def main():
    # Change the base folder according to your case.
    base_folder = 'F:/Tmp/s13/'
    rename_file(base_folder)


if __name__ == '__main__':
    main()

解决方案 2
使用 pathlib 和 argparse 模块。它提供 --base-folder 选项来定位基本文件夹,无需修改源。查看用法。

"""
rename_file.py

Rename filename inside the folders.




Example:

base_folder
F:/Tmp/s13/

sub_folders
F:/Tmp/s13/2022-05-01
F:/Tmp/s13/2022-08-01

files under subfolder
F:/Tmp/s13/2022-05-01/aa.txt
F:/Tmp/s13/2022-08-01/bb.txt


Usage:

command line:

python rename_file.py --base-folder "F:/Tmp/s13/"
"""

from pathlib import Path  # python version >= 3.4
import argparse


def rename_file(base_folder):
    """
    Rename the filename of the file under the sub-folders of the base_folder.
    """
    base_path = Path(base_folder).glob('*/*')

    # Get the file path in every sub-folder.
    for file in base_path:
        # print(file)
        sub_folder_abs_path = file.parent  # sub-folder path, F:/Tmp/s13/2022-05-01
        sub_folder_name = file.parent.name  # sub-folder name, 2022-05-01

        # Rename the file to sub-folder name.
        new_file = Path(sub_folder_abs_path, sub_folder_name)
        file.rename(new_file)


def main():
    parser = argparse.ArgumentParser(description='Rename file to sub-folder name.')
    parser.add_argument('--base-folder', required=True,
                        help='the base folder, example: --base-folder "f:/tmp/so13/"')

    args = parser.parse_args()
    rename_file(args.base_folder)


if __name__ == '__main__':
    main()

用法:
打开命令提示符和 CD 到 rename_file.py.

的位置
python rename_file.py --base-folder "f:/tmp/s13/"

因此,根据我的理解,每个文件夹中都有一个文件。您想重命名具有相同文件夹名称的文件并保留扩展名。

import os

# Passing the path to your parent folders
path = r'D:\bat4'

# Getting a list of folders with date names
folders = os.listdir(path)

for folder in folders:
    files = os.listdir(r'{}\{}'.format(path, folder))

    # Accessing files inside each folder
    for file in files:

        # Getting the file extension
        extension_pos = file.rfind(".")
        extension = file[extension_pos:]

        # Renaming your file
        os.rename(r'{}\{}\{}'.format(path, folder, file),
                  r'{}\{}\{}{}'.format(path, folder, folder, extension))

我在自己的文件上试过如下:

这是输出示例:

希望我明白你的意思。 :)

这是一个简单的解决方案,仅使用 osshutil 模块,这两个模块都已预安装。它是 cross-platform 并且对我来说工作得很好而且很快。它还可以处理每个子文件夹中的多个文件。

我认为您可以从评论中理解代码,但如果不是这样,请随时通知我。

import os, shutil
from os.path import * # just to avoid typing "os.path." everywhere

# I am using abspath() here to get the absolute path to the folder.
folder = abspath(input('Enter the main folder: '))

# index through all elements in the main folder that are directories
for subfolder in os.listdir(folder):
    abs_subfolder = join(folder, subfolder) # get the folder's absolute path
    if not isdir(abs_subfolder):
        continue # go to the next element because this one wasn't a folder

    # index through all the files in this subfolder
    for file in os.listdir(abs_subfolder):
        # get the extension of the file to move
        extension = splitext(file)[1]

        new_file_path = abs_subfolder + '.' + extension

        # move the file to its parent directory, and change its name
        shutil.move(join(abs_subfolder, file), new_file_path)

    # delete the directory the files were in
    # you can comment the next line if you don't want that to happen
    os.rmdir(abs_subfolder)

基本上,此代码的作用是对包含所有这些子文件夹及其中的文件的文件夹内的每个目录进行索引。

然后,它搜索每个子文件夹中的每个文件,然后将这些文件移动到主文件夹,同时将它们的名称更改为它们所在的子文件夹。

最后,一旦该子文件夹的每个文件都被移动并重命名,它就会删除空目录。如果您不希望这种情况发生,您可以只评论最后一行。

希望对您有所帮助。


另外,我不知道你的代码是从哪里来的,但是你到处都是 .kml 的原因是因为代码所做的就是将所有文件夹重命名为它们的名称 + .kml。它甚至不涉及子文件夹中的文件。我不认为我可以让你的代码按你想要的方式工作而不改变其中的几乎所有内容。


如果您想了解有关 os 模块的更多信息,请查看 this page as well as this one for os.path. I would say shutil is just a "complement" to the os module, and it shares some similarities with is, but you can see the full documentation here

如果您想总体上学习 Python,我认为 w3schools 是最好的去处。

每一行代码的推理都有注释!每个答案都应该使用iglob,请阅读更多相关信息here!该代码也与后缀无关(.klm 因为后缀不是硬编码的),并且适用于需要此实用程序的任何场景。

只使用了标准的库函数。

最满意的方法:移出目录,重命名,删除目录

import os
from shutil import move
from glob import iglob
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor


# The .py file has to be on the same directory as the folders containing the files!
root = Path(__file__).parent

# Using threading in case the operation becomes I/O bound (many files)
with ThreadPoolExecutor() as executor:
    for file in iglob(str(root / "**" / "*")):
        file = Path(file)

        # The new filename is the name of the directory, and the suffix(es) of the original file
        new_filename = f"{file.parent.name}{''.join(file.suffixes)}"

        # Move AND rename simultaneosly
        executor.submit(move, file, root / new_filename)

        # Delete directory because it is empty, and has no utility; ommit this line if not True
        executor.submit(os.rmdir, file.parent)

不太满意; OP 请求:重命名文件(保留在目录中)

如果您真的只想重命名文件,并将它们保存在各自的目录中:

import os
from shutil import move
from glob import iglob
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor


RENAME_ONLY = True


# The .py file has to be on the same directory as the folders containing the files!
root = Path(__file__).parent

# Using threading in case the operation becomes I/O bound
with ThreadPoolExecutor() as executor:
    for file in iglob(str(root / "**" / "*")):
        file = Path(file)

        # The new filename is the name of the directory, and the suffix(es) of the original file
        new_filename = f"{file.parent.name}{''.join(file.suffixes)}"

        if RENAME_ONLY:
            executor.submit(os.rename, file, file.parent / new_filename)
        else:
            # Move AND rename simultaneosly
            executor.submit(move, file, root / new_filename)

            # Delete directory because it is empty, and has no utility; ommit this line if not True
            executor.submit(os.rmdir, file.parent)

为什么 ''.join(file.suffixes)

有些文件有多个句点;喜欢 abc.x.yz。我们用 file.suffix 得到 .yz,用 ''.join(file.suffixes) 得到 .x.yz;因此我选择使用后者。

这是对 sub-suffixes 的敏感性问题,这通常很重要。例如,.tar.gz 个文件 file.suffix 不会捕获 .tar,这对文件格式不利。