将大文件作为拆分的zip文件,流或字节数组WCF返回的最佳方法 [英] Best way to return large file as split zip files,Stream or Byte array WCF

查看:71
本文介绍了将大文件作为拆分的zip文件,流或字节数组WCF返回的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经将zip文件流作为以下 MessageContract 返回给客户端:

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

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

我决定在文件长度超过500 MB。



方案:



1-用户将调用Export方法,该方法返回 ExportResult_C



2-如果请求的文件大于500 MB,则将其拆分为较小的部分



3-如果请求的文件小于500 MB,则返回 MessageContract



Desc:



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



问题:



1- MessageContract 是否可以具有流的另一个数组道具?

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



3-还是要执行上述方案,我必须完全更改合同,或者有更好的主意(在吞吐量和向后兼容性方面)?

解决方案

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



问题1:



这不可能有 MessageBodyMember 要么是 Stream 或任何其他类型,在运行代码后,您可能会遇到如下异常:


在MessageContract编程模型中,类型yourMessageContract必须具有单个具有MessageBodyMember属性的成员,并且成员类型必须是Stream。


问题2:



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

  [MessageBodyMember] 
public Stream []流
{
get;
组;
}

我的一段代码将大文件分割为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的段
zip.Save(fileName);
ExportResult_C结果= null;
if(zip.NumberOfSegmentsForMostRecentSave> 1)
{
结果=新的ExportResult_C()
{
PackedStudy = packed.ToArray(),
流= new Stream [zip.NumberOfSegmentsForMostRecentSave]
};
string [] zipFiles = Directory.GetFiles(zipRoot);
foreach(zipFiles中的字符串fileN)
{
Stream streamToAdd = new MemoryStream(File.ReadAllBytes(fileN));
result.Streams [zipFiles.ToList()。IndexOf(fileN)] = streamToAdd;
}

}
其他
{
结果=新的ExportResult_C()
{
PackedStudy = packed.ToArray() ,
Streams = new Stream [1] {new MemoryStream(File.ReadAllBytes(fileName))}
};
}
返回结果;

在编译时,当我们在 MessageBodyMember ,一切正常,直到服务在运行时通过我穿越异常的方式将数组流(代码中的结果)传递给使用者像这样:


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


问题3:



要实现上述情况,合同不应因向后兼容而发生变化,因此合同具有像以前一样的消息正文流:

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

但是我要把zip部分的流写到<$的末尾c $ c> Stream 作为一个流,在客户端-服务器中将读取每个流的拆分文件



解决方案:




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


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




在最后的流中将是这样的



流= Part1 len + part1流内容+ part2 len + part2流内容+ ....



任何对答案的评论和帮助都会受到赞赏。


I have already return zip file stream to client as the following 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.

Scenario:

1- User will call Export method which returns ExportResult_C

2- If requested file is greater than 500 MB split it to smaller part that each section must have 200MB size.

3- If requested file is smaller than 500 MB return the MessageContract with one stream.

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.

Question:

1- Is that MessageContract can have another array prop of stream ?

2- If not, is it possible to change the Stream prop to array of Stream type ?

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)?

解决方案

I want to share the result of my investigation and my solution to pass big file as stream to client consumer:

Question 1:

this is not possible to have MessageBodyMember دeither Stream or any other type, after running code you may got an Exception as following:

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.

Question 2:

I changed the contract to have a prop member named Stream like what I was wanted, the Streams is array of stream:

 [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:

 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 :

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'.

Question 3:

To implement the mentioned scenario the Contract should not change for Backward-Compatibility so the contract have a message body stream like before:

  [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

solution:

  • 4 Byte for length number of each stream

  • each stream content write after it's length number(after 4 byte)

at the end stream will be something like this

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

any comment and help around the answer would be truly appreciated.

这篇关于将大文件作为拆分的zip文件,流或字节数组WCF返回的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