python Flask當文件名包含中文時使用secure_filename,中文會被忽略的解決辦法


在修改自己項目的文件上傳功能時,發現文件是成功上傳到服務器端了,但是服務器端上的文件名確是'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() 相同.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM