【问题标题】:Batch rename part of a filename from a lookup file从查找文件批量重命名文件名的一部分
【发布时间】:2013-01-17 22:30:09
【问题描述】:

编辑:我的最终解决方案见底部

我有一个包含 ~12,700 个文本文件的目录。

他们有这样的名字:

1 - Re/Report Novenator 公开呼吁埋葬 - Lizbett 于 2009 年 9 月 10 日星期四.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__'

【问题讨论】:

标签: python dictionary rename


【解决方案1】:

这在 Python 中应该非常简单,只需使用 csvos 模块即可。

Python 有一个名为 dict 的内置 dictionary type,可用于在处理时将 ​​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 指出的那样,按照我上面的说明,有可能覆盖现有文件。几种可能的策略:

  1. 使用os.rename() 将重命名的文件版本移动到不同的目录(例如当前目录的子目录,或者更好的是使用tempfile.mkdtemp() 创建的临时目录。一旦所有文件都被重命名,使用os.rename 将文件从临时目录移动到当前目录。
  2. 为新文件名添加扩展名,例如.tmp,假设选择的扩展名不会引起其他冲突。完成所有重命名后,使用第二个循环重命名文件以排除 .tmp 扩展名。

【讨论】:

  • @TheodrosZelleke:你说得很好。我不确定它是否值得投反对票,但我刚刚编辑了答案以说明这一点,因为根据示例数据,命名冲突是合理的。
  • 我撤回了反对票。我也将反对票理解为表明答案需要改进的一种手段(这是错误的解释吗?)。当答案得到改善时,我总是收回反对票。我很少投反对票,但在这种情况下,我认为 OP 丢失数据存在一些真正的危险......根据个人经验,我知道这种情况发生的速度有多快;)
  • @ig0774 我尽我所能地尝试了,虽然它似乎很好地成对加载了东西,但在那之后它似乎就坏了。如果它是一个快速修复,任何额外的帮助将不胜感激。
【解决方案2】:

这是我最终与朋友一起锻炼的结果,如果有人找到并寻找它:

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)

【讨论】:

    猜你喜欢
    • 2018-07-23
    • 1970-01-01
    • 2011-05-07
    • 2013-12-19
    • 2020-01-29
    • 2017-04-20
    • 2019-02-09
    • 1970-01-01
    相关资源
    最近更新 更多