Python練習:讀取Apple Plist文件
Plist文件簡介
- ??定義??:Apple公司創建的基于XML結構的文件格式
- ??特點??:采用XML語法組織數據,可存儲鍵值對、數組等結構化信息
- 文件擴展名??:.plist
- 應用場景:
??iOS系統:?? 應用描述文件(權限配置:藍牙/網絡訪問/GameCenter等)IPA安裝包中的配置信息 ??
macOS系統??: .app應用的配置文件 系統偏好設置存儲 ??
蘋果生態?? iTunes音樂播放列表 Xcode項目配置
Python操作庫:plistlib
import plistlib
代碼適配指南(Python 2 → Python 3)
??廢棄方法??(Python 2舊版)
plist = plistlib.read(filename)
??正確方法??(Python 3新版)
with open(filename, 'rb') as plist_file:plist = plistlib.load(plist_file)
注意事項
- 始終使用??二進制模式??(‘rb’)打開文件 Python
- 3.4+ 支持load()/dump()替代舊版API
- macOS內置plutil工具可驗證文件有效性:bash 下運行下面的代碼
plutil -lint Example.plist
下文是練習代碼,其中也包含了畫圖部分
練習代碼:
import re, argparse
import sys
from matplotlib import pyplot
import plistlib
import numpy as np# 找到重復的音樂
def find_duplicates(file_name):print("Find duplicate tracks in %s..." % file_name)with open(file_name, 'rb') as f:plist = plistlib.load(f)# 讀取playlist# 獲取音軌目錄tracks = plist['Tracks']# 創建音軌字典track_names = {}# 結構:{name:(duration,count)}# 遍歷 添加for track_id, track in tracks.items():try:name = track['name']duration = track['Total Time']# 檢查是不是以及在在字典里面了if name in track_names:# 匹配 歌曲名稱和時長if duration // 1000 == track_names['name'][0] // 1000:count = track_names[name][1]track_names[name] = (duration, count + 1)else:# 不匹配的情況下track_names[name] = (duration, count)except:# ignorepass# 保存重復的音軌, name, countdups = []for k, v in track_names.items():if v[1] > 1:dups.append(k, v[1])# 保存到一個文件if len(dups) > 0:print("發現一共有%d個重復的文件, 以及保存到了dup.txt中" % len(dups))else:print("沒有發現任何重復的文件")f = open("dups.txt", "w")for val in dups:f.writable("[%d] %s \n" % (val[0], val[1]))f.close()# 查找多個播放列表中的共同的音軌
def find_common_tracks(file_names):# a list of sets of track namestrack_name_sets = []# 遍歷讀取多個plist文件for file_name in file_names:track_names = set()with open(file_name, 'rb') as f:plist = plistlib.load(f)# 獲取音軌節點tracks = plist.get("Tracks", {})# 遍歷迭代for track_id, track in tracks.items():try:track_names.add(track['Name'])except:# ignorepass# 添加到track_name_sets中track_name_sets.append(track_names)# 交集處理common_tracks = set.intersection(*track_name_sets)# 寫文件if len(common_tracks) > 0:f = open("common.txt", "w")for val in common_tracks:# s = "%s\n" % valf.write(f"{val}\n")f.close()print(f"Track names wirte to common.txt { len(common_tracks)}")else:print("No common tracks!")# 收集歌曲評分和時長
def plot_stats(file_name):# 讀取播放列表with open(file_name, 'rb') as f:plist = plistlib.load(f)tracks = plist['Tracks']# 創建音軌排序和時長ratings = []durations = []for track_id, track in tracks.items():try:ratings.append(track['Album Rating'])durations.append(track['Total Time'])except:# ignorepass# 確保是有效數據if ratings == [] or durations == []:print(f"在文件中%s沒有有效的Album Rating/Total Time 數據 {file_name}")return# scatter plot x= np.array(durations, np.int32) # convert to minutes x = x/60000.0 y = np.array(ratings, np.int32) pyplot.subplot(2, 1, 1) pyplot.plot(x, y, 'o') pyplot.axis([0, 1.05*np.max(x), -1, 110]) pyplot.xlabel('Track duration') pyplot.ylabel('Track rating') # plot histogram pyplot.subplot(2, 1, 2) pyplot.hist(x, bins=20) pyplot.xlabel('Track duration') pyplot.ylabel('Count') # show plot pyplot.show() def main():# create parserdescStr = """This program analyzes playlist files (.xml) exported from iTunes."""parser = argparse.ArgumentParser(description=descStr)# add a mutually exclusive group of argumentsgroup = parser.add_mutually_exclusive_group()# add expected argumentsgroup.add_argument('--common', nargs = '*', dest='plFiles', required=False)group.add_argument('--stats', dest='plFile', required=False)group.add_argument('--dup', dest='plFileD', required=False)# parse argsargs = parser.parse_args()if args.plFiles:# find common tracksfind_common_tracks(args.plFiles)elif args.plFile:# plot statsplot_stats(args.plFile)elif args.plFileD:# find duplicate tracksfind_duplicates(args.plFileD)else:print("These are not the tracks you are looking for.")if __name__ == "__main__":main()
最后這個是畫圖的部分,以后有興趣再研究吧