為什麼我的 UTF-8 文件會在 Azure Data Lake Analytics 中引發 UTF-8 編碼錯誤?
我有一個從未知源系統以 gunzip 壓縮的文件。它是使用 7zip 控制台應用程序下載和解壓縮的。該文件是一個似乎以 UTF-8 編碼的 CSV 文件。
然後在壓縮後立即將其上傳到 Azure Data Lake Store。然後有一個 U-SQL 作業設置,只需將其從一個文件夾複製到另一個文件夾。此過程失敗並引發值的 UTF-8 編碼錯誤:ée
測試
我從商店下載了該文件並刪除了所有記錄,但帶有 Azure 標記的值的記錄除外。在 Notepad++ 中,它將文件顯示為 UTF-8。我再次將文件另存為 UTF-8 並將其上傳回商店。我再次執行該過程,該過程成功,該值為 UTF-8
我在這裡想念什麼?原始文件是否可能不是真正的 UTF-8?是否有其他原因導致誤報?我有點困惑。
可能性
- 文件不是真正的 UTF-8,需要重新編碼
- 也許上傳文件的方法是重新編碼
- 也許 7zip 重新編碼不正確
環境/工具
- 視窗伺服器
- 蟒蛇 2.7
- Azure 數據湖儲存
- Azure 數據湖分析
- 7Zip.exe
- 廣州
- Azure API
USQL
僅定義架構的基本 USQL 作業然後將所有欄位選擇到新目錄。除了省略標題之外,不會發生任何轉換。該文件是 CSV,用逗號分隔字元串上的雙引號。無論數據類型如何,模式都是字元串。嘗試的提取器是 TEXT 和 CSV,兩者都設置為編碼:UTF8,即使根據系統上的 Azure 文件,兩者都預設為 UTF8。
其他注意事項
- 過去,該文件已上傳到 BLOB 儲存,並通過 Polybase 以相同方式導入 Azure 數據倉庫,沒有出現錯誤。
- 導致 UTF-8 編碼錯誤的值是在 100 萬條其他記錄中損壞的 URL。
- 即使它是 UTF-8 文件,看起來也有 ASCII 字元進入。
- 當我將其轉換為 ANSI 並使用 ASCII 提取器時,文件成功。
- Azure Data Lake Analytics 不允許你忽略該錯誤,因為它是一個編碼問題。我很樂意像在 Azure 數據倉庫中一樣使記錄失效。
筆記
這裡有幾件事要處理:
- 只是為了解決這個問題:gz$$ ip $$和7zip.exe與此無關。壓縮不會改變編碼或任何原始字節(否則壓縮/解壓縮將不可靠)。好吧,從理論上講,其中一個可能存在錯誤,因此解壓縮的輸出在某種程度上略有不同,但我認為這將是一個廣泛存在的問題,並且這些算法,尤其是這兩個工具,已經存在很長一段時間,並且被認為是可靠的。
- 請記住:文件,甚至是文本文件,都包含字節,而不是字元。這些字節可以表示一些字元集,或者另一個集,或者其他東西。但歸根結底,它只是一個字節的集合。因此,如果您看到
Ã
,那不是因為Ã
文件中有一個 ,而是由於存在一個或多個目前被解釋為表示Ã
. 可能這些相同的字節應該真正被解釋為代表其他東西。並且,同時,也可能是其他一些字節序列,在不同的解釋下,也代表Ã
.- >
然後有一個 U-SQL 作業設置,只需將其從一個文件夾複製到另一個文件夾。
好的,這裡應該引發一個危險信號:為什麼“簡單地複製文件”會產生編碼錯誤?如果正在讀取文件,則只會出現編碼錯誤,否則它只是從 A 點移動到 B 點的字節集合(或者它可能只是被重新連結而不移動,但無論哪種方式)。 4. >
此過程失敗並引發值的 UTF-8 編碼錯誤:
ée
這是另一個關鍵指標(可能被某些人誤解):錯誤是UTF-8 encoding error。這告訴我們兩件事:
- 該文件已被解釋為 UTF-8,因此字節序列不會被解釋為其他編碼(例如 Windows-1252 或 ISO-8859-1)。這意味著這些
é
字元已經是 UTF-8 編碼的字節(即0xC383C2A9
),而不是 Windows-1252 字節(0xC3A9
),應該將其解釋為 UTF-8 以生成é
.- 它是錯誤的事實意味著它
ée
不是錯誤,因為如果它是錯誤,那麼它將無法顯示它。編碼錯誤是指字節序列無法生成該編碼中的字元。含義:序列中缺少某些內容。這ée``ée
序列應該是可以從文件中的字節解碼的剩餘部分。請記住,Unicode 是一種規範,而不是軟體。實施由每個供應商決定。有關於合規實現的指南,其中包括如何處理解碼錯誤。但是,也有一些靈活性。因此,在這種情況下,某些實現可能會拋出硬錯誤,或者其他實現可能會顯示“替換”字元,或者某些實現可能在該位置不顯示任何內容。無論哪種情況,ée
從字面上看,這個序列很可能是一個紅鯡魚,而不是我們應該看到的。- >
在 Notepad++ 中,它將文件顯示為 UTF-8。我再次將文件另存為 UTF-8 並將其上傳回商店。我再次執行該過程,該過程成功,該值為 UTF-8
行。因此,在**Notepad++中,當它在打開文件時在底欄右側顯示“UTF-8”時,並不一定保證該文件實際上被編碼為 UTF-8。這是一個最好的猜測,可能基於常見的字節序列。如果編碼指示器改為顯示“UTF-8-BOM”,則可以保證文件被編碼為 UTF-8。“-BOM”表示一個字節順序標記存在。BOM 是一個可選的 2 - 4 字節序列,位於文件的開頭,應該隱藏,但指示文件的編碼。這僅適用於 Unicode。UTF-16 有兩個 2 字節的 BOM,一個用於 Little Endian,一個用於 Big Endian。UTF-32 也有兩個 4 字節的 BOM,每個字節序一個。UTF-8 只有一個 3 字節的 BOM,因為字節順序不適用於 UTF-8(因為程式碼單元是單個字節,所以字節只能有一個順序)。當然,擁有 BOM 並不能保證它會被讀取文件的任何人尊重甚至理解。在此處介紹的情況下,擁有 BOM 不應對結果產生任何影響,因為該文件已被作為 UTF-8 文件讀取。再一次,如果Notepad++正在顯示
ée
並且在右下角顯示“UTF-8”,那麼它已經是 UTF-8 而不是 Windows-1252 / ISO-8859-1 需要被告知讀取為 UTF-8 才能生成é
. 6. 如果Notepad++**認為文件是 UTF-8,那麼將文件保存為 UTF-8應該不會真正改變任何東西。其他的東西一定已經改變了。 7. >該文件是 CSV,用逗號分隔字元串上的雙引號。
和:
這是一個包含 100 萬條其他記錄的 URL。
那麼,該欄位
ée
的值是多少?entire
它在文件中的雙引號內嗎?ée
似乎不是 URL ;-)此外,錯誤中顯示的值是否與您在文件中看到的值完全匹配?如果是這樣,則文件中可能存在導致此問題的隱藏字元。 8. >
即使它是 UTF-8 文件,看起來也有 ASCII 字元進入。
“ASCII”字元是什麼意思?UTF-8 的一個特點是前 128 個程式碼點(U+0000 到 U+007F)的編碼與標準 ASCII 相同。這是 UTF-8 的主要設計目標:完全兼容 ACSII(不是 8 位擴展 ASCII,只是 7 位標準 ASCII)。因此,如果文件的大部分內容使用美國英語字元和標點符號,那麼是的,無論您以 ASCII 還是 UTF-8 格式打開文件,您都應該期望看到相同的內容。 9. >
當我將其轉換為 ANSI 並使用 ASCII 提取器時,文件成功。
這並不奇怪。我認為不可能出現 ANSI / ASCII 編碼錯誤。在程式碼頁 Windows-1252 中只有少數程式碼點/值未定義,它們通常表現為“隱藏”字元。
當然,如果您在該文件中確實有有效的 UTF-8 編碼字元,則轉換為 ANSI 會將它們更改為“?” 如果它們在 Windows-1252 中不可用。
外賣
如果這是一個 ANSI / Windows-1252 / ISO-8859-1 編碼文件,
é
表明字節序列為0xC3A9
,則不會出現 UTF-8 編碼錯誤,因為 的字節序列0xC3A9
是有效的 UTF-8é
。由於錯誤本身無法顯示(否則它不會是編碼錯誤):
ée
不是錯誤,而是錯誤的結果我們需要查看存在編碼錯誤的行的確切字節,以便查看無法解碼的內容。
沒有說文件需要以 UTF-8 格式導入。如果一個文件(即使不是這個)被編碼為 Windows-1252、ISO-8859-1 或其他任何文件,並且文件中的數據都是正確的,那麼與其試圖強製文件為 UTF-8 ,最好告訴正在讀取文件的任何程序/工具實際的文件編碼是什麼。沒有理由不將 Windows-1252 編碼文件導入為 Windows-1252。
底線是:有太多猜測/野鵝追逐而沒有看到具有編碼錯誤的行的原始字節。有這條線將有助於確定 a) 發生了什麼,以及 b) 如何進行。
如果賞金的發布者可以在此答案中添加評論以提供更多詳細資訊,尤其是出現錯誤的確切字節序列,那將有助於解決此問題。
UTF-8 編碼文件可以選擇包含字節順序標記 (BOM)。這是一個“幻數”,用於向使用軟體指示文件是 UTF 編碼的。更複雜的是,BOM 可以是 big-endian 或 little-endian。
Notepad++ 通過編碼菜單使所有這些可見。我建議您為您的文件(或它的精簡副本)擺弄這些文件,看看有什麼(如果有的話)有效。