保存地方記憶——安全讀寫UTF-8文字檔
從原始逐字稿、講述者確認稿到巡查日誌,讓每一份文字都有來源、版本與安全邊界。
完成本篇後,你能使用
with open() 及不同模式讀寫文字檔,逐行處理大型資料,正確處理UTF-8與換行,安全追加巡查日誌,並以新檔案保存修訂版本而不覆蓋原始資料。一、文字檔不只是「開啟與儲存」
水井村USR可能保存長者訪談、台語逐字稿、導覽文字、學生反思與設備巡查日誌。程式寫得出檔案不代表資料管理正確:原始稿是否保留?誰確認過?能否公開?都是教材的一部分。
二、open()的基本結構
from pathlib import Path
path = Path("地方故事.txt")
with path.open("w", encoding="utf-8") as file:
file.write("水井三寶:白馬、烏龜、姻緣花\n")
with path.open("r", encoding="utf-8") as file:
content = file.read()
print(content)with 區塊結束後會自動關閉檔案,即使讀寫時發生例外,也比手動呼叫 close() 安全。
三、選對檔案模式
| 模式 | 用途 | 風險或特性 |
|---|---|---|
r | 讀取 | 檔案不存在會出錯 |
w | 寫入 | 會清空並覆蓋既有檔案 |
a | 追加 | 內容寫在檔案尾端 |
x | 排他建立 | 檔案已存在就拒絕寫入 |
r+ | 讀寫 | 游標位置較複雜,初學時慎用 |
x;巡查日誌可用 a;原始逐字稿只用 r。除非已備份且明確確認,不要對重要資料使用 w。四、拒絕覆蓋原始逐字稿
from pathlib import Path
def create_new_text(path, content):
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("x", encoding="utf-8", newline="") as file:
file.write(content)
return path
target = Path("逐字稿") / "水井三寶_整理稿_v1.txt"
try:
created = create_new_text(target, "教學用整理稿\n")
except FileExistsError:
print("檔案已存在,請建立新版本名稱。")
else:
print("已建立:", created)五、一次讀完與逐行讀取
from pathlib import Path
path = Path("地方故事.txt")
with path.open("r", encoding="utf-8") as file:
for line_number, line in enumerate(file, start=1):
cleaned = line.rstrip("\n")
print(line_number, cleaned)read() 適合小檔案;直接迭代檔案物件能逐行處理大型日誌。rstrip("\n") 只移除行尾換行,比不加參數的 strip() 更能保留有意義的前後空白。
六、readline()與readlines()
from pathlib import Path
path = Path("地方故事.txt")
with path.open("r", encoding="utf-8") as file:
first_line = file.readline()
remaining_lines = file.readlines()
print("第一行:", first_line.rstrip("\n"))
print("其餘行數:", len(remaining_lines))readline() 每次讀一行;readlines() 會把剩餘內容放入串列,大檔案可能占用較多記憶體。
七、安全追加智慧養殖巡查日誌
from datetime import datetime
from pathlib import Path
def append_patrol_log(path, site, message):
timestamp = datetime.now().isoformat(timespec="seconds")
safe_site = " ".join(str(site).split())
safe_message = " ".join(str(message).split())
line = f"{timestamp}\t{safe_site}\t{safe_message}\n"
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("a", encoding="utf-8", newline="") as file:
file.write(line)
append_patrol_log(
"巡查資料/教學巡查.log",
"示範池A",
"完成例行檢查",
)先移除輸入中的換行,可避免一筆紀錄被偽裝成多行。真正系統還要限制可寫入欄位,避免Token、密碼及個資進入日誌。
八、使用writelines()時別忘了換行
from pathlib import Path
items = ["白馬", "烏龜", "姻緣花"]
lines = [f"{number}. {item}\n" for number, item in enumerate(items, 1)]
path = Path("水井三寶清單.txt")
with path.open("w", encoding="utf-8", newline="") as file:
file.writelines(lines)writelines() 不會自動加入換行,因此要自行在每個字串結尾放入 \n。
九、處理不同作業系統的換行
Windows常見CRLF,Linux常見LF。文字模式通常會自動轉換;需要輸出一致格式時,可使用 newline="" 並明確寫入 \n。讀取時可用 splitlines() 處理常見換行。
text = "第一行\r\n第二行\n第三行\r第四行"
for number, line in enumerate(text.splitlines(), start=1):
print(number, line)十、遇到編碼錯誤時不要默默刪字
from pathlib import Path
def read_utf8(path):
path = Path(path)
try:
return path.read_text(encoding="utf-8")
except FileNotFoundError:
print("找不到檔案:", path)
except UnicodeDecodeError as error:
print("檔案不是有效UTF-8,請確認來源編碼:", error)
return None不建議用 errors="ignore",因為它會直接丟掉無法解碼的字元。地方名稱、臺羅聲調或訪談內容可能因此無聲消失。
十一、從原始稿產生確認稿
以下流程只讀原始稿,將清理結果寫入新的確認稿;如果目標已存在就停止。
import unicodedata
from pathlib import Path
def prepare_review_copy(source, target):
source = Path(source)
target = Path(target)
text = source.read_text(encoding="utf-8")
normalized = unicodedata.normalize("NFC", text)
lines = [line.rstrip() for line in normalized.splitlines()]
review_text = "\n".join(lines) + "\n"
target.parent.mkdir(parents=True, exist_ok=True)
with target.open("x", encoding="utf-8", newline="") as file:
file.write(review_text)
return target
# 實際使用時請換成資料副本路徑
# prepare_review_copy("逐字稿/原始檔/訪談.txt",
# "逐字稿/確認稿/訪談_v1.txt")十二、簡易版本資訊檔
from pathlib import Path
metadata = [
"文件:水井三寶訪談整理稿",
"版本:v1",
"狀態:待講述者確認",
"公開:否",
]
path = Path("逐字稿") / "水井三寶_v1_metadata.txt"
with path.open("x", encoding="utf-8", newline="") as file:
file.write("\n".join(metadata) + "\n")真實專案還可記錄建立日期、來源檔案、整理者、確認者、授權範圍及撤回方式,但不要把不必要的個資寫入公開中繼資料。
十三、常見錯誤檢查表
| 現象 | 原因 | 修正 |
|---|---|---|
| 原始內容消失 | 誤用w模式 | 重要新檔使用x,原始檔只讀 |
| 檔案沒有完整寫入 | 未正確關閉檔案 | 使用with管理資源 |
| writelines全部黏在一起 | 沒有自行加入換行 | 每個字串結尾加\n |
| 中文或臺羅缺字 | 編碼錯誤或忽略解碼失敗 | 確認來源編碼,不用errors="ignore" |
| 日誌一筆變多行 | 使用者輸入含換行 | 寫入前清理並限制欄位 |
十四、USR實作挑戰
建立原始檔、整理稿、講述者確認稿與公開版流程,為每份檔案加上狀態資訊,確認程式永不覆蓋原始檔。
追加十筆匿名教學紀錄,再逐行統計正常、待確認與離線筆數;不把無效讀值當成正常。
在Thonny、Colab與不同作業系統開啟同一UTF-8檔,記錄換行及編碼差異。
十五、與生成式AI協作
請擔任Python文字檔與USR資料治理助教。
請設計地方訪談文字檔處理流程:
1. 原始逐字稿只能讀取,不得覆蓋;
2. 整理稿使用新版本檔名與x模式;
3. 明確指定UTF-8;
4. 不可使用errors="ignore"刪字;
5. 保留原始稿、修改紀錄與確認狀態;
6. 公開版必須由講述者或權利人確認。
請先列風險,再提供小型、可測試的函式。安全讀寫文字檔的核心不只是模式與編碼,而是知道哪些資料可以覆寫、哪些必須保留,以及誰有權決定公開。
with、UTF-8與排他建立模式,是技術上的第一道防線。
沒有留言:
張貼留言