使用Python實現一個簡單的文件搜索引擎
文本是關于Python文件操作的基礎和進階知識,包括讀寫文件、文件和目錄管理、錯誤處理、文件路徑操作、文件編碼、處理大文件、臨時文件、文件權限以及一個簡單的文件搜索引擎示例。進階部分涉及了文件模式、緩沖、文件鎖、高級文件搜索技巧、文件系統(tǒng)監(jiān)控、跨平臺文件路徑處理、性能考慮、安全性,以及一個進一步優(yōu)化的文件搜索引擎示例。
基礎
讀寫文件
示例代碼:
# 讀取文件
with open('example.txt', 'r') as file:
content = file.read()
print(content)
# 寫入文件
with open('example.txt', 'w') as file:
file.write('Hello, World!')
無需額外安裝包,Python內置的open函數就可以進行文件的讀寫操作。
文件和目錄管理
示例代碼:
import os
import shutil
# 創(chuàng)建目錄
os.mkdir('new_directory')
# 重命名目錄
os.rename('new_directory', 'renamed_directory')
# 刪除文件
os.remove('old_file.txt')
# 復制文件
shutil.copy('source.txt', 'destination.txt')
# 列出目錄內容
print(os.listdir('.'))
包簡介:
os模塊:提供了豐富的方法用來處理文件和目錄。shutil模塊:提供了一系列對文件和文件集合的高級操作。
錯誤處理
在進行文件操作時,處理潛在的錯誤非常重要。例如,嘗試打開一個不存在的文件會引發(fā)FileNotFoundError。使用try和except語句可以幫助您優(yōu)雅地處理這些情況:
try:
with open('non_existent_file.txt', 'r') as file:
content = file.read()
except FileNotFoundError:
print("文件不存在。")
上下文管理器
Python的with語句提供了一種管理資源的簡潔方式,特別是對于文件操作。使用with可以確保文件在使用后正確關閉,即便在文件操作過程中發(fā)生了異常。
with open('example.txt', 'r') as file:
content = file.read()
print(content)
文件路徑操作
雖然os模塊提供了基本的路徑操作功能,但pathlib模塊提供了一種更面向對象的方式來處理文件路徑。使用pathlib可以使路徑操作更加直觀和易于維護:
from pathlib import Path
# 當前目錄路徑
current_dir = Path('.')
# 列出當前目錄中的所有文件
for file in current_dir.iterdir():
print(file)
# 讀取文件
file_path = current_dir / 'example.txt'
with file_path.open('r') as file:
content = file.read()
文件編碼
當處理文本文件時,考慮文件的編碼非常重要。默認情況下,Python使用系統(tǒng)默認的編碼打開文件,這可能會導致在不同系統(tǒng)之間移植代碼時出現問題。指定編碼可以確保文件正確讀寫:
# 使用UTF-8編碼打開文件
with open('example.txt', 'r', encoding='utf-8') as file:
content = file.read()
處理大文件
對于非常大的文件,一次性讀取它們的內容可能會消耗大量內存。使用迭代器逐行讀取可以減少內存使用:
with open('large_file.txt', 'r') as file:
for line in file:
process(line) # 處理每一行
臨時文件
有時,您可能需要創(chuàng)建臨時文件來存儲數據,這些數據在程序結束后不再需要。tempfile模塊提供了創(chuàng)建臨時文件和目錄的方法:
import tempfile
# 創(chuàng)建臨時文件
with tempfile.TemporaryFile('w+t') as temp_file:
temp_file.write('Hello, World!')
temp_file.seek(0) # 回到文件開頭
print(temp_file.read())
文件權限
在Linux和UNIX系統(tǒng)上,文件權限對于文件安全至關重要。使用os模塊,您可以檢查和修改文件的權限:
import os
# 修改文件權限(只讀)
os.chmod('example.txt', 0o444)
綜合示例——一個簡單的文件搜索引擎
一個文件搜索引擎,允許用戶指定一個根目錄和一個文件名(或部分文件名),然后在該目錄及其所有子目錄中搜索匹配該名稱的文件。
import os
import time
def find_files(directory, filename):
matches = []
# 遍歷根目錄
for root, dirnames, filenames in os.walk(directory):
for name in filenames:
# 檢查文件名是否包含搜索關鍵字
if filename.lower() in name.lower():
matches.append(os.path.join(root, name))
return matches
# 用戶輸入
root_directory = input("請輸入要搜索的根目錄: ")
file_to_find = input("請輸入要搜索的文件名(支持部分匹配): ")
# 記錄開始時間
start_time = time.time()
# 搜索文件
found_files = find_files(root_directory, file_to_find)
# 記錄結束時間
end_time = time.time()
# 輸出結果
print(f"找到 {len(found_files)} 個文件:")
for file in found_files:
print(file)
# 輸出耗時
print(f"搜索耗時: {end_time - start_time:.2f} 秒")
這個腳本使用了os.walk()函數,該函數可以遍歷指定目錄下的所有子目錄。腳本將所有找到的匹配文件的完整路徑添加到一個列表中,并在搜索完成后將這些路徑打印出來。
用戶首先被提示輸入要搜索的根目錄和文件名。然后,腳本會調用find_files函數來執(zhí)行搜索。搜索結果將顯示找到的文件數量以及它們的路徑。
請注意,這個腳本在文件名匹配時不區(qū)分大小寫,因為它使用了.lower()方法來將文件名轉換為小寫。這意味著搜索是大小寫不敏感的。
$ python3 r1.py
請輸入要搜索的根目錄: /DB6/project
請輸入要搜索的文件名(支持部分匹配): index.vue
找到 531 個文件:
/DB6/project/blog/BlogSSR/node_modules/@kangc/v-md-editor/src/components/scrollbar/index.vue
......
搜索耗時: 46.71 秒
進階
文件模式詳解
使用open函數時,可以通過不同的模式來打開文件,這些模式決定了文件的讀寫權限及行為。
# 寫入模式,如果文件存在,覆蓋原有內容
with open('example.txt', 'w') as file:
file.write('Hello, Python!')
# 追加模式,寫入的內容會添加到文件末尾
with open('example.txt', 'a') as file:
file.write('\nAppend text.')
# 二進制寫入模式
with open('example.bin', 'wb') as file:
file.write(b'\x00\xFF')
緩沖
緩沖是文件操作中的一個重要概念,它影響數據寫入文件的時機。Python允許你控制文件的緩沖行為。
# 使用無緩沖模式打開文件
with open('example.txt', 'r', buffering=0) as file:
print(file.read())
文件鎖
在多線程或多進程環(huán)境中,為了避免數據沖突,可以使用文件鎖。
import portalocker
with open('example.txt', 'a') as file:
portalocker.lock(file, portalocker.LOCK_EX)
file.write('Locked file.\n')
portalocker.unlock(file)
高級文件搜索技巧
結合os.walk和正則表達式,可以實現復雜的文件搜索邏輯。
import os
import re
def search_files(directory, pattern):
regex = re.compile(pattern)
for root, _, files in os.walk(directory):
for name in files:
if regex.search(name):
print(os.path.join(root, name))
search_files('.', 'example.*')
文件系統(tǒng)監(jiān)控
使用watchdog庫可以監(jiān)控文件系統(tǒng)的變化,這對于需要根據文件更新實時做出響應的應用非常有用。
from watchdog.observers import Observer from watchdog.events import LoggingEventHandler event_handler = LoggingEventHandler() observer = Observer() observer.schedule(event_handler, path='.', recursive=True) observer.start()
跨平臺文件路徑處理
pathlib模塊提供了一種面向對象的方式來處理文件路徑。
from pathlib import Path
p = Path('example.txt')
with p.open('r') as file:
print(file.read())
性能考慮
使用mmap模塊可以通過內存映射的方式提高大文件的處理效率。
import mmap
import os
with open('example.txt', 'r+b') as f:
mm = mmap.mmap(f.fileno(), 0)
print(mm.readline())
mm.close()
安全性
在處理文件路徑時,尤其是那些來自用戶的路徑時,需要特別小心,以避免安全漏洞。
from pathlib import Path
def safe_open(file_path, root_directory):
root = Path(root_directory).resolve()
absolute_path = (root / file_path).resolve()
if root not in absolute_path.parents:
raise ValueError("不允許訪問根目錄之外的文件")
return open(absolute_path, 'r')
user_path = '../outside.txt'
try:
file = safe_open(user_path, '.')
print(file.read())
except ValueError as e:
print(e)
綜合示例——進一步修改文件搜索引擎
import os
import re
import time
from concurrent.futures import ThreadPoolExecutor
def search_files(directory, pattern):
"""
在指定目錄中搜索匹配正則表達式的文件。
"""
matches = []
regex = re.compile(pattern)
for root, dirnames, filenames in os.walk(directory):
for name in filenames:
if regex.search(name):
matches.append(os.path.join(root, name))
return matches
def search_directory(directory, pattern):
"""
搜索單個目錄。
"""
try:
return search_files(directory, pattern)
except PermissionError:
return [] # 忽略權限錯誤
def main(root_directory, pattern):
"""
主函數:并行搜索目錄并匯總結果。
"""
start_time = time.time()
matches = []
# 使用ThreadPoolExecutor來并行搜索
with ThreadPoolExecutor() as executor:
futures = []
for root, dirs, files in os.walk(root_directory):
for dirname in dirs:
future = executor.submit(search_directory, os.path.join(root, dirname), pattern)
futures.append(future)
# 等待所有線程完成并匯總結果
for future in futures:
matches.extend(future.result())
end_time = time.time()
# 打印搜索結果
print(f"找到 {len(matches)} 個文件:")
# for match in matches:
# print(match)
print(f"搜索耗時: {end_time - start_time:.2f} 秒")
if __name__ == "__main__":
import sys
if len(sys.argv) != 3:
print("用法: python search_engine.py [根目錄] [搜索模式]")
else:
main(sys.argv[1], sys.argv[2])
os: 用于與操作系統(tǒng)交互,包括遍歷目錄樹。re: 用于正則表達式匹配,以便按模式搜索文件名。time: 用于測量搜索操作的開始和結束時間,以計算總耗時。concurrent.futures.ThreadPoolExecutor: 用于并行化搜索任務,提高搜索效率。
search_files 函數
這個函數接受兩個參數:directory(要搜索的目錄路徑)和pattern(正則表達式模式),并返回匹配該模式的所有文件的完整路徑列表。
- 首先,創(chuàng)建一個空列表
matches來存儲找到的匹配文件路徑。 - 使用
re.compile(pattern)編譯正則表達式模式,以便在搜索中使用。 - 使用
os.walk(directory)遍歷指定目錄及其所有子目錄。對于每個目錄,os.walk返回一個三元組(root, dirnames, filenames),其中root是當前目錄的路徑,dirnames是該目錄下所有子目錄的名稱列表,filenames是該目錄下所有文件的名稱列表。 - 在每個目錄中,遍歷所有文件名,使用正則表達式的
.search(name)方法檢查文件名是否與給定模式匹配。如果匹配,將文件的完整路徑(使用os.path.join(root, name)構建)添加到matches列表中。 - 函數返回
matches列表,包含所有找到的匹配文件的路徑。
search_directory 函數
這個函數封裝了search_files函數,以便在單個目錄中進行搜索,并處理可能發(fā)生的PermissionError。
- 接受和
search_files相同的參數。 - 嘗試調用
search_files函數進行搜索,如果遇到PermissionError(例如,因為沒有足夠的權限訪問某個目錄),則捕獲該異常并返回一個空列表,表示沒有找到匹配的文件。
main 函數
這是腳本的主函數,負責初始化并行搜索,匯總結果,并打印搜索耗時和找到的匹配文件。
- 首先記錄搜索開始時間。
- 創(chuàng)建一個空列表
matches來存儲所有找到的匹配文件路徑。 - 使用
ThreadPoolExecutor創(chuàng)建一個線程池,以并行執(zhí)行搜索任務。這通過遍歷根目錄及其所有子目錄,并為每個子目錄提交一個search_directory任務到線程池來實現。 - 使用
executor.submit提交任務,并將返回的Future對象添加到futures列表中。 - 使用
future.result()等待所有任務完成并收集結果,將每個任務找到的匹配文件路徑擴展到matches列表中。 - 記錄搜索結束時間,并計算總耗時。
- 打印找到的匹配文件總數和搜索耗時。注釋掉的部分可以取消注釋以打印每個匹配文件的路徑。
腳本入口
- 檢查命令行參數的數量。如果不等于3(腳本名稱、根目錄和搜索模式),則打印使用說明。
- 如果參數數量正確,調用
main函數并傳入根目錄和搜索模式。
運行一下看看效果
$ python3 r2.py /DB6/project index.*
找到 1409008 個文件:
搜索耗時: 147.67 秒
以上就是使用Python實現一個簡單的文件搜索引擎的詳細內容,更多關于Python文件搜索引擎的資料請關注腳本之家其它相關文章!
相關文章
如何使用python的ctypes調用醫(yī)保中心的dll動態(tài)庫下載醫(yī)保中心的賬單
這篇文章主要介紹了如何使用python的ctypes調用醫(yī)保中心的dll動態(tài)庫下載醫(yī)保中心的賬單,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05

