批量重命名文件名的一部分来自查找文件
编辑: 请看下面我的最终解决方案
我有一个大约12,700个文本文件的文件夹。
这些文件的名字像这样:
1 - Re/ Report Novenator public call for bury - by Lizbett on Thu, 10 Sep 2009.txt
文件名前面的数字是递增的,比如文件夹里的最后一个文件名是“12,700 - ”。
不幸的是,这些文件的顺序不是按时间排列的,而我需要它们按时间排序。幸运的是,我有一个单独的CSV文件,其中映射了ID号码,比如上面例子中的1实际上应该是25(因为它前面有24条消息),2应该是8,3应该是1,依此类推,像这样:
OLD_FILEID TIMESORT_FILEID
21 0
23 1
24 2
25 3
我只需要更改文件名中的这个开头数字,其他的都不需要动。我的想法是,打开文件名,检查在破折号前面的数字,然后在CSV文件中查找,把它替换成对应的值,然后用调整后的标题保存文件,再继续下一个文件。
那么,做这个的最佳方法是什么呢?我对Python还是个新手,但玩过一段时间,觉得跟着大多数的指示或建议还是没问题的。谢谢 :)
e: 按照下面的指示尽量去做,我做了这个,但不管用,我也不太确定为什么:
import os
import csv
import sys
#open and store the csv file
with open('timesortmap.csv','rb') as csvfile:
timeReader = csv.reader(csvfile, delimiter = ',', quotechar='"')
#get the list of files
for filename in os.listdir('DiggOutput-TIMESORT/'):
oldID = filename.split(' - ')[0]
newFilename = filename.replace(oldID, timeReader[oldID],1)
os.rename(oldID, newFilename)
我得到的错误是:
TypeError: '_csv.reader' object is not subscriptable
我没有使用DictReader,但这是因为当我使用csv.reader并打印行时,它看起来像这样:
['12740', '12738']
['12742', '12739']
['12738', '12740']
['12737', '12741']
['12739', '12742']
而当我使用DictReader时,它看起来像这样:
{'FILEID-TS': '12738', 'FILEID-OLD': '12740'}
{'FILEID-TS': '12739', 'FILEID-OLD': '12742'}
{'FILEID-TS': '12740', 'FILEID-OLD': '12738'}
{'FILEID-TS': '12741', 'FILEID-OLD': '12737'}
{'FILEID-TS': '12742', 'FILEID-OLD': '12739'}
然后我在终端得到了这个错误:
File "TimeSorter.py", line 16, in <module>
newFilename = filename.replace(oldID, timeReader[oldID],1)
AttributeError: DictReader instance has no attribute '__getitem__'
2 个回答
在Python中,这个操作其实非常简单,只需要用到csv
和os这两个模块。
Python有一个内置的字典类型,叫做dict
,可以用来在处理过程中把csv文件的内容存储在内存中。简单来说,你需要用csv
模块读取csv文件,把每一条记录转换成字典中的一项,通常用OLD_FILEID
字段作为键,用TIMESORT_FILEID
作为值。
接着,你可以用os.listdir()
来获取文件列表,然后用循环一个一个地处理每个文件名。如果你需要过滤掉某些文件,可以看看glob
模块。在循环中,你只需要提取与文件相关的数字,可以用类似下面的方式来实现:
file_number = filename.split(' - ')[0]
然后调用os.rename()
,传入旧文件名和新文件名。新文件名可以用类似下面的方式找到:
new_filename = filename.replace(file_number, file_mapping[file_number], 1)
这里的file_mapping
就是从csv文件创建的字典。这样会把file_number
的第一次出现替换为你映射文件中的数字。
编辑
正如TheodrosZelleke所指出的,按照我上面说的做,有可能会覆盖掉已有的文件。这里有几种可能的解决方案:
- 使用
os.rename()
把重命名后的文件移动到不同的目录(比如当前目录的子目录,或者更好的是,使用tempfile.mkdtemp()
创建一个临时目录)。等所有文件都重命名完后,再用os.rename
把文件从临时目录移动到当前目录。 - 给新文件名加个扩展名,比如
.tmp
,前提是这个扩展名不会引起其他冲突。等所有重命名完成后,再用第二个循环把文件名中的.tmp
扩展名去掉。
这是我和朋友们一起研究出来的,如果有人找到并想了解这个内容的话:
import os
import csv
import sys
IDs = {}
#open and store the csv file
with open('timesortmap.csv','rb') as csvfile:
timeReader = csv.reader(csvfile, delimiter = ',', quotechar='"')
# build a dictionary with the associated IDs
for row in timeReader:
IDs[ row[0] ] = row[1]
# #get the list of files
path = 'DiggOutput-OLDID/'
tmpPath = 'DiggOutput-TIMESORT/'
for filename in os.listdir('DiggOutput-OLDID/'):
oldID = filename.split(' - ')[0]
newFilename = filename.replace(oldID, IDs[oldID])
os.rename(path + filename, tmpPath + newFilename)