使用记事本打开JPG图片,将所有“文本”粘贴到新的记事本文件中,更改为.JPG,它将不再打开。为什么?


82

这种现象一直让我有疑问要问。

这是详细的实验,我的操作系统是Windows 7 x64 SP1:

  • 我仅通过更改扩展名将图片(JPG)文件更改为TXT(或者可以选择使用记事本打开JPG,也是一样)

它看起来应该像这样,奇怪的文本序列,其中一些(非常稀有)实际上是有意义的,例如“创建者:dg-jpeg v1.0 ...”下面的屏幕截图。

JPG文字范例

  • 我禁用了换行功能,并使用Ctrl + A选择了所有文本(以确保没有遗漏任何内容)
  • 我将复制的文本粘贴到另一个空白TXT文件中,并将其另存为JPG,然后将新文件的大小与原始JPG进行了比较。所有这些文件(原始JPG,转换后的TXT文件和新创建的TXT文件)的大小完全相同,以字节为单位。

当我尝试打开时,Windows会说“ Windows Photo Viewer无法打开该图片,因为该文件似乎已损坏,损坏或太大”

我什至尝试使用另一种方法对其进行测试:用记事本打开JPG,从易于记忆的位置剪切了一个已知字符(例如第二行的第一个字符),然后保存了文件。观众当然会显示相同的消息。然后我再次打开它,并将字符粘贴到EXACT位置(记事本记得它的退出状态,例如Windows位置,换行,字体大小...所以我没问题,就可以了)

并且仍然是相同的错误。您可以尝试使用此方法来获得创意,请记住选择一张小图片,否则记事本会像个生锈的老男人。

造成这种现象的原因可能是什么?


4
尝试使用fc命令。打开一个cmd提示,然后执行- C:\blah>fc file1 file2 文件大小可能相同但不同。(尽管通常情况下,某些随机更改通常不会使文件保持相同大小,但很容易做到)。fc命令对于调查正在发生的情况将非常有用。您也可以使用xxd命令,该命令在cygwin中,并且也随vim7一起提供。xxd -p file1将转储文件的十六进制。您可以将两个文件的十六进制分别与that和fc进行比较。甚至在记事本中打开十六进制,然后使用alt-tab在两个记事本窗口之间滑动。
barlop

22
您正在尝试使用简单的文本编辑器(如记事本)读取二进制文件。它将无法正确读取ANSI编码,因此它将对其进行转换。保存后,文件将不再是二进制文件,因此解析器无法读取文件中的数据。(查找基于XML的文件保存和二进制文件的保存之间的区别是一个有趣的话题。)如果您使用Notepad ++尝试相同的实验,那么您将成功进行尝试。
woutervs 2014年


3
对于感兴趣的用户:您可以在Vim中编辑图像:但是,窍门在于,Vim以XPM格式(纯ASCII)转换文件。
Boldewyn

4
长话短说,记事本在显示文件之前先对其进行修改。
德里克·朕会功夫2014年

Answers:


81

根据打开文件所用的编码,您可能会看到不同的行为。我的Windows 7记事本允许打开ANSI,UTF-8,Unicode或Unicode big endian文件。

我已经用gimp创建了一个小的2x2像素jpeg图像,并使用ANSI编码打开并保存了图像文件,从而测试了此问题。用十六进制编辑器打开原始图像和保存的图像,我发现所有00个序列(两个十六进制数字,NUL控制字符)都已转换为20(空格字符)。

在十六进制编辑器中全部替换为20 by 00将恢复图像格式。

我已经用谷歌搜索了一下,但没有找到任何解释它为什么这样做的参考。仅对发出警告的帖子的引用(Google缓存链接,该页面不可用)。

如果将文件保存/打开为UTF-8,它似乎仍会将NUL字符转换为空格,但是由于从单字节字符到UTF-8多字节序列的转换,它还会增加文件大小。

如果您以Unicode格式保存/打开文件,似乎它仍会将NUL字符转换为空格,但还会在文件的开头BOM处添加一个字节。


