解码base64字符串并写入文件

39

我正在尝试读取包含编码的base64字符串的文件,并将解码后的输出写入另一个文件。我的Input.txt文件包含一个类似于base64字符串的内容:

PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48cmV2aWV3LWNhc2UgY3JlYXRl\r\nZGF0ZT0iMTMvTWFyLzIwMTQgMDk6MDQ6NTEiIHN5c3RlbT0iVHJhZmlndXJhX1RlbXBsYXRlX01h\r\nbmFnZW1lbnRfdjUuMSIgYmF0Y2hpZD0iMCIgdHJhbnNhY3Rpb25ubz0iMSIgYmF0Y2huYW1lPSJH\r\nVUlEKGY1NWRmYjgwODQ4ZDQ3YzliZmVhYTg3YzMyZDQyNDQyKS1HTE9CQUxfSU5WT0lDRS1FTkdM\r\nSVNIIiB2ZXJzaW9uPSI1LjEuMi44ICBidWlsZCA1MjUzOSI+PHRyYW5zYWN0aW9uPjxvYmplY3Rz\r\nPjxvYmplY3QgY2xhc3M9IlRoXzE5NTQwMDk3OTRfNl9tb2RlbCIgbmFtZT0ibW9kZWwiPjxwcm9w\r\nZXJ0eSBuYW1lPSJUaXRsZSIgdmFsdWU9IlByb3Zpc2lvbmFsIEludm9pY2UiLz48cHJvcGVydHkg\r\nbmFtZT0iR3JvdXBDb21wYW55Ij48b2JqZWN0IGNsYXNzPSJUaF8xOTU0MDA5Nzk0XzZfR3JvdXBD\r\nb21wYW55IiBuYW1lPSJHcm91cENvbXBhbnkiPjxwcm9wZXJ0eSBuYW1lPSJOYW1lIiB2YWx1ZT0i\r\nVHJhZmlndXJhIEJlaGVlciBCLlYuIEFNU1RFUkRBTSwgQlJBTkNIIE9GRklDRSBMVUNFUk5FIi8+\r\nPHByb3BlcnR5IG5hbWU9IkFkZHJlc3MiIHZhbHVlPSJaPz9yaWNoc3RyYXNzZSAzMSIgaW5kZXg9\r\nIjAiLz48cHJvcGVydHkgbmFtZT0iQWRkcmVzcyIgdmFsdWU9Ikx1Y2VybmUiIGluZGV4PSIxIi8+\r\nPHByb3BlcnR5IG5hbWU9IkFkZHJlc3MiIHZhbHVlPSI2MDAyIiBpbmRleD0iMiIvPjxwcm9wZXJ0\r\neSBuYW1lPSJBZGRyZXNzIiB2YWx1ZT0iU3dpdHplcmxhbmQiIGluZGV4PSIzIi8+PHByb3BlcnR5\r\nIG5hbWU9IlBob25lTnVtYmVyIiB2YWx1

这个字符串是使用Java apache codec.binary.Base64库在服务器端创建的。当两个不同的Web服务之间通信时,使用Fiddler捕获了此字符串。有时我无法访问另一个Web服务,这就是为什么我要嗅探服务之间的消息。此外,我使用Ruby自动化一些例行任务,并决定再次使用Ruby。为了对捕获的base64字符串进行编码,我使用以下代码片段:

require "base64"

content = File.read('Input.txt')
decode_base64_content = Base64.decode64(content) 
File.open("Output.txt", "wb") do |f|
  f.write(decode_base64_content)
end 

但输出结果看起来是格式不正确的,像<?xml version="1.0" encoding="UTF-8"?><review-case create®vFFSТ#2фЦ"у#B“ЈCЈS"7—7FVУТ%G&f–wW&хFVЧЖFUфЦзnagement_v5.1" ba等等。您可以指导我做错了什么吗?我在Windows 7和Ubuntu 12.04上使用Ruby 1.9.3。


