简体   繁体   English

将大文件作为拆分的zip文件,流或字节数组WCF返回的最佳方法

[英]Best way to return large file as split zip files,Stream or Byte array WCF

I have already return zip file stream to client as the following MessageContract : 我已经将zip文件流作为以下MessageContract返回给客户端:

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

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

I have decided to split it to zip parts when the file length is more than 500 MB. 当文件长度超过500 MB时,我决定将其拆分为zip部分。

Scenario: 场景:

1- User will call Export method which returns ExportResult_C 1-用户将调用Export方法,该方法返回ExportResult_C

2- If requested file is greater than 500 MB split it to smaller part that each section must have 200MB size. 2-如果请求的文件大于500 MB,则将其拆分为较小的部分,即每个部分的大小必须为200MB。

3- If requested file is smaller than 500 MB return the MessageContract with one stream. 3-如果请求的文件小于500 MB,则返回一个流的MessageContract

Desc: 描述:

For backward compatibility I have decided to change ExportResult_C to have two properties one named Stream which already designed for when file is smaller than 500 MB and the other one will be array of stream to hold all split zip with 200 MB of size. 为了向后兼容,我决定将ExportResult_C更改为具有两个属性,一个名为Stream ,该属性已经设计用于文件小于500 MB的情况,另一属性将是流的数组,以容纳200 MB大小的所有拆分zip。

Question: 题:

1- Is that MessageContract can have another array prop of stream ? 1- MessageContract可以有另一个流数组支持吗?

2- If not, is it possible to change the Stream prop to array of Stream type ? 2-如果不是,是否可以将Stream属性更改为Stream类型的数组?

3- Or to implement mentioned scenario I have to change the contract completely or is there any better idea (in terms of throughput and backward-compatibility)? 3-或者要实施上述方案,我必须完全更改合同,或者有更好的主意(在吞吐量和向后兼容性方面)?

I want to share the result of my investigation and my solution to pass big file as stream to client consumer: 我想分享我的调查结果和将大文件作为流传递给客户消费者的解决方案:

Question 1: 问题1:

this is not possible to have MessageBodyMember دeither Stream or any other type, after running code you may got an Exception as following: 这不可能使MessageBodyMember具有Stream或任何其他类型,在运行代码之后,您可能会收到如下异常:

In order to use Streams with the MessageContract programming model, the type yourMessageContract must have a single member with MessageBodyMember attribute and the member type must be Stream. 为了将Streams与MessageContract编程模型一起使用,类型yourMessageContract必须具有具有MessageBodyMember属性的单个成员,并且成员类型必须为Stream。

Question 2: 问题2:

I changed the contract to have a prop member named Stream like what I was wanted, the Streams is array of stream: 我将合同更改为像我想要的那样有一个名为Stream的支持成员, StreamsStreams的数组:

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

my piece of code to split big file to parts of zip and make stream of each part into Streams like: 我的一段代码将大文件拆分为zip部分,并将每个部分的Streams转换为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;

At the compile time there is no any error when we have array of stream in MessageBodyMember , everything works fine until the service is passing array stream ( result in code) to consumer at runtime, by the way I cross the Exception like : 在编译时,当我们在MessageBodyMember拥有流数组时,没有任何错误,直到服务在运行时通过我穿越Exception的方式将数组流(代码中的result )传递给使用者时,一切都可以正常工作:

The socket connection was aborted. 套接字连接已中止。 This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. 这可能是由于处理您的消息时出错,远程主机超出了接收超时或潜在的网络资源问题引起的。 Local socket timeout was '00:29:59.9895560'. 本地套接字超时为“ 00:29:59.9895560”。

Question 3: 问题3:

To implement the mentioned scenario the Contract should not change for Backward-Compatibility so the contract have a message body stream like before: 为了实现上述场景, Contract不得因向后兼容而更改,因此合同应具有像以前一样的消息正文流:

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

but I am going to write stream of the zip part to end of Stream as one stream and in client-server will be read an split each stream as file 但是我将zip部分的Stream作为一个流写入到Stream末尾,并且将在客户端服务器中读取每个流作为文件的拆分

solution: 解:

  • 4 Byte for length number of each stream 每个流的长度数字为4字节

  • each stream content write after it's length number(after 4 byte) 每个流内容在其长度数字之后写入(4个字节后)

at the end stream will be something like this 最后的流将是这样的

Stream = Part1 len + part1 stream content + part2 len + part2 stream content + .... 流=第1 Part1 len + part1 stream content + part2 len + part2 stream content + .... 1 Part1 len + part1 stream content + part2 len + part2 stream content + ....

any comment and help around the answer would be truly appreciated. 任何评论和围绕答案的帮助将不胜感激。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM