題 用記事本打開JPG圖片,將所有“文本”粘貼到新的記事本文件,更改為.JPG,不再打開。為什麼?


這種現象讓我有些疑問。

這是詳細的實驗,我的操作系統是Windows 7 x64 SP1:

  • 我通過簡單地更改其擴展名將圖片(JPG)文件更改為TXT(或者可以選擇用記事本打開JPG,同樣的事情)

它看起來應該是這樣的,看起來奇怪的文本序列,其中一些(非常罕見)實際上是有意義的,如下面的截圖“creator:dg-jpeg v1.0 ......”

Sample JPG text

  • 我禁用包裝並使用Ctrl + A選擇所有文本(以確保沒有遺漏)
  • 我將復制的文本粘貼到另一個空白TXT文件並保存為JPG,我將新文件大小與原始JPG進行了比較。所有這些(原始JPG,轉換後的TXT文件和新創建的TXT文件)都屬於 精確 相同的大小,到字節。

當我試圖打開時,Windows會說 “Windows Photo Viewer無法打開此圖片,因為該文件似乎已損壞,已損壞或太大”

我甚至嘗試用另一種方​​法測試它:用記事本打開JPG,我剪了  來自易於記憶的位置的已知字符(如第二行的第一個字符)然後保存文件。觀眾當然會顯示相同的消息。然後我又打開它並將角色貼到了 精確 位置(記事本記得它的退出狀態,如窗口位置,包裝,字體大小......所以我沒有問題,這是正確的)

而且仍然是同樣的錯誤。你可以嘗試這個來獲得這個想法,記得選擇一張小圖片其他記事本會像一個老生鏽的男人。

可能是造成這種現象的原因是什麼?


81
2017-07-13 20:50


起源


嘗試使用fc命令。打開一個cmd提示符並執行 - C:\blah>fc file1 file2   文件可能大小相同但不同。 (雖然通常一些隨機的改變不會使文件保持相同的大小,但它很容易)。 fc命令對於調查正在發生的事情非常有用。您也可以使用xxd命令,這是在cygwin中,還附帶了vim7。 xxd -p file1這將轉儲文件的十六進制。您可以將兩個文件的十六進制與fc和fc進行比較。或者甚至在記事本中打開十六進制,然後使用alt-tab在兩個記事本窗口之間輕彈。 - barlop
您正在嘗試使用簡單的文本編輯器(如記事本)讀取二進製文件。它將無法正確讀取ANSI編碼,因此它將轉換它。保存時,文件將不再是二進製文件,因此解析器無法讀取文件中的數據。 (查找基於XML的文件保存和二進製文件之間的區別,保存它是一個有趣的主題。)如果您嘗試使用Notepad ++進行相同的實驗,您將成功完成您的嘗試。 - woutervs
可能重複 為什麼exe文件在記事本等文本編輯器中不顯示為1和0? - Horn OK Please
對於感興趣的:你可以在Vim中編輯圖像:但是,訣竅是,Vim轉換文件 XPM 格式,純ASCII。 - Boldewyn
簡而言之,記事本在將文件顯示給您之前會修改您的文件。 - Derek 朕會功夫


答案:


根據用於打開文件的編碼,您可能會看到不同的行為。我的Windows 7記事本允許打開ANSI,UTF-8,Unicode或Unicode大端的文件。

我用一個用gimp創建的小的2x2像素jpeg圖像測試了這個問題,打開並用ANSI編碼保存圖像文件。使用十六進制編輯器打開原始圖像和保存圖像,我看到所有00序列(兩個十六進制數字, NUL控制角色)已被轉換為20(空格字符)。

在十六進制編輯器中全部替換20乘以00可恢復圖像格式。

我用谷歌搜索了一下,我沒有找到任何解釋為什麼會這樣做的參考文獻。只要 提到一個警告它的帖子 (谷歌緩存鏈接,該頁面不可用)。

如果您將文件保存/打開為UTF-8,它似乎仍將NUL字符轉換為空格,但由於從單字節字符到UTF-8多字節序列的轉換,它也會增加生成的文件大小。

如果您將文件保存/打開為Unicode,它似乎仍然將NUL字符轉換為空格,但也會在文件的開頭添加一個字節, BOM


80
2017-07-13 23:06