22
0x00是C字符​​串中的字符串终止符。它们可能已替换了它们,因为文本文件中不应包含它们。记事本是一个非常老的程序。
Zonder 2014年

25
我怀疑notepad.exe是.NET可执行文件。
knittl

10
@Bakuriu AC字符串最肯定可以存在于文件中;我可以想到许多包含它们的文件格式。Windows应用程序附带的绝大多数应用程序都是本地的,而不是.NET。也就是说,记事本不会将以空值结尾的字符串写入文件。
Carey Gregory

4
@Bakuriu:Windows程序通常不是用.Net编写的。它是C / C ++,本机为核心。微软开发的.Net应用程序之一是live writer,现已停产。
bhathiya-perera 2014年

5
@ SJuan76嗯?C ++没有定义名为的数据类型byte。也许您在考虑其他语言。应用程序开发人员可以处理他们认为合适的二进制数据,包括选择使用C字符串。如前所述,我可以想到许多包含C字符串的二进制文件格式。
Carey Gregory 2014年

37

为什么失败:

记事本(ASCII code 32)NUL之 类的字符创建空格字符,(ASCII code 0)因为Windows API的文本框仅允许以null终止的char * ASCIIZ(字符数组,指针)。它在第一个NUL截止。

发生这种情况是因为Windows API主要是用C语言编写的,并且以null终止的字符串是常见功能之一。即使当现代Windows和Unicode被视为相同时,也会出现以null结尾的字符串。因此,记事本只需将它们替换为空格,以便您可以查看完整的文件。

因此,当您保存文件时,它已损坏。

维基百科空终止的字符串


如何做进一步的研究:

您可以使用无与伦比的比较器(商业,试用)来查看字符替换效果。另请参阅其他二进制比较工具

十六进制比较

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


记事本在大文件上作用缓慢的原因

它检查每个字符,并用空格替换特殊字符。其他软件不执行内存中转换(至少不是原始的记事本转换)。他们只是以不同的方式呈现特殊字符。他们使用高级缓冲技术。


调查Notepad.exe(XP 32位)

