题
我接收一些XML的文件具有嵌入的base64编码图像,即我需要解码并保存为文件。
这样的文件的未修改(压缩比其他)的例子可以在下面下载:
20091123-125320.zip (60KB)
不过,我得到“无效的长度为一的Base-64字符数组”和“无效字符在碱-64串”错误。我标记在我得到的错误代码中的代码行。
一个文件可能看起来像这样:
<?xml version="1.0" encoding="windows-1252"?>
<mediafiles>
<media media-type="image">
<media-reference mime-type="image/jpeg"/>
<media-object encoding="base64"><![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]></media-object>
<media.caption>What up</media.caption>
</media>
</mediafiles>
和的代码来处理这样的:
var xd = new XmlDocument();
xd.Load(filename);
var nodes = xd.GetElementsByTagName("media");
foreach (XmlNode node in nodes)
{
var mediaObjectNode = node.SelectSingleNode("media-object");
//The line below is where the errors occur
byte[] imageBytes = Convert.FromBase64String(mediaObjectNode.InnerText);
//Do stuff with the bytearray to save the image
}
在XML的数据是从企业报系统,所以我敢肯定这些文件是确定 - 并且必须有东西在我处理它们的方式,这是绝对错误的。可能与编码的问题?
我试图写出mediaObjectNode.InnerText的内容,并且它是base64编码数据 - 这样的导航XML的文档不是问题
。我一直在谷歌上搜索,暴食,stackoverflowing和哭泣! - 和发现无解...帮助
编辑:
添加了一个实际的例子文件(和奖金)。请注意,可下载的文件是在一个位不同的模式,因为我在上面的例子简化它,除去不相干的东西...
解决方案
有关的第一镜头我没有使用任何编程语言,只是记事本++
我打开内的XML文件,并复制和粘贴的原始内容的base64到一个新文件(方括号)。
然后我选择一切(STRG-A)和所使用的选项扩展 - 默工具 - Base64的解码。这引发了有关错误错误的文本长度(必须国防部4)。所以,我刚添加两个等号(“=”)作为占位符在端部,以获得正确的长度。
另一重试和它成功地解码成“东西”。只是将文件保存为jpg和它打开像任何图片浏览器一个魅力。
所以,我要说,有什么不对的,你会得到的数据。他们只是不具备的等号右边的数字在年底填补了一些迹象可以打入的4个包。
在“易”的方式是添加等号直到解码不会引发错误。更好的方式是计算字符数(减去CR / LF类!)的数量和在一个步骤中添加所需的。
进一步的研究
只是为了赏金,这里是我的代码(不是一个很好的出发点绝对完美,但足够); - )
static void Main(string[] args)
{
var elements = XElement
.Load("test.xml")
.XPathSelectElements("//media/media-object[@encoding='base64']");
foreach (XElement element in elements)
{
var image = AnotherDecode64(element.Value);
}
}
static byte[] AnotherDecode64(string base64Decoded)
{
string temp = base64Decoded.TrimEnd('=');
int asciiChars = temp.Length - temp.Count(c => Char.IsWhiteSpace(c));
switch (asciiChars % 4)
{
case 1:
//This would always produce an exception!!
//Regardless what (or what not) you attach to your string!
//Better would be some kind of throw new Exception()
return new byte[0];
case 0:
asciiChars = 0;
break;
case 2:
asciiChars = 2;
break;
case 3:
asciiChars = 1;
break;
}
temp += new String('=', asciiChars);
return Convert.FromBase64String(temp);
}
其他提示
如奥利弗已经说过,去除空格字符后的字符串的长度必须是4的倍数的基于64串不是有效的。如果你看一下然后结束的base64字符串(见下文),你会看到该行是比其他人短。
RRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=
如果您删除这条线,你的程序将正常工作,但由此产生的图像将在右下角缺少的部分。您需要垫此行,总字符串长度corect。从我的计算,如果你有3个字符它应该工作。
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=
除去最后2个字符,而图像不会得到正确的
public Image Base64ToImage(string base64String)
{
// Convert Base64 String to byte[]
byte[] imageBytes=null;
bool iscatch=true;
while(iscatch)
{
try
{
imageBytes = Convert.FromBase64String(base64String);
iscatch = false;
}
catch
{
int length=base64String.Length;
base64String=base64String.Substring(0,length-2);
}
}
MemoryStream ms = new MemoryStream(imageBytes, 0,
imageBytes.Length);
// Convert byte[] to Image
ms.Write(imageBytes, 0, imageBytes.Length);
Image image = Image.FromStream(ms, true);
pictureBox1.Image = image;
return image;
}
尝试使用LINQ到XML:
using System.Xml.XPath;
class Program
{
static void Main(string[] args)
{
var elements = XElement
.Load("test.xml")
.XPathSelectElements("//media/media-object[@encoding='base64']");
foreach (var element in elements)
{
byte[] image = Convert.FromBase64String(element.Value);
}
}
}
更新:
下载XML文件和media-object
节点的分析值之后很显然,它是不是一个有效的base64字符串:
string value = "PUT HERE THE BASE64 STRING FROM THE XML WITHOUT THE NEW LINES";
byte[] image = Convert.FromBase64String(value);
抛出一个System.FormatException
说,长度不是有效的基部64的字符串。事件当我删除字符串中的\n
这是行不通的:
var elements = XElement
.Load("20091123-125320.xml")
.XPathSelectElements("//media/media-object[@encoding='base64']");
foreach (var element in elements)
{
string value = element.Value.Replace("\n", "");
byte[] image = Convert.FromBase64String(value);
}
也会引发System.FormatException
。
我也有与编码从XML文档(特别是Office OpenXML的包文件)串解码的Base64的问题。
原来字符串已经施加附加编码:HTML编码,这样做第一HTML解码,然后解码的Base64没有的伎俩:
private static byte[] DecodeHtmlBase64String(string value)
{
return System.Convert.FromBase64String(System.Net.WebUtility.HtmlDecode(value));
}
以防万一就同一问题别人绊倒。
好了,这一切都非常简单。 CDATA
是节点本身,因此mediaObjectNode.InnerText
实际上产生<![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]>
,这显然不是有效的Base64编码数据。
要使事情工作,使用mediaObjectNode.ChildNodes[0].Value
并传递该值Convert.FromBase64String'
。
时的字符编码正确的吗?错误听起来像有导致无效字符数组中出现的问题。尝试复制出来的文字和手动解码以查看该数据是否确实有效。
(根据记录,窗口1252是不完全一样的ISO-8859-1,因此这可能是一个问题的原因,除非腐败的其他来源。)