在修改自己項目的文件上傳功能時,發現文件是成功上傳到服務器端了,但是服務器端上的文件名確是'xlsx',前面的中文全都不見了,最后發現是secure_filename的問題,這里把解決方法整理一下
原因
查看源碼可以發現secure_filename函數只返回ASCII字符,非ASCII字符會被其中的正則表達式過濾掉。
def secure_filename(filename):
if isinstance(filename, text_type):
from unicodedata import normalize
filename = normalize("NFKD", filename).encode("ascii", "ignore")
if not PY2:
filename = filename.decode("ascii")
for sep in os.path.sep, os.path.altsep:
if sep:
filename = filename.replace(sep, " ")
filename = str(_filename_ascii_strip_re.sub("", "_".join(filename.split()))).strip(
"._"
)
# on nt a couple of special files are present in each folder. We
# have to ensure that the target file is not such a filename. In
# this case we prepend an underline
if (
os.name == "nt"
and filename
and filename.split(".")[0].upper() in _windows_device_files
):
filename = "_" + filename
return filename
解決方法
修改源碼
def secure_filename(filename):
if isinstance(filename, text_type):
from unicodedata import normalize
filename = normalize('NFKD', filename).encode('utf-8', 'ignore') # 轉碼
if not PY2:
filename = filename.decode('utf-8') # 解碼
for sep in os.path.sep, os.path.altsep:
if sep:
filename = filename.replace(sep, ' ')
# 正則增加對漢字的過濾 \u4E00-\u9FBF 中文
# 自定義構建新正則
_filename_ascii_add_strip_re = re.compile(r'[^A-Za-z0-9_\u4E00-\u9FBF.-]')
# 使用正則
# 根據文件名中的空字符,包括空格、換行(\n)、制表符(\t)等,把文件名分割成列表,然后使用下划線“_”進行連接,再過濾掉正則之外的字符,最后去掉字符串兩頭的“._”字符,最終生成新的文件名
filename = str(_filename_ascii_add_strip_re.sub('', '_'.join(filename.split()))).strip('._')
return filename
使用pypinyin
pip install pypinyin
pypinyin是漢字拼音轉換模塊,可以將漢字轉為拼音,但可能存在拼音有誤的問題,具體可以查看后面的地址。https://pypi.org/project/pypinyin/
from pypinyin import lazy_pinyin
filename = secure_filename(''.join(lazy_pinyin(file.filename)))
使用uuid模塊重命名文件名
https://blog.csdn.net/qq_36390239/article/details/98847888
a) uuid.uuid1([node[, clock_seq]]) : 基於時間戳
使用主機ID, 序列號, 和當前時間來生成UUID, 可保證全球范圍的唯一性. 但由於使用該方法生成的UUID中包含有主機的網絡地址, 因此可能危及隱私. 該函數有兩個參數, 如果 node 參數未指定, 系統將會自動調用 getnode() 函數來獲取主機的硬件地址. 如果 clock_seq 參數未指定系統會使用一個隨機產生的14位序列號來代替.
b) uuid.uuid3(namespace, name) : 基於名字的MD5散列值
通過計算命名空間和名字的MD5散列值來生成UUID, 可以保證同一命名空間中不同名字的唯一性和不同命名空間的唯一性, 但同一命名空間的同一名字生成的UUID相同.
c) uuid.uuid4() : 基於隨機數
通過隨機數來生成UUID. 使用的是偽隨機數有一定的重復概率.
d) uuid.uuid5(namespace, name) : 基於名字的SHA-1散列值
通過計算命名空間和名字的SHA-1散列值來生成UUID, 算法與 uuid.uuid3() 相同.