用户登录
用户注册

分享至

一个流中的多个流不会正确传递给客户端

  • 作者: 逗比男神你建哥
  • 来源: 51数据库
  • 2023-02-13

问题描述

在 WCF 服务中,我根据 这个问题 喜欢:

In WCF service I fill Stream according to this question like :

   result.Stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(result.Stream);
            foreach (string fileN in zipFiles)
            {
                byte[] fileBytes = File.ReadAllBytes(fileN);
                writer.Write(BitConverter.GetBytes(fileBytes.Length), 0, 4);
                writer.Write(fileBytes, 0, fileBytes.Length);
            }
            writer.Flush();
            return result; 

在此之前,我通过这个返回流,一切都在服务端和客户端运行:

before this I was returning stream by this and everything works in service and client side:

 result.Stream = new MemoryStream(File.ReadAllBytes(fileN));

流为 MessageBodyMember但 nut 现在将其更改为将所有文件保存在一个流中.

Stream be MessageBodyMember but nut now changed it to save all file in one stream.

和客户端的测试方法:

 ExportClient export = new ExportClient("exportEndPoint");
        ExportResult_C result = export.Export(source);
        result.Stream.Position = 0;
        //result.Stream.SaveToFile("d:\kkk.log");
        BinaryReader reader = new BinaryReader(result.Stream, System.Text.Encoding.UTF8);
        string pathToSave = string.Empty;
        while (result.Stream.Position < result.Stream.Length)
        {
            int size = reader.ReadInt32();
            byte[] data = reader.ReadBytes(size);
            pathToSave = "D:\test\" + new Random().Next(0, 2564586).ToString() + ".zip";
            File.WriteAllBytes(pathToSave, data);
        }

端点地址:

 <endpoint address="net.tcp://localhost:2082/Exchange/Export.svc" binding="netTcpBinding" bindingConfiguration="largeSizeStreamTcp"
    contract="xxx" name="exportEndPoint"/>

和绑定配置:

 <netTcpBinding>
    <binding openTimeout="00:00:03" maxReceivedMessageSize="2000000000" transferMode="Streamed" maxBufferSize="2000000000" >
      <readerQuotas maxDepth="32" maxArrayLength="2000000000" maxStringContentLength="2000000000" />
      <security mode="None" />
    </binding>
    <binding name="largeSizeStreamTcp"  transferMode="Streamed" receiveTimeout="00:30:00" sendTimeout="00:30:00" openTimeout="00:00:01" maxReceivedMessageSize="2000000000" maxBufferSize="2000000000" >
      <readerQuotas maxDepth="32" maxArrayLength="2000000000" maxStringContentLength="2000000000" />
      <security mode="None" />
    </binding>
  </netTcpBinding>
  <netNamedPipeBinding>

我相信端点和绑定是正确的,因为我能够返回一个文件流并将其保存回来,但现在服务端没有问题,但是当它从客户端获取时,流丢失了它的内容、长度、位置.

I believe endpoint and binding is correct as I was able to return one file stream and save it back but now there is no prob in service side but when it will get from client side, Stream got lost it's content,length,position.

这真的把我逼疯了!!!

this is really drive me up the wall!!!

有谁知道为什么会发生这种情况(在客户端)?

does anyone know why this is occurred(in client side) ?

推荐答案

哇,我终于成功地正确实现了我们的场景,将答案放在这里也许有人想使用该解决方案在一个流中返回多个文件.

Wooow, Finally I get success to implement our scenario properly, going to put the answer here maybe someone wants to use the solution to returns multiple files in one stream.

有几个示例可以返回多个文件,但它们都返回字节数组,由于多种原因,我更喜欢返回流,重要的是流对于大文件会表现得更好,因为并非所有文件都需要读取一次进入内存并向后兼容我的情况.

there are several sample to return multiple files but all of them are returning byte array, I prefer to return stream because of many reason, the important thing is streams will perform better for large files since not all of it needs to be read into memory at one time and backward compatibility for my case.

所以在第一步,我创建了一个可序列化的DataContract来保存文件的名称及其内容字节.

So at the first step I have created a serializable DataContract to hold the name of file and it's content byte.

[DataContract]
[Serializable]
public class ExportSourceFiles_C
{
    [DataMember]
    public string Name;
    [DataMember]
    public byte[] Content;
}

第二步,将创建??一个 ExportSourceFile_C 列表,如:

at the second step a list of ExportSourceFile_C will be created like:

List<ExportSourceFiles_C> sourceFiles = new List<ExportSourceFiles_C>();
string[] zipFiles = Directory.GetFiles(zipRoot);
foreach (string path in zipFiles)
  {
     byte[] fileBytes = File.ReadAllBytes(path);
     sourceFiles.Add(new ExportSourceFiles_C()
     {
         Name = Path.GetFileName(path),
         Content = fileBytes
     });
  }

第三步,提到的列表应该序列化为result.Stream,如:

at the third step the mentioned list should be serialized to result.Stream like:

  result.Stream = new MemoryStream();
  BinaryFormatter formatter = new BinaryFormatter();
  formatter.Serialize(result.Stream, sourceFiles);
  result.Stream.Position = 0;
  return result;

在客户端,这足以将流反序列化为 ExportSourceFiles_C 列表,因此客户端的最后一步应该是这样的:

in client side this is enough deserialize the stream to list of ExportSourceFiles_C so the last step in client side should be something like this:

 ExportClient export = new ExportClient("exportEndPoint");
 ExportResult_C result = export.Export(source);
 BinaryFormatter formatter = new BinaryFormatter();
 List<ExportSourceFiles_C> deserialisedFiles = (List<ExportSourceFiles_C>)formatter.Deserialize(result.Stream);
 foreach (ExportSourceFiles_C file in deserialisedFiles)
      File.WriteAllBytes("d:\" + file.Name, file.Content);

一切都像魅力一样,没有任何问题.

everything works like a charm without any problem.

享受.

软件
前端设计
程序设计
Java相关