當網盤文件超過100G的時候,找文件就有點苦惱了,不記得放在什么文件夾,也不記得名字,就想着從目錄着手。
現在百度網盤還未推出目錄功能,這里就套用網上推薦的查詢目錄的方式。后面附有代碼。
整體思路
查看網盤緩存數據庫文件
百度網盤在本地有個數據庫文件BaiduYunCacheFileV0.db
,里面存放着文件路徑和文件名等信息,兩者結合提取出目錄信息。該文件可以用Navicat Premium 15打開。
代碼分析
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import asksaveasfilename
from tkinter.ttk import *
import sqlite3
這里用到了用於GUI圖形界面開發的庫,Tkinter 模塊(Tk 接口),其中Tkinter filedialog是文件對話框控件。由於tkinter模塊下的組件,整體風格較老較丑,同時也導入了組件更加美觀、功能更加強大的ttk 組件。ttk新增了 LabeledScale( 帶標簽的Scale)、Notebook( 多文檔窗口)、Progressbar(進度條)、Treeview(數)等組件。
def select_db_file():
db_file = askopenfilename(title="請選擇BaiduYunCacheFileV0.db文件",filetypes=[('db', '*.db')])
db.set(db_file)
def select_save_file():
save_file = asksaveasfilename(filetypes=[('文件', '*.txt')])
f.set(save_file+".txt")
StringVar的作用,我們在使用界面編程的時候,有些時候是需要跟蹤變量的值的變化,以保證值的變更隨時可以顯示在界面上。由於python無法做到這一點,所以使用了tcl的相應的對象,也就是StringVar、BooleanVar、DoubleVar、IntVar
- StringVar類型需要通過
StringVar.set()
寫入string字符串內容。 - StringVar類型需要通過
StringVar.get()
讀取內容,返回一個string字符串
askopenfilename
返回文件名,是string字符串類型
select_db_file()
函數巧妙的是,它把StringVar變量的聲明寫在了函數的外面且后面出現,而不是函數內部,呀呀,就是不能寫在函數內部,在函數外面才是全局變量。
當然也可以理解為回調函數,當按鈕被點擊時,變量就存在了,不用擔心它聲明在后面
核心函數
def write_file(file_dict,f,item,gap=""):
if item=="/":
f.write("━" + "/" + "\n")
for i in file_dict["/"]:
f.write("┣" + "━" + i + "\n")
i = item + i + "/"
if i in file_dict:
write_file(file_dict,f,i, gap="┣━")
else:
gap = "┃ " + gap
for i in file_dict[item]:
f.write(gap + i + "\n")
i = item + i + "/"
if i in file_dict:
write_file(file_dict,f,i,gap)
遞歸函數write_file(file_dict,f,item,gap="")
,參數分別是存放路徑和對應文件的字典file_dict
,f是待寫入內容的txt文件,item是路徑,gap是間隙
函數主體分析:如果路徑item是最外層的路徑,就將最外層路徑對應的文件名,寫入到f文件中,然后根據文件名重新賦值一個新路徑,判斷這個新路徑是否在字典中,如果在,就遞歸調用該函數,檢查文件名是否是文件夾(也就是文件名包裝后的新路徑在字典中)
如果路徑不是根路徑,每次調用函數gap會變化,將新路徑對應的文件名,寫入到f文件中,然后在文件名前面加上上一級路徑后面加上/,賦值一個新路徑,在字典中檢查,也就是判斷該文件名變成路徑后,是否還有下一級路徑,如果字典中有它
就表示有下一級路徑,然后繼續調用該函數。
連接數據庫提取內容
def create_baiduyun_filelist():
file_dict = {}
conn = sqlite3.connect(db.get())
cursor = conn.cursor()
cursor.execute("select * from cache_file")
while True:
value = cursor.fetchone()
if not value:
break
path = value[2]
name = value[3]
size = value[4]
isdir = value[6]
if path not in file_dict:
file_dict[path] = []
file_dict[path].append(name)
else:
file_dict[path].append(name)
with open(f.get(),"w",encoding='utf-8') as fp:
write_file(file_dict,fp,"/")
conn.close()
conn = sqlite3.connect(db.get())
連接數據庫,db是StringVar類型,需要通過db.get()
讀取db里的內容,返回string類型的字符串,這里是地址+數據庫文件名
cursor = conn.cursor()
使用 cursor() 方法創建一個游標對象,游標對象用於執行查詢和獲取結果
cursor.execute("select * from cache_file")
使用 execute() 方法執行 SQL 查詢,SQL語句和BaiduYunCacheFileV0.db
里的表格結構有關系,它里面有張叫cache_file
的表
value = cursor.fetchone()
fetchone() 獲取下一個查詢結果集。結果集是一個對象
conn.close()
關閉數據庫連接
主函數
root = Tk()
root.title('百度雲文件列表生成工具')
db_select = Button(root, text=' 選擇DB文件 ',command=select_db_file)
db_select.grid(row=1,column=1,sticky=W,padx=(2,0),pady=(2,0))
db = StringVar()
db_path = Entry(root,width=80,textvariable = db)
db_path['state'] = 'readonly'
db_path.grid(row=1,column=2,padx=3,pady=3,sticky=W+E)
save_path = Button(root, text='選擇保存地址',command=select_save_file)
save_path.grid(row=2,column=1,sticky=W,padx=(2,0),pady=(2,0))
f = StringVar()
file_path = Entry(root,width=80,textvariable = f)
file_path['state'] = 'readonly'
file_path.grid(row=2, column=2,padx=3,pady=3,sticky=W+E)
create_btn = Button(root, text='生成文件列表',command=create_baiduyun_filelist)
create_btn.grid(row=3,column=1,columnspan=2,pady=(0,2))
root.columnconfigure(2, weight=1)
root.mainloop()
root = Tk()
調用窗口函數,實例化一個窗口對象
root.title('百度雲文件列表生成工具')
窗口最頂部顯示的文字
db_select = Button(root, text=' 選擇DB文件 ',command=select_db_file)
在窗口上創建一個button,調用一個按鈕,command代表點擊按鈕發生的事件
padx,pady:與之並列的組件之間的間隔,x方向和y方向,默認單位是像素
db_select.grid(row=1,column=1,sticky=W,padx=(2,0),pady=(2,0))
設置按鈕的位置,在第一行第一列,padx=(2,0) ,與之並列的組件之間的間隔,水平方向上,button與左邊的組件,距離是2個像素,與右邊的組件,距離是0像素。
如果不調用Button的grid函數,它將不會顯示。sticky=W靠左邊。
sticky:有點類似於 pack() 方法的 anchor 選項,同樣支持 N(北,代表上)、E(東,代表右)、S(南,代表下)、W(西,代表左)、NW(西北,代表左上)、NE(東北,代表右上)、SW(西南,代表左下)、SE(東南,代表右下)、CENTER(中,默認值)這些值。
db = StringVar()
StringVar是Tk庫內部定義的字符串變量類型,改變StringVar,按鈕上的文字也隨之改變。
db_path = Entry(root,width=80,textvariable = db)
TKinter輸入類(TKinter文本框)獲取用戶輸入,TKinter Entry類創建文本框,把變量db綁定到Entry
db_path['state'] = 'readonly'
變量db綁定Entry后,Entry狀態變為只讀
root.columnconfigure(2, weight=1)
列屬性設置
root.mainloop()
此函數調用窗口的無限循環,因此窗口將等待任何用戶交互,直到我們將其關閉。
grid()方法相關參數
選項 | 說明 | 取值范圍 |
---|---|---|
column | 單元格的列號 | 從0開始的正整數column |
columnspan | 跨列,跨越的列數 | 正整數 |
row | 單元格的行號 | 從0開始的正整數 |
rowspan | 跨行,跨越的行數 | 正整數 |
ipadx, ipady | 設置子組件之間的間隔,x方向或者y方向,默認單位為像素 | 非負浮點數,默認0.0 |
padx,pady | 與之並列的組件之間的間隔,x方向或者y方向,默認單位是像素 | 非負浮點數,默認0.0 |
sticky | 組件緊貼所在單元格的某一角,對應於東南西北中以及4個角 | N/S/W/E, NW/SW/SE/NE, CENTER(默認) |
整體代碼
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import asksaveasfilename
from tkinter.ttk import *
import sqlite3
def select_db_file():
db_file = askopenfilename(title="請選擇BaiduYunCacheFileV0.db文件",filetypes=[('db', '*.db')])
db.set(db_file)
def select_save_file():
save_file = asksaveasfilename(filetypes=[('文件', '*.txt')])
f.set(save_file+".txt")
def write_file(file_dict,f,item,gap=""):
if item=="/":
f.write("━" + "/" + "\n")
for i in file_dict["/"]:
f.write("┣" + "━" + i + "\n")
i = item + i + "/"
if i in file_dict:
write_file(file_dict,f,i, gap="┣━")
else:
gap = "┃ " + gap
for i in file_dict[item]:
f.write(gap + i + "\n")
i = item + i + "/"
if i in file_dict:
write_file(file_dict,f,i,gap)
def create_baiduyun_filelist():
file_dict = {}
conn = sqlite3.connect(db.get())
cursor = conn.cursor()
cursor.execute("select * from cache_file")
while True:
value = cursor.fetchone()
if not value:
break
path = value[2]
name = value[3]
size = value[4]
isdir = value[6]
if path not in file_dict:
file_dict[path] = []
file_dict[path].append(name)
else:
file_dict[path].append(name)
with open(f.get(),"w",encoding='utf-8') as fp:
write_file(file_dict,fp,"/")
conn.close()
root = Tk()
root.title('百度雲文件列表生成工具')
db_select = Button(root, text=' 選擇DB文件 ',command=select_db_file)
db_select.grid(row=1,column=1,sticky=W,padx=(2,0),pady=(2,0))
db = StringVar()
db_path = Entry(root,width=80,textvariable = db)
db_path['state'] = 'readonly'
db_path.grid(row=1,column=2,padx=3,pady=3,sticky=W+E)
save_path = Button(root, text='選擇保存地址',command=select_save_file)
save_path.grid(row=2,column=1,sticky=W,padx=(2,0),pady=(2,0))
f = StringVar()
file_path = Entry(root,width=80,textvariable = f)
file_path['state'] = 'readonly'
file_path.grid(row=2, column=2,padx=3,pady=3,sticky=W+E)
create_btn = Button(root, text='生成文件列表',command=create_baiduyun_filelist)
create_btn.grid(row=3,column=1,columnspan=2,pady=(0,2))
root.columnconfigure(2, weight=1)
root.mainloop()
運行結果
參考資料:
Python官方手冊:https://docs.python.org/zh-cn/3.8/library/tkinter.ttk.html