你的代码看起来没问题。尝试使用严格的decode64,看看会抛出什么错误。 - SreekanthGS
是的,你能为我们提供一个编码字符串吗(不是敏感的那个,但请找出用于创建它的方法并在此处发布,以及一个编码示例或其他内容)。 - Mike H-R
嗯,Java的Apache Base64库文档提到了RFC 2045,所以常规的decode应该是最好的选择。然而,它会告诉你行分隔符(默认)是CRLF ("\r\n"),这在你的示例中有所体现。你在Windows和Ubuntu上得到了相同的结果吗?我不知道不同的行尾是否会混淆Base64,但至少存在这种可能性。尝试使用Ruby对已知明文进行编码,并比较生成的字节序列。 - Patru
结果在Windows和Ubuntu上是相同的。当我尝试使用strict_decode64时,我会收到“invalid base64 (ArgumentError)”错误,因为根据文档,“如果str填充不正确或包含非字母字符,则会引发ArgumentError”。 - olyv
1
@MikeH-R Base64模块的文档告诉你:“返回bin的Base64编码版本。此方法符合RFC 2045。每60个编码字符添加换行符。”因此,它可能不会期望额外的CR,请使用gsub("\r", '')去掉它。decode64(可能)能够处理长度为76的行。 - Patru
显示剩余4条评论
1个回答

42

我不知道你是如何做到的,但是你字符串中的换行符\r\n似乎以4字节的字符序列形式存在,而不是2字节的转义CRLF。如果我将你的文件复制到使用单引号的 ruby 字符串中:

unescaped='PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48cmV2aWV3LWNhc2UgY3JlYXRl\r\nZGF0ZT0iMTMvTWFyLzIwMTQgMDk6MDQ6NTEiIHN5c3RlbT0iVHJhZmlndXJhX1RlbXBsYXRlX01h\r\nbmFnZW1lbnRfdjUuMSIgYmF0Y2hpZD0iMCIgdHJhbnNhY3Rpb25ubz0iMSIgYmF0Y2huYW1lPSJH'
Base64.decode64(unescaped)
#=> garbled text for every second line

如果我使用双引号(这些引号将会保留转义字符)做同样的操作:

escaped="PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48cmV2aWV3LWNhc2UgY3JlYXRl\r\nZGF0ZT0iMTMvTWFyLzIwMTQgMDk6MDQ6NTEiIHN5c3RlbT0iVHJhZmlndXJhX1RlbXBsYXRlX01h\r\nbmFnZW1lbnRfdjUuMSIgYmF0Y2hpZD0iMCIgdHJhbnNhY3Rpb25ubz0iMSIgYmF0Y2huYW1lPSJH"
Base64.decode64(escaped)
#=> all is well that ends well

因此,问题似乎出现在你写文件时。不过在 Ruby 中可以进行修正:

unescaped='PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48cmV2aWV3LWNhc2UgY3JlYXRl\r\nZGF0ZT0iMTMvTWFyLzIwMTQgMDk6MDQ6NTEiIHN5c3RlbT0iVHJhZmlndXJhX1RlbXBsYXRlX01h\r\nbmFnZW1lbnRfdjUuMSIgYmF0Y2hpZD0iMCIgdHJhbnNhY3Rpb25ubz0iMSIgYmF0Y2huYW1lPSJH'
Base64.decode64(unescaped)
escaped=unescaped.gsub('\\r', "\r").gsub('\\n', "\n")
Base64.decode64(escaped)
#=> now you should be fine again

但是正确的解决方案当然应该是正确地存储文件。

针对您当前的文件,以下方法应该可行:

require "base64"

content = File.read('Input.txt')
content.gsub!('\\r', "\r")
content.gsub!('\\n', "\n")
decode_base64_content = Base64.decode64(content) 
File.open("Output.txt", "wb") do |f|
  f.write(decode_base64_content)
end

如果没有输出,请发表一些输出。


如果我在Ruby文件中使用双引号并指定编码字符串,它就能工作。但是,如果我尝试从文件中获取编码字符串,仍然没有成功。感谢您的帮助。至少它能工作了,如果没有其他变体被建议,我应该接受您的答案。 - olyv
1
@olyv:为什么你写文件的方式是这样的?应该使用适当的换行符(在任何约定中)而不是转义字符来编写它。如果按照你的示例代码读取整个文件,应该通过添加content.gsub!('\\ r',"\ r")content.gsub!('\\ n',"\ n")进行解码(注意感叹号,gsub!将直接修改字符串而不是创建副本)。 - Patru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接