使用Python根据文件列表将文件复制到指定目录
我有一堆文件放在一个文件夹里,现在想把它们整理到子文件夹里。
这个文件夹的结构(也就是哪些文件放在哪个文件夹里)在一个文件列表中指定,内容大概是这样的:
目录:音乐\
-> 01-某首歌1.mp3
-> 02-某首歌2.mp3
-> 03-某首歌3.mp3
目录:图片\
-> 01-某张图片1.jpg
-> 02-某张图片2.jpg
......................
我在想把这些数据(目录名和文件名)提取出来,存到一个字典里,字典的样子大概是这样的:
dictionary = {'Music': (01-some_song1.mp3, 02-some_song2.mp3,
03-some_song3.mp3),
'Images': (01-some_image1.jpg, 02-some_image2.jpg),
......................................................
}
然后我就可以把文件复制或移动到它们各自的文件夹里。
我已经提取了目录名,并创建了空的文件夹。
对于字典的值,我试着通过以下方式获取一个列表的列表:
def get_values(file):
values = []
tmp = []
pattern = re.compile(r'^-> (.+?)$')
for line in file:
if line.strip().startswith('->'):
match = re.search(pattern, line.strip())
if match:
tmp.append(match.group(1))
elif line.strip().startswith('Directory'):
values.append(tmp)
del tmp[:]
return values
但是这似乎不太对。values
列表中的每个列表都重复包含同样的四个文件名。
我哪里出错了呢?
我还想知道有没有其他方法可以做到这一切?我相信一定有更好、更简单、更干净的方法。
3 个回答
如果你使用collections.defaultdict(list),你会得到一个字典,这个字典的值是列表。如果找不到某个键,它会自动添加这个键,并且值是一个空列表,这样你就可以直接开始往这个列表里添加内容了。这行代码就是这么干的:
d[dir].append(match.group(1))
它会创建一个目录名作为键,如果这个键不存在,就会把找到的文件名添加到这个列表里。
顺便说一下,如果你在使用正则表达式时遇到问题,可以尝试加上调试标志来创建它们。我记不清具体的名字了,但数字是128。所以如果你这样做:
file_regex = re.compile(r'^-> (.+?)$', 128)
你会得到额外的输出:
at at_beginning
literal 45
literal 62
literal 32
subpattern 1
min_repeat 1 65535
any None
at at_end
你可以看到有一个开始行匹配加上'-> '(对应45 62 32),然后是一个重复的任意模式和行尾匹配。这对调试非常有帮助。
代码:
from __future__ import with_statement
import re
import collections
def get_values(file):
d = collections.defaultdict(list)
dir = ""
dir_regex = re.compile(r'^Directory: (.+?)\\$')
file_regex = re.compile(r'\-\> (.+?)$')
with open(file) as f:
for line in f:
line = line.strip()
match = dir_regex.search(line)
if match:
dir = match.group(1)
else:
match = file_regex.search(line)
if match:
d[dir].append(match.group(1))
return d
if __name__ == '__main__':
d = get_values('test_file')
for k, v in d.items():
print k, v
结果:
Images ['01-some_image1.jpg', '02-some_image2.jpg']
Music ['01-some_song1.mp3', '02-some_song2.mp3', '03-some_song3.mp3']
我觉得问题的原因是你总是使用同一个列表。
del tmp[:]
这个命令只是清空了列表,但并没有创建一个新的列表。在你的情况下,你需要通过调用 tmp = []
来创建一个新的列表。
下面这个修复方法应该可以解决问题(我没有测试过)。
def get_values(file): values = [] tmp = [] pattern = re.compile(r'^-> (.+?)$') for line in file: if line.strip().startswith('->'): match = re.search(pattern, line.strip()) if match: tmp.append(match.group(1)) elif line.strip().startswith('Directory'): values.append(tmp) tmp = [] return values
不需要使用正则表达式
d = {}
for line in open("file"):
line=line.strip()
if line.endswith("\\"):
directory = line.split(":")[-1].strip().replace("\\","")
d.setdefault(directory,[])
if line.startswith("->"):
song=line.split(" ")[-1]
d[directory].append(song)
print d
输出
# python python.py
{'Images': ['01-some_image1.jpg', '02-some_image2.jpg'], 'Music': ['01-some_song1.mp3', '02-some_song2.mp3', '03-some_song3.mp3']}