在Java中进行base64编码并在C#中进行解码

4

我需要将一个文件发送到我的webservice,但是webservice假定文件(字节数组)是base64Binary格式。

在编码之前,byteArrayFile被保存在磁盘上作为一个普通的文件。(我只是为了测试这个功能)

所以,在我的Java客户端中,我通过以下方式发送信息:

String file = new sun.misc.BASE64Encoder().encode(byteArrayFile);
port.sendFileToWebService(file);

这个Web服务需要解码信息并将接收到的文件保存在磁盘上。

    [WebMethod]
    public string sendFileToWebService(string file)
    {

        string dirname = HttpContext.Current.Request.PhysicalApplicationPath + "\\Attachments\\";
        if (!System.IO.Directory.Exists(dirname))
        {
            System.IO.Directory.CreateDirectory(dirname);
        }
        string filename = dirname + "/" + "file.sim";
        WebClient myWebClient = new WebClient();
        myWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
        byte[] byteArray = null;

        byteArray = Convert.FromBase64String(file.Replace("\n", ""));

        byte[] responseArray = myWebClient.UploadData(filename, "POST", byteArray);
        return "Webservice says OK";
    }

问题是:
保存在磁盘上的文件(编码之前)和使用C#解码后的文件不相等。 我不知道这是Java编码还是C#解码的问题。
任何建议,包括更改文件类型或逻辑处理,将始终受到赞赏。
提前感谢!
编辑 - 文件比较:
原始文件链接: http://img819.imageshack.us/img819/820/originalu.png 解码后的文件链接(经过Java编码): http://img826.imageshack.us/img826/3184/processed.png

原始文件保存在我的本地磁盘上。另一个文件被发送到Web服务,该服务将文件保存在服务器磁盘上。我能够访问这两个位置,并使用Notepad++打开文件并确认两个文件的大小和内容都不同。 - CalypsOOO
你的 C# 代码中为什么要使用 WebClient? - nos
我不确定...我从一个论坛上复制了这段代码。 - CalypsOOO
尝试使用普通文件I/O将字节数组写入文件,使用WebClient似乎非常不可靠。 - nos
1
@CalypsOOO 我认为你“从论坛上复制这段代码”是你问题的核心。:) 具体来说,你不需要用base-64或web客户端,这样只会让事情更加复杂。想想你想要做什么(将二进制数据发送/接收到/从Web服务)并查找最佳做法。 - bzlm
当您在客户端读取base64编码的文本时,是否将其读入缓冲区中?Base64读取四个字节并写入三个字节。如果您从InputSteam或GZipStream中读取,则它可能不会返回一个长度可以被四整除的缓冲区。 - JoshRoss
2个回答

3
我知道XSD标准规定了一种名为base64Binary的数据类型。这应该允许您的[WebMethod]参数是一个byte[]。然后底层服务堆栈将把字节数组编码为base64字符串。
例如,我刚刚做了一个快速的Java服务如下:
   @WebMethod(operationName = "TestByteArray")
    public void testByteArray(byte[] data) {

    }

以下是生成的WSDL文件中相关部分:

<operation name="TestByteArray">
    <input wsam:Action="jordan.services/EncodingTests/TestByteArrayRequest" message="tns:TestByteArray"/>
    <output wsam:Action="jordan.services/EncodingTests/TestByteArrayResponse" message="tns:TestByteArrayResponse"/>
</operation>

<xs:complexType name="TestByteArray">
    <xs:sequence>
        <xs:element name="arg0" type="xs:base64Binary" nillable="true" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

我也在 .Net 中进行了一次测试:

[WebMethod]
public void testByteArray(byte[] bytes) {
}

生成的WSDL文件中相关部分:

<wsdl:portType name="TestWSSoap">
    <wsdl:operation name="testByteArray">
        <wsdl:input message="tns:testByteArraySoapIn"/>
        <wsdl:output message="tns:testByteArraySoapOut"/>
    </wsdl:operation>
</wsdl:portType>

<wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
        <s:element name="testByteArray">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="bytes" type="s:base64Binary"/>
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="testByteArrayResponse">
            <s:complexType/>
        </s:element>
    </s:schema>
</wsdl:types>

谢谢。非常有帮助的评论。 我的问题与Java和C#之间的base64编码和解码有关。 - CalypsOOO
1
@CalypsOOO - 我的建议是您在进行WS调用之前/之后不需要执行base64编码。只需发送原始字节数组即可。当您在c#中接收它时,只需发布字节数组(或直接写出它)。如果您在发送之前进行编码,则会通过电线发送xsd:string而不是您在问题的第一句话中提到的xsd:base64Binary。 - Jordan S. Jones
嗯,好的。抱歉,我之前没有理解你的建议。 你之前测试过吗?我认为base64Binary是一个字符串,因为将任何内容编码为base64Binary都会返回一个字符串。 类似的问题在这里:http://stackoverflow.com/questions/2551525/failed-sending-bytes-array-to-jax-ws-web-service-on-axis - CalypsOOO
2
@CalypsOOO,是的,我之前已经测试过了。当你通过一个类型为base64Binary的webservice传递一个字节数组时,底层的webservice堆栈会为你将二进制数组转换为base64字符串。然后在服务器上,当请求到达时,它会将其解码回字节数组。我的建议是尝试一下。 - Jordan S. Jones
非常感谢!你说得完全正确!如果它被定义为byteArray,我们必须发送一个byteArray。谢谢! - CalypsOOO

1
尝试使用普通文件 I/O 而不是 WebClient。
public string sendFileToWebService(string file)
{

    string dirname = HttpContext.Current.Request.PhysicalApplicationPath + "\\Attachments\\";
    if (!System.IO.Directory.Exists(dirname))
    {
        System.IO.Directory.CreateDirectory(dirname);
    }
    string filename = dirname + "/" + "file.sim";
    byte[] byteArray = Convert.FromBase64String(file);
    File.WriteAllBytes(filename, byteArray ); //might wanna catch exceptions that could occur here
    return "Webservice says OK";
}

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