(我假设它仍然是用C ++编写的,或者至少使用类似的链接器

记事本

我正在使用PEiD工具(由于引入了PE + / 64 exes而停止了开发)

PEiD可以捆绑在Universal Extractor的bin文件夹中

我提取了记事本。从Windows XP iso中的ex_文件可以明显看出。试试看。这是使用7z提取的cab文件。

警告 !您的病毒扫描程序可能会将Universal Extractor / PEiD检测为黑客工具或病毒。不要相信它不要下载!


有关Windows API的更多信息

积分:Jason C

不只是文本框;通常WM_SETTEXT不提供用于指定字符串长度的参数,并且始终假定字符串以null结尾。您始终可以使用指定字符串长度的自定义消息来创建自定义文本框,但是记事本和大多数其他程序都没有这样做。同样,函数SetWindowText也没有提供length参数。


1
显示与Windows XP版本捆绑在一起的Notepad可执行文件的属性表有点奇怪,但是从窗口主题来看,您显然正在运行某些版本的Windows8。这可以解释为什么可执行文件与该工具集的7.1版-这就是他们用来编译Windows XP和相关实用程序的工具。Windows 8版本的记事本无疑将使用更新版本的SDK工具进行编译。
科迪·格雷

2
不只是文本框;WM_SETTEXT通常,不提供用于指定字符串长度的参数,并且始终假定字符串以null结尾。您始终可以使用指定字符串长度的自定义消息来创建自定义文本框,但是记事本和大多数其他程序都没有这样做。
詹森·C

@BhathiyaPerera因为我对通过在评论中添加信息而完成的工作水平感到满意。如果需要,欢迎您使用这些信息来改善您的答案。
杰森C

28

记事本不能完全保留所有特殊/扩展字符。我没有立即获得此行为的参考,但是发现情况确实如此,例如UNIX风格的LF行尾,记事本将转换为CRLF,而null(0x00)将被忽略。在诸如JPG之类的二进制文件中,记事本不保留的字符可能会随机出现。使用支持HEX的编辑器尝试实验,然后它应该可以工作。如果找到很好的参考并且测试了HEX编辑器,我将更新我的答案。

更新:我尝试了一些著名的程序员编辑器,但是只有一个人可以立即使用MaëlHörz的HxD。我以前从未使用过HxD,但由于对此Stack文章(Notepad ++的十六进制查看器/编辑器插件)的回答而找到了它。

几分钟后仍无法使用的其他编辑器是Notepad ++,Notepad2和UltraEdit(v17.3,较旧的版本)。其中几个在复制/粘贴前几个字节(JPEG 文件签名魔术数字 FF D8 FF)时遇到问题。也许他们会比我现在有时间的工作更麻烦一些。


Sublime Text(2/3)通过以十六进制格式显示自动打开二进制文件。例如,只需单击“打开” 即可
断定

3
实际上,比记事本更经常地将LF转换为CRLF,它将以原样保留LF并显示文本,好像根本没有换行符!
Moshe Katz 2014年

6

过去,您可以使用当天回写操作来执行此操作。它是Windows 3.1中的标准程序,但我不记得Windows 95是否包含它。写入将允许二进制安全编辑它可以打开的任何文件(可能非常有限的文件大小)。记事本绝对不是二进制安全的(文本保持不变,但非文本字符的实际字节数(例如控制代码)可能会更改),这就是为什么JPG示例无法正常工作的原因。尝试获取Write(和非常旧的Windows)副本,然后重试实验!

根据Wikipedia的“ Windows Write”文章,Windows NT 3.5之前都包含Write。在Windows 95及更高版本中,它已被Wordpad取代。write.exe仍然存在于Windows目录中,但仅仅是打开写字板的包装。


5

我认为这不是编码的问题,而是字符集的问题。JPG格式基本上是字节流。因此,允许使用不可打印的字符,例如NUL,ETX,STX,SOH,DLE等。

Microsoft记事本无法显示那些不可打印的字符。它可能会显示某种占位符,例如一个空字符的空格。因此,使用记事本打开文件不会显示实际内容,而是通过所选编码(utf-8,utf-16等)解码并以特定字符集(unicode,ascii等)显示的内容,但非可打印的字符。

选择所有显示的文本并将其复制到剪贴板时,仅复制包括占位符的可打印字符。因此,自动将空字符转换为空格,并完全忽略其他不可打印的字符。

因此,基本上,您只是失去了这样做的内容。如果改用十六进制编辑器,它将完全复制所有内容。


更新:Bhathiya Pereras的答案是正确的:https ://superuser.com/a/782885/322784 将文本复制到剪贴板时,不可打印的字符不会被忽略。


每个文件都是“基本上是字节流”。
杰森C

1
@JasonC我不同意。虽然每个文件都可以作为字节流读取。XML文件之类的结构化文件不能作为数据流读取。在读取文件末尾之前,该内容将无效。切成两半的jpg仍然有效,并且可以显示。它只是丢失了一半的图片。
sbecker 2014年

在这方面确实没有分歧的余地。:) XML是字节流,就像其他任何字节一样,XML(以及字符编码)定义了这些字节的格式。作为数据流,它当然是可读的。例如,在十六进制编辑器中将其打开。该数据流恰好可以解析为XML。
杰森·C

@JasonC不能对此进行争论。:)触摸!
sbecker 2014年

2

JPEG文件除某些字段外包含非文本数据,基本上可以找到0到25​​5之间的任何字节值,尤其是在表示包含几乎伪随机数据的编码压缩图像的区域中。

但是默认情况下,记事本会将数据视为ANSI文本,因此它将执行各种更改原始数据的操作,例如:

  • 替换映射特殊/未定义/禁止字符的字节,因为它们对于有效的ANSI文本没有意义

  • 将空字符,行尾和文件序列结尾重新编码为Windows / DOS约定

这意味着,如果您将数据编辑并保存为文本,则最好的情况下将更改jpeg,最坏的情况下将使其不可用。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.