最好的方式来返回大文件分割压缩文件,流或字节数组WCF
本文关键字:文件 字节 WCF 数组 字节数 压缩 分割 方式 返回 | 更新日期: 2023-09-27 18:13:25
我已经返回zip文件流到客户端如下MessageContract
:
[MessageContract]
public class ExportResult_C
{
[MessageHeader]
public PackedStudy_C[] PackedStudy
{
get;
set;
}
[MessageBodyMember]
public Stream Stream
{
get;
set;
}
}
当文件长度超过500mb时,我决定将其拆分为zip部分。
场景:
1-用户将调用导出方法返回ExportResult_C
2-如果请求的文件大于500mb,将其分割成更小的部分,每个部分必须有200MB的大小。
3-如果请求的文件小于500 MB,返回一个流的MessageContract
。
Desc:
为了向后兼容性,我决定将ExportResult_C
更改为具有两个属性,一个名为Stream
,它已经为文件小于500 MB而设计,另一个将是流数组,以容纳所有拆分zip,大小为200 MB。
问题:
1- MessageContract
可以有另一个流的数组道具吗?
2-如果没有,是否可以将Stream
prop更改为流类型的数组?
3-或者为了实现上述场景,我必须完全更改合约,或者有更好的想法(在吞吐量和向后兼容性方面)?
我想分享我的调查结果和我的解决方案,将大文件作为流传递给客户端消费者:
问题1:
这是不可能有MessageBodyMember
دeither Stream
或任何其他类型,运行代码后,你可能会得到一个异常如下:
为了在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
)到消费者在运行时,顺便说一下,我越过异常,如:
socket连接被终止。这可能是由于处理消息时出现错误、远程主机超过接收超时或底层网络资源问题造成的。本地套接字超时'00:29:59.9895560'.
问题3:
为了实现上述场景,Contract
不应该为了向后兼容性而改变,所以合约有一个像以前一样的消息体流:
[MessageBodyMember]
public Stream Stream
{
get;
set;
}
但是我将把zip部分的流作为一个流写入Stream
的末尾,并且在客户端-服务器中将被读取并将每个流分割为文件
解决方案:
每个流的长度为4字节
每个流内容在它的长度之后写入(在4字节之后)
应该是这样的
Stream = Part1 len + part1 stream content + part2 len + part2 stream content + ....
任何关于答案的评论和帮助都将是非常感谢的。