0x00是C字符​​串中的字符串終止符。他們可能已經替換了它們,因為文本文件不應該包含它們。記事本是一個非常古老的程序。 - Zonder
我懷疑notepad.exe是一個.NET可執行文件。 - knittl
@Bakuriu一個C字符串肯定可以存在於一個文件中;我可以想到包含它們的眾多文件格式。 Windows應用程序附帶的絕大多數應用程序都是本機的,而不是.NET。也就是說,記事本不會將以空字符結尾的字符串寫入文件。 - Carey Gregory
@Bakuriu:Windows程序通常不是用.Net編寫的。它是C / C ++並且是核心原生的。由microsoft開發的一個.Net應用程序是現場編寫器,現已停止使用。 - Bhathiya Perera
@ SJuan76嗯? C ++沒有定義名為的數據類型 byte。也許你正在考慮其他一些語言。應用程序開發人員可以處理他們認為合適的二進制數據,包括如果他們選擇使用C字符串。正如我之前所說,我可以想到許多包含C字符串的二進製文件格式。 - Carey Gregory


為什麼失敗:

記事本創建空間 (ASCII code 32) 字符的字符 NUL  (ASCII code 0) 因為Windows API的文本框只允許null終止 char *  ASCIIZ (字符數組,指針)。 它在第一個NUL被切斷了。 

那是因為 Windows API 主要寫在 C 語言和 null終止字符串 是常見的功能之一。即使現代Windows和Unicode被認為是相同的,也會出現空終止字符串。所以記事本只需用空格替換它們就可以查看完整的文件。

因此,當您保存文件時,它已損壞。

wikipedia-null終止字符串


如何進一步研究:

您可以使用比較器 超越比較(商業,試用) 看到角色替換效果。也看到了 其他二進制比較工具

hex comparison

注意 :(20)16 =(32)10


記事本的原因對大文件的作用很慢

 它檢查每個字符並用空格替換特殊字符。其他軟件不進行內存中轉換(至少不像記事本那樣原始)。它們只是以不同方式呈現特殊字他們使用先進的緩衝技術。


看著Notepad.exe(XP 32位)

(我假設它仍然用C ++編寫,或者至少使用相似的版本 鏈接 )

notepad

我正在使用 PEID 工具(通過引入PE + / 64 exes來停止開發)

可以將PEiD捆綁在bin文件夾中 通用提取器

我提取了記事本。顯然來自Windows xp iso的ex_文件。試試看。這是一個使用7z的cab文件提取。

警告 !您的病毒掃描程序可能會將Universal Extractor / PEiD檢測為黑客工具或病毒。不信任它不下載!!


有關Windows API的更多信息

積分:傑森C.

它不僅僅是文本框; WM_SETTEXT 通常不提供用於指定字符串長度的參數,並且始終假定字符串以null結尾。您始終可以使用指定字符串長度的自定義消息創建自定義文本框,但記事本和大多數其他程序合理地不會。 還有功能 SetWindowText函數 也沒有提供長度參數。


36
2017-07-14 09:59



你顯示一個與Windows XP版本捆綁在一起的Notepad可執行文件的屬性表有點奇怪,但是從窗口主題判斷,你顯然正在運行某些版本的Windows 8.這可以解釋為什麼可執行文件與工具集的7.1版 - 這是他們用來編譯Windows XP和相關實用程序的東西。毫無疑問,Windows 8版本的Notepad將使用較新版本的SDK工具進行編譯。 - Cody Gray
它不僅僅是文本框; WM_SETTEXT通常不提供用於指定字符串長度的參數,並且始終假定字符串以null結尾。您始終可以使用指定字符串長度的自定義消息創建自定義文本框,但記事本和大多數其他程序合理地不會。 - Jason C
@BhathiyaPerera因為我對通過在評論中添加信息所做的工作水平感到滿意。如果您願意,歡迎您使用該信息改進您的答案。 - Jason C


記事本不會完全保留所有特殊/擴展字符。我手邊沒有對這種行為的引用,但是發現這是例如使用UNIX風格的行尾LF,記事本將轉換為CRLF和null(0x00),它將忽略它。在諸如JPG之類的二進製文件中,可能存在記事本不保留的字符的隨機出現。嘗試使用支持HEX的編輯器進行實驗,然後就可以了。如果我找到了一個很好的參考,並且一旦我測試了一個HEX編輯器,我會更新我的答案。

