Python文件操作
假设我有这样的文件夹结构:
rootfolder
|
/ \ \
01 02 03 ....
|
13_itemname.xml
在我的根文件夹下,每个子文件夹代表一个月份,比如 01、02、03。在这些子文件夹里,我有一些文件,它们的命名方式是根据创建的小时和文件名,比如 16_item1.xml、24_item1.xml 等等。你可以猜到,这里有好几个文件,每个文件都是每小时创建的。
现在我想做两件事:
我需要生成一个某个月的文件名列表,比如在 01 这个文件夹里,我有 item1、item2 和 item3。
我需要对每个文件进行筛选,比如对于 item1,我想读取从 01_item1.xml 到 24_item1.xml 的所有文件。
我该如何用 Python 轻松实现这些呢?
3 个回答
假设每个项目的名称都有固定的前缀和后缀,比如前面有3个字符的前缀'01_',后面有4个字符的后缀'.xml',那么你可以这样解决问题的第一部分:
names = set(name[3:-4] for name in os.listdir('01') if name.endswith('.xml')]
这样你就能得到独一无二的项目名称了。
要筛选每个项目,只需查找以该项目名称结尾的文件,如果需要的话可以进行排序。
item_suffix = '_item2.xml'
filtered = sorted(name for name in os.listdir('01') if name.endswith(item_suffix))
我不太确定你具体想做什么,但这里有一些可能对你有用的建议。
创建文件名时,可以用 ("%02d" 这个格式表示在数字前面加零填充)
foldernames = ["%02d"%i for i in range(1,13)]
这行代码会生成从01到12的文件夹名称。
filenames = ["%02d"%i for i in range(1,24)]
这行代码会生成从01到23的文件名。
使用 os.path.join 来构建复杂的路径,这比简单的字符串拼接要好。
os.path.join(foldername,filename)
用 os.path.exists 来检查一个文件是否存在。
if os.path.exists(newname):
print "file already exists"
如果你想列出目录里的内容,可以使用 glob。
from glob import glob
xmlfiles = glob("*.xml")
使用 shutil 来进行更高级的操作,比如创建文件夹或重命名文件。
shutil.move(oldname,newname)
这行代码可以用来移动或重命名文件。
用 basename 可以从完整路径中提取出文件名。
filename = os.path.basename(fullpath)
这行代码会得到文件的名字。
这里有两种方法可以实现你想要的功能(如果我理解正确的话)。一种是用正则表达式,另一种则不使用。你可以选择你喜欢的那种;)
有一点可能看起来像魔法的就是“setdefault”这一行。想要了解它的具体含义,可以查看这个文档。我把理解它的过程留给你自己去探索;)
from os import listdir
from os.path import join
DATA_ROOT = "testdata"
def folder_items_no_regex(month_name):
# dict holding the items (assuming ordering is irrelevant)
items = {}
# 1. Loop through all filenames in said folder
for file in listdir( join( DATA_ROOT, month_name ) ):
date, name = file.split( "_", 1 )
# skip files that were not possible to split on "_"
if not date or not name:
continue
# ignore non-.xml files
if not name.endswith(".xml"):
continue
# cut off the ".xml" extension
name = name[0:-4]
# keep a list of filenames
items.setdefault( name, set() ).add( file )
return items
def folder_items_regex(month_name):
import re
# The pattern:
# 1. match the beginnning of line "^"
# 2. capture 1 or more digits ( \d+ )
# 3. match the "_"
# 4. capture any character (as few as possible ): (.*?)
# 5. match ".xml"
# 6. match the end of line "$"
pattern = re.compile( r"^(\d+)_(.*?)\.xml$" )
# dict holding the items (assuming ordering is irrelevant)
items = {}
# 1. Loop through all filenames in said folder
for file in listdir( join( DATA_ROOT, month_name ) ):
match = pattern.match( file )
if not match:
continue
date, name = match.groups()
# keep a list of filenames
items.setdefault( name, set() ).add( file )
return items
if __name__ == "__main__":
from pprint import pprint
data = folder_items_no_regex( "02" )
print "--- The dict ---------------"
pprint( data )
print "--- The items --------------"
pprint( sorted( data.keys() ) )
print "--- The files for item1 ---- "
pprint( sorted( data["item1"] ) )
data = folder_items_regex( "02" )
print "--- The dict ---------------"
pprint( data )
print "--- The items --------------"
pprint( sorted( data.keys() ) )
print "--- The files for item1 ---- "
pprint( sorted( data["item1"] ) )