重新排列嵌套目录
Rearranging nested directory
我有一个结构如下的文件夹系统:
folderA
- folder1
- file1A.txt
- folder2
- file2A.txt
- folder3
- file3A.txt
folderB
- folder1
- file1B.txt
- folder2
- file2B.txt
- folder3
- file3B.txt
我想更改顺序,使字母文件夹上方的编号文件夹为:
folder1
- folderA
- file1A.txt
- folderB
- file1B.txt
folder2
- folderA
- file2A.txt
- folderB
- file2B.txt
folder3
- folderA
- file3A.txt
- folderB
- file3B.txt
这里有一段代码构建了初始目录结构的MWE:
import os
import shutil
import string
root_dir = os.getcwd()
os.chdir('/home/alletro/Tc-97/tools')
os.makedirs('master', exist_ok=True)
os.chdir('master')
master_dir = os.getcwd()
top_tier = [f'folder{i}' for i in range(1,4)]
second_tier = [f'folder{i}' for i in list(string.ascii_uppercase)[:4]]
for folder in top_tier:
os.chdir(master_dir)
os.makedirs(folder, exist_ok=True)
os.chdir(folder)
fold_dir = os.getcwd()
for sub_folder in second_tier:
os.chdir(fold_dir)
os.makedirs(sub_folder, exist_ok=True)
os.chdir(sub_folder)
os.mknod("newfile.txt")
os.chdir(root_dir)
我找到了一个解决方案,可以获取目录树的字典:
def get_directory_structure(rootdir):
"""
Creates a nested dictionary that represents the folder structure of rootdir
"""
dir = {}
rootdir = rootdir.rstrip(os.sep)
start = rootdir.rfind(os.sep) + 1
for path, dirs, files in os.walk(rootdir):
folders = path[start:].split(os.sep)
subdir = dict.fromkeys(files)
parent = reduce(dict.get, folders[:-1], dir)
parent[folders[-1]] = subdir
return dir
然而,我正在努力寻找从这里获取它的位置。
以下对我有用。有四个部分:
- 获取所有文件路径的列表。
- 使用该列表创建所需子文件夹的列表。
- 创建子文件夹并将文件移入其中。
- 删除旧的文件层次结构。
第 1 部分: 获取文件路径列表。
import os
import glob
import shutil
all_files = [filename for filename in glob.iglob('**/*.txt', recursive=True)]
第 2 部分:使用文件名创建子文件夹列表。
# Function that takes a filename and returns desired subfolder and file paths as tuple.
def get_full_path(file):
num = file[-6]
let = file[-5]
file_name = file.split('/')[-1]
subfolders = f'folder{num}/folder{let}/'
file_path = f'folder{num}/folder{let}/{file_name}'
return subfolders, file_path
# Call the function on each file to get all subfolders and file paths.
subfolders = []
full_paths = []
for file in all_files:
subfolder, full_path = get_full_path(file)
subfolders.append(subfolder), full_paths.append(full_path)
第 3 部分:创建所有子文件夹,将所有文件移入其中。
for i in range(len(all_files)):
os.makedirs(subfolders[i])
os.rename(all_files[i], full_paths[i])
第 4 部分:删除原来的文件夹和子文件夹。
old_folders = [x for x in os.listdir() if x[-1] in ['A', 'B', 'C']]
for folder in old_folders:
shutil.rmtree(folder, ignore_errors=False, onerror=None)
如果您有文件夹 'C' 之外的文件夹,您需要在第 4 部分中扩展 in ['A', 'B', 'C']
列表。否则这应该任意扩展。
如果您有任何问题,请告诉我,祝项目的其余部分一切顺利!
这是一个不采用特定文件夹名称的解决方案:
from pathlib import Path
def switch_parts(path):
one, two, three, four = path.parts
return Path(one, three, two, four)
# generate new paths
files = Path('master').glob('**/*.txt')
rearranged = [switch_parts(f) for f in files]
# create new folders and move files
for old, new in zip(files, rearranged):
new.parent.mkdir(parents=True, exist_ok=True)
old.rename(new)
# clean up old folders
for old in files:
old.parent.rmdir()
try:
old.parent.parent.rmdir()
except OSError:
pass # will be deleted eventually
你可以先获取所有文件的路径,然后使用递归创建新结构:
import os, shutil, collections
#generator function that finds all file paths in the target directory
def get_files(d = os.getcwd(), p = None):
for i in os.listdir(d):
if os.path.isdir(_d:=os.path.join(d, i)):
yield from get_files(d = _d, p = ([] if p is None else p)+[i])
else:
yield ([] if p is None else p)+[i]
#group all reversed file paths from the function above on the leading dir name
def new_structure(d, p = []):
_dir = collections.defaultdict(list)
for a, b, c in d:
if not a:
shutil.copyfile(c, os.path.join(os.getcwd(), *p, b))
else:
_dir[a[0]].append((a[1:], b, c))
for a, b in _dir.items():
os.mkdir(os.path.join(os.getcwd(), *(_p:=p+[a])))
new_structure(b, p = _p)
r = [[a[::-1], b, os.path.join(*a, b)] for *a, b in get_files()]
new_structure(r)
#remove old structure
for (*_, a), _, _ in r:
if os.path.isdir(a):
shutil.rmtree(a, ignore_errors=False, onerror=None)
此解决方案适用于任何深度的目录以及完全任意的目录和文件名。
我有一个结构如下的文件夹系统:
folderA
- folder1
- file1A.txt
- folder2
- file2A.txt
- folder3
- file3A.txt
folderB
- folder1
- file1B.txt
- folder2
- file2B.txt
- folder3
- file3B.txt
我想更改顺序,使字母文件夹上方的编号文件夹为:
folder1
- folderA
- file1A.txt
- folderB
- file1B.txt
folder2
- folderA
- file2A.txt
- folderB
- file2B.txt
folder3
- folderA
- file3A.txt
- folderB
- file3B.txt
这里有一段代码构建了初始目录结构的MWE:
import os
import shutil
import string
root_dir = os.getcwd()
os.chdir('/home/alletro/Tc-97/tools')
os.makedirs('master', exist_ok=True)
os.chdir('master')
master_dir = os.getcwd()
top_tier = [f'folder{i}' for i in range(1,4)]
second_tier = [f'folder{i}' for i in list(string.ascii_uppercase)[:4]]
for folder in top_tier:
os.chdir(master_dir)
os.makedirs(folder, exist_ok=True)
os.chdir(folder)
fold_dir = os.getcwd()
for sub_folder in second_tier:
os.chdir(fold_dir)
os.makedirs(sub_folder, exist_ok=True)
os.chdir(sub_folder)
os.mknod("newfile.txt")
os.chdir(root_dir)
我找到了一个解决方案,可以获取目录树的字典:
def get_directory_structure(rootdir):
"""
Creates a nested dictionary that represents the folder structure of rootdir
"""
dir = {}
rootdir = rootdir.rstrip(os.sep)
start = rootdir.rfind(os.sep) + 1
for path, dirs, files in os.walk(rootdir):
folders = path[start:].split(os.sep)
subdir = dict.fromkeys(files)
parent = reduce(dict.get, folders[:-1], dir)
parent[folders[-1]] = subdir
return dir
然而,我正在努力寻找从这里获取它的位置。
以下对我有用。有四个部分:
- 获取所有文件路径的列表。
- 使用该列表创建所需子文件夹的列表。
- 创建子文件夹并将文件移入其中。
- 删除旧的文件层次结构。
第 1 部分: 获取文件路径列表。
import os
import glob
import shutil
all_files = [filename for filename in glob.iglob('**/*.txt', recursive=True)]
第 2 部分:使用文件名创建子文件夹列表。
# Function that takes a filename and returns desired subfolder and file paths as tuple.
def get_full_path(file):
num = file[-6]
let = file[-5]
file_name = file.split('/')[-1]
subfolders = f'folder{num}/folder{let}/'
file_path = f'folder{num}/folder{let}/{file_name}'
return subfolders, file_path
# Call the function on each file to get all subfolders and file paths.
subfolders = []
full_paths = []
for file in all_files:
subfolder, full_path = get_full_path(file)
subfolders.append(subfolder), full_paths.append(full_path)
第 3 部分:创建所有子文件夹,将所有文件移入其中。
for i in range(len(all_files)):
os.makedirs(subfolders[i])
os.rename(all_files[i], full_paths[i])
第 4 部分:删除原来的文件夹和子文件夹。
old_folders = [x for x in os.listdir() if x[-1] in ['A', 'B', 'C']]
for folder in old_folders:
shutil.rmtree(folder, ignore_errors=False, onerror=None)
如果您有文件夹 'C' 之外的文件夹,您需要在第 4 部分中扩展 in ['A', 'B', 'C']
列表。否则这应该任意扩展。
如果您有任何问题,请告诉我,祝项目的其余部分一切顺利!
这是一个不采用特定文件夹名称的解决方案:
from pathlib import Path
def switch_parts(path):
one, two, three, four = path.parts
return Path(one, three, two, four)
# generate new paths
files = Path('master').glob('**/*.txt')
rearranged = [switch_parts(f) for f in files]
# create new folders and move files
for old, new in zip(files, rearranged):
new.parent.mkdir(parents=True, exist_ok=True)
old.rename(new)
# clean up old folders
for old in files:
old.parent.rmdir()
try:
old.parent.parent.rmdir()
except OSError:
pass # will be deleted eventually
你可以先获取所有文件的路径,然后使用递归创建新结构:
import os, shutil, collections
#generator function that finds all file paths in the target directory
def get_files(d = os.getcwd(), p = None):
for i in os.listdir(d):
if os.path.isdir(_d:=os.path.join(d, i)):
yield from get_files(d = _d, p = ([] if p is None else p)+[i])
else:
yield ([] if p is None else p)+[i]
#group all reversed file paths from the function above on the leading dir name
def new_structure(d, p = []):
_dir = collections.defaultdict(list)
for a, b, c in d:
if not a:
shutil.copyfile(c, os.path.join(os.getcwd(), *p, b))
else:
_dir[a[0]].append((a[1:], b, c))
for a, b in _dir.items():
os.mkdir(os.path.join(os.getcwd(), *(_p:=p+[a])))
new_structure(b, p = _p)
r = [[a[::-1], b, os.path.join(*a, b)] for *a, b in get_files()]
new_structure(r)
#remove old structure
for (*_, a), _, _ in r:
if os.path.isdir(a):
shutil.rmtree(a, ignore_errors=False, onerror=None)
此解决方案适用于任何深度的目录以及完全任意的目录和文件名。