我有一个 C# WPF 应用程序,其中有一个部分用作 FTP 客户端,列出远程服务器上的文件并允许用户下载它们。我希望用户能够将文件列表中的文件拖放到他们自己的计算机上(即拖放到 Windows 资源管理器外壳中)。
为此,我使用了 VirtualFileDataObject code from Delay's blog , 使用 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>
我提供将实际文件数据写入流的方法。我的委托(delegate)只是打开一个文件并将字节读入提供的流中。
有没有办法避免这最后一步,也许以某种方式直接传递文件流以供 Explorer shell 从中读取?我在想类似替换 iStream
的东西带有指向 .NET 文件流的指针我已经...但是我对 COM 互操作的了解还不够,甚至不知道这样做的语法。任何提示/方向将不胜感激!
最佳答案
经过更多的谷歌搜索和跌跌撞撞,不断尝试,我找到了一些可行的方法,但我仍然愿意接受更好的解决方案。现在,当删除操作发生时,我将文件检索到一个临时位置,然后使用 SHCreateStreamOnFileEx
打开指向该位置的 IStream
。修改后的部分 GetData
lambda 如下:
GetData = () => {
var filename = getFilename();
IStream stream = null;
NativeMethods.SHCreateStreamOnFileEx(filename, NativeMethods.STGM_FAILIFTHERE, NativeMethods.FILE_ATTRIBUTE_NORMAL, false, null, ref stream);
var ptr = Marshal.GetComInterfaceForObject(stream, typeof(IStream));
Marshal.ReleaseComObject(stream);
return new Tuple<IntPtr, int>(ptr, NativeMethods.S_OK);
}
正如我所说,我不知道这是否是最好的方法,或者我是否可以更干净地管理它,但这似乎有效。
关于c# - 将大型虚拟文件从 C# 拖放到 Windows 资源管理器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12410114/