这个现象一直让我产生疑问。
以下是详细的实验,我的操作系统是Windows 7 x64 SP1:
- 我通过简单地更改其扩展名将图片(JPG)文件更改为 TXT(或者也可以选择用记事本打开 JPG,同样的事情)
它看起来应该是这样的,奇怪的文本序列,其中一些(非常罕见)实际上是有意义的,就像下面的屏幕截图“创建者:dg-jpeg v1.0...”
- 我禁用了换行并使用 Ctrl+A 选择了所有文本(以确保没有遗漏任何内容)
- 我将复制的文本粘贴到另一个空白 TXT 文件中,并将其另存为 JPG,然后比较新文件与原始 JPG 的大小。它们(原始 JPG、转换后的 TXT 文件和新创建的 TXT 文件)的大小都一样精确的大小相同,以字节为单位。
当我尝试打开时,Windows 会说“Windows 照片查看器无法打开此图片,因为该文件似乎已损坏、损坏或太大”。
我甚至尝试使用另一种方法进行测试:用记事本打开 JPG,然后剪切一从一个容易记住的位置(例如第二行的第一个字符)找到已知字符,然后保存文件。查看器当然会显示相同的消息。然后我再次打开它并将字符粘贴到精确的位置(记事本会记住其退出状态,如窗口位置、换行、字体大小……因此我可以毫无问题地正确执行此操作)
还是同样的错误。你可以尝试一下,以了解其中的原理,记得选择一张小图片,否则记事本会像一个生锈的老人。
造成这种现象的原因是什么?
答案1
根据打开文件时使用的编码,您可能会看到不同的行为。我的 Windows 7 记事本允许以 ANSI、UTF-8、Unicode 或 Unicode big endian 打开文件。
我用一张用 gimp 创建的 2x2 像素的 jpeg 小图像测试了这个问题,并用 ANSI 编码打开和保存了该图像文件。用十六进制编辑器打开原始图像和保存的图像后,我发现所有 00 序列(两个十六进制数字,NUL 控制字符)已转换为20(空格字符)。
在十六进制编辑器中将所有 20 替换为 00 可恢复图像格式。
我在 Google 上搜索了一下,没有找到任何参考资料来解释为什么会这样。只有引用一篇对此提出警告的帖子(谷歌缓存链接,页面不可用)。
如果您将文件保存/打开为 UTF-8,它似乎仍会将 NUL 字符转换为空格,但由于从单字节字符转换为 UTF-8 多字节序列,它也会增加生成的文件大小。
如果你将文件保存/打开为 Unicode,它似乎仍然会将 NUL 字符转换为空格,但也会在文件开头添加一个字节,物料清单。
答案2
失败原因:
(ASCII code 32)
记事本为类似字符创建空格字符空值 (ASCII code 0)
因为 Windows API 的文本框只允许以空字符结尾char *
ASCIIZ(字符数组,指针)。它在第一个 NUL 处被切断。
发生这种情况是因为Windows API主要写于C语言和以空字符结尾的字符串是常见特征之一。即使考虑到现代 Windows 和 Unicode,也会出现相同的以空字符结尾的字符串。因此,记事本只需将它们替换为空格,即可查看完整文件。
因此当您保存文件时它已损坏。
如何进行进一步研究:
您可以使用类似的比较器无可比拟(商业,试用)查看字符替换效果。另请参阅其他二进制比较工具。
笔记:(20)16 =(32)10
记事本处理大文件速度慢的原因
它检查每个字符并用空格替换特殊字符。其他软件不进行内存转换(至少不像记事本那样简单)。它们只是以不同的方式呈现特殊字符。并且它们使用高级缓冲技术。查看 Notepad.exe(XP 32 位)
(我假设它仍然是用 C++ 编写的,或者至少使用类似的链接器)
我正在使用聚乙烯亚胺工具(由于引入 PE+/64 exe 而停止开发)
PEiD 位于通用提取器
我显然是从 Windows xp iso 中提取了 notepad.ex_ 文件。试试看。这是使用 7z 提取的 cab 文件。
警告!您的病毒扫描程序可能会将 Universal Extractor/PEiD 检测为黑客工具或病毒。不要相信它,不要下载它!!
有关 Windows API 的更多信息
致谢:杰森·C
它不仅仅是文本框;WM_SETTEXT通常不提供用于指定字符串长度的参数,并且字符串始终假定为以 null 结尾。您始终可以创建一个带有指定字符串长度的自定义消息的自定义文本框,但记事本和大多数其他程序合理地不这样做。此外,函数设置窗口文本也没有提供长度参数。
答案3
记事本不会保留所有特殊/扩展字符。我手头没有关于此行为的参考资料,但我发现例如 UNIX 样式的行尾 LF 就是这种情况,记事本会将其转换为 CRLF 和空 (0x00),并忽略这些字符。在二进制文件(例如 JPG)中,可能会随机出现记事本不会保留的字符。尝试使用支持十六进制的编辑器进行实验,然后它应该会起作用。如果我找到好的参考资料并测试了十六进制编辑器,我会更新我的答案。
更新:我尝试了一些知名的程序员编辑器,但只有其中一个能立即工作,Maël Hörz 拍摄的 HxD。我以前从未使用过 HxD,但多亏了这篇 Stack 文章的回答,我找到了它,Notepad++ 的十六进制查看器/编辑器插件。
经过几分钟的努力后,其他无法正常工作的编辑器是 Notepad++、Notepad2 和 UltraEdit(v17.3,旧版本)。其中几个在复制/粘贴前几个字节时出现问题,JPEG文件签名魔法数字FF D8 FF。也许他们还需要再多花点时间才能完成我现在的工作。
答案4
我认为这不仅仅是编码问题,也是字符集问题。JPG 格式基本上是字节流。因此允许使用不可打印的字符,如 NUL、ETX、STX、SOH、DLE 等。
Microsoft Notepad 无法显示这些不可打印的字符。它可能会显示某种占位符,例如空格作为空字符。因此,使用记事本打开文件不会显示实际内容,而是显示按所选编码(utf-8、utf-16 等)解码的内容,并按特定字符集(unicode、ascii 等)显示,但不包括不可打印的字符。
当选择所有显示的文本并将文本复制到剪贴板时,您只复制可打印字符(包括占位符)。因此会自动将空字符转换为空格,并完全忽略其他不可打印字符。
所以基本上你这样做只会丢失内容。如果你改用十六进制编辑器,它会完全复制所有内容。
更新:Bhathiya Pereras 的答案是正确的:https://superuser.com/a/782885/322784 将文本复制到剪贴板时不会忽略不可打印的字符。