更新:我嘗試了一些著名的程序員編輯,但只有其中一個工作正常, MaëlHörz的HxD。我之前從未使用過HxD,但感謝這篇Stack文章的回答, 用於Notepad ++的十六進制查看器/編輯器插件

幾分鐘後沒有工作的其他編輯器是Notepad ++,Notepad2和UltraEdit(v17.3,舊版本)。其中一些在前幾個字節(JPEG)的複制/粘貼方面存在問題 文件簽名幻數 FF D8 FF。也許他們會比我現在有時間更多地擺弄。


28
2017-07-13 21:49



Sublime Text(2/3)通過以十六進制格式顯示二進製文件自動打開。例如,只需單擊“打開”即可啟動JPEG文件: puu.sh/aaAVx/bd08dab46e.png - tomsmeding
實際上,比記事本更頻繁地將LF轉換為CRLF,它將保留LF的方式並顯示文本,好像根本沒有換行! - Moshe Katz


你曾經能夠在當天寫回來做到這一點。它是Windows 3.1中的標準程序,但我不記得Windows 95是否包含它。寫入將允許二進制安全編輯它可以打開的任何文件(可能非常有限的文件大小)。記事本肯定不是二進制安全的(文本保持不變,但非文本字符的實際字節[例如控制代碼]可能會改變)這就是你的JPG示例不起作用的原因。嘗試獲取Write(以及非常舊的Windows)的副本並再次嘗試您的實驗!

根據 維基百科的“Windows寫”文章 寫入包含在Windows NT 3.5中。它在Windows 95之後被Wordpad取代。 write.exe 仍然存在於Windows目錄中,但它只是打開Wordpad的包裝器。


6
2017-07-14 06:54





我認為這不是編碼的問題,而是字符集的問題。 JPG格式基本上是一個字節流。因此允許不可打印的字符,如NUL,ETX,STX,SOH,DLE等。

Microsoft記事本無法顯示那些不可打印的字符。它可能會顯示某種類型的佔位符,例如空字符的空格。因此,使用記事本打開文件不會顯示實際內容,而是顯示由所選編碼(utf-8,utf-16等)解碼的內容,並由特定字符集(unicode,ascii等)顯示,不包括非可打印的字符。

選擇所有顯示的文本並將文本複製到剪貼板時,只複製包括佔位符在內的可打印字符。因此,自動將空字符轉換為空格並完全忽略其他不可打印的字符。

所以基本上你只是失去了這樣做的內容。如果您使用十六進制編輯器,它將完全複製所有內容。


更新: Bhathiya Pereras的回答是對的: https://superuser.com/a/782885/322784 將文本複製到剪貼板時,不會忽略不可打印的字符。


5
2017-07-14 09:00



每個文件“基本上都是一個字節流”。 - Jason C
@JasonC我不同意。雖然每個文件都可以作為字節流讀取。像XML文件這樣的結構化文件不能作為數據流讀取。在讀取文件末尾之前,內容無效。切成兩半的jpg仍然有效並且可以顯示。它只丟失了一半的圖片。 - sbecker
對此沒有真正的分歧空間。 :) XML是一個像其他任何東西一樣的字節流,XML(以及字符編碼)定義了這些字節的格式。它當然可以作為數據流讀取。例如,在十六進制編輯器中打開它。這個數據流恰好可以解析為XML。 - Jason C
@JasonC實際上無法與之爭辯。 :)Touché! - sbecker


JPEG文件包含除某些字段之外的非文本數據,基本上將找到0到25​​5之間的任何字節值,尤其是在表示包含幾乎偽隨機數據的編碼壓縮圖像的區域中。

但是默認情況下,Notepad會將數據視為ANSI文本,因此會執行各種改變原始數據的操作,如下所示:

  • 替換字節映射特殊/未定義/禁止字符,因為它們對有效的ANSI文本沒有意義

  • 重新編碼空字符,行尾和文件序列結束到Windows / DOS約定

這意味著如果您編輯並將數據保存為文本,它將在最佳情況下更改jpeg,並使其在最壞情況下無法使用。


2
2017-07-14 13:16



“ANSI”在技術上不正確雖然人們普遍理解。 - Jason C