我有一个 C# WPF 应用程序,其中一个部分用作 FTP 客户端,列出远程服务器上的文件并允许用户下载它们。我希望用户能够将文件从文件列表拖放到他们自己的机器上(即进入 Windows 资源管理器外壳)。
为此,我使用了Delay 博客中的 VirtualFileDataObject 代码Action<Stream>
,使用SetData
. 这适用于较小的文件。
我的问题是:我正在处理的一些文件非常大(2+ GB),并且VirtualFileDataObject
该类处理流的方式涉及将整个内容读入内存,这最终可能会引发“存储空间不足”错误对于那些非常大的文件。
代码的相关部分VirtualFileDataObject
如下。如何重写此代码以不需要整个流都在内存中?
public void SetData(short dataFormat, int index, Action<Stream> streamData) {
_dataObjects.Add(
new DataObject {
FORMATETC = new FORMATETC {
cfFormat = dataFormat,
ptd = IntPtr.Zero,
dwAspect = DVASPECT.DVASPECT_CONTENT,
lindex = index,
tymed = TYMED.TYMED_ISTREAM
},
GetData = () => {
// Create IStream for data
var ptr = IntPtr.Zero;
var iStream = NativeMethods.CreateStreamOnHGlobal(IntPtr.Zero, true);
if (streamData != null) {
// Wrap in a .NET-friendly Stream and call provided code to fill it
using (var stream = new IStreamWrapper(iStream)) {
streamData(stream);
}
}
// Return an IntPtr for the IStream
ptr = Marshal.GetComInterfaceForObject(iStream, typeof(IStream));
Marshal.ReleaseComObject(iStream);
return new Tuple<IntPtr, int>(ptr, NativeMethods.S_OK);
},
});
}
特别是,这部分GetData
是罪魁祸首:
// Wrap in a .NET-friendly Stream and call provided code to fill it
using (var stream = new IStreamWrapper(iStream)) {
streamData(stream);
}
streamData
是Action<stream>
我提供的将实际文件数据写入流的。我的代表只是打开一个文件并将字节读入提供的流中。
有没有办法避免这最后一步,也许以某种方式直接传递文件流以供 Explorer shell 读取?我正在考虑iStream
用一个指向我所拥有的.NET 文件流的指针来替换......但我对 COM 互操作知之甚少,甚至不知道这样做的语法。任何提示/方向将不胜感激!