【问题标题】:Best way to return large file as split zip files,Stream or Byte array WCF将大文件作为拆分 zip 文件、流或字节数组 WCF 返回的最佳方式
【发布时间】:2016-10-24 19:58:17
【问题描述】:

我已经将 zip 文件流返回给客户端,如下MessageContract:

[MessageContract]
public class ExportResult_C
{
    [MessageHeader]
    public PackedStudy_C[] PackedStudy
    {
        get;
        set;
    }

    [MessageBodyMember]
    public Stream Stream
    {
        get;
        set;
    }
}

当文件长度超过 500 MB 时,我决定将其拆分为 zip 部分。

场景:

1- 用户调用 Export 方法返回ExportResult_C

2- 如果请求的文件大于 500 MB,则将其拆分为较小的部分,每个部分的大小必须为 200MB。

3- 如果请求的文件小于 500 MB,则返回 MessageContract 和一个流。

描述:

为了向后兼容,我决定将 ExportResult_C 更改为具有两个属性,一个名为 Stream,它已经为文件小于 500 MB 时设计,另一个是流数组,用于保存所有 200 的拆分 zip MB 大小。

问题:

1- MessageContract 可以有另一个流的数组属性吗?

2- 如果没有,是否可以将 Stream 属性更改为 Stream 类型的数组?

3- 或者要实现上述场景,我必须完全更改合同,还是有更好的想法(在吞吐量和向后兼容性方面)?

【问题讨论】:

    标签: c# .net arrays wcf stream


    【解决方案1】:

    我想分享我的调查结果以及将大文件作为流传递给客户消费者的解决方案:

    问题一:

    这不可能有MessageBodyMemberStream 或任何其他类型,运行代码后你可能会得到如下异常:

    为了在 MessageContract 编程模型中使用 Streams,类型 yourMessageContract 必须有一个具有 MessageBodyMember 属性的成员,并且成员类型必须是 Stream。

    问题 2:

    我将合同更改为有一个名为 Stream 的道具成员,就像我想要的一样,Streams 是流数组:

     [MessageBodyMember]
        public Stream[] Streams 
        {
            get;
            set;
        }
    

    我的一段代码将大文件拆分为 zip 的一部分并将每个部分的流转换为Streams,例如:

     ZipFile zip = new ZipFile(); 
            if (!Directory.Exists(zipRoot))
                Directory.CreateDirectory(zipRoot);
            zip.AddDirectory(packageSpec.FolderPath, zipRoot);
            zip.MaxOutputSegmentSize = 200 * 1024 * 1024; // 200 MB segments
            zip.Save(fileName); 
            ExportResult_C result = null;
            if (zip.NumberOfSegmentsForMostRecentSave > 1)
            { 
                result = new ExportResult_C()
                {
                    PackedStudy = packed.ToArray(),
                    Streams = new Stream[zip.NumberOfSegmentsForMostRecentSave] 
                };
                string[] zipFiles = Directory.GetFiles(zipRoot);
                foreach (string fileN in zipFiles)
                {
                    Stream streamToAdd = new MemoryStream(File.ReadAllBytes(fileN));
                    result.Streams[zipFiles.ToList().IndexOf(fileN)] = streamToAdd;
                }
    
            }
            else
            {
                result = new ExportResult_C()
                {
                    PackedStudy = packed.ToArray(),
                    Streams = new Stream[1] { new MemoryStream(File.ReadAllBytes(fileName)) }
                };
            }
            return result;
    

    在编译时,当我们在MessageBodyMember 中有流数组时没有任何错误,一切正常,直到服务在运行时将数组流(代码中的result)传递给消费者,顺便说一句我交叉像这样的异常:

    套接字连接被中止。这可能是由于处理您的消息时出错或远程主机超出接收超时,或者是潜在的网络资源问题引起的。本地套接字超时为 '00:29:59.9895560'。

    问题 3:

    要实现上述场景,Contract 不应因向后兼容性而更改,因此合约具有像以前一样的消息正文流:

      [MessageBodyMember]
    public Stream Stream
    {
        get;
        set;
    }
    

    但我会将 zip 部分的流作为一个流写入Stream 的末尾,并且在客户端-服务器中将读取每个流作为文件的拆分

    解决方案:

    • 每个流的长度数为 4 字节

    • 每个流内容写在它的长度之后(4字节之后)

    最后流会是这样的

    流 = Part1 len + part1 stream content + part2 len + part2 stream content + ....

    任何关于答案的评论和帮助将不胜感激。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多