我使用分段http下载使用范围(HttpWebRequest.AddRanges())将文件分成几部分然后连接所有部分。如果一个文件是100个字节,我将它分成4个部分(0-24,25-49,50-74,75-99),我调用4次DownloadPart函数。 使用异步编程模型(BeginRead / EndRead)下载每个部分。当所有部件都完成后,我加入他们,part1 + part2 + ...
public void DowloadPart(HttpWebResponse httpResp)
{
Stream httpStm = httpResp.GetResponseStream();
Stream fileStm = new FileStream("myFile.part1", FileMode.Append, FileAccess.Write);
byte[] buff = new byte[1024 * 16];
AsyncCallback callback = null;
callback = ar =>
{
int bytesRead = httpStm.EndRead(ar);
fileStm.Write(buff, 0, bytesRead);
if(bytesRead == 0)
return;
httpStm.BeginRead(buff, 0, buff.Length, callback, null);
};
httpStm.BeginRead(buff, 0, buff.Length, callback, null);
}
我想用直接写入文件来替换加入的部件。由于所有“DownloadPart”都在不同的线程中运行,因此在不同线程的不同位置同时写入FileStream的最佳方法是什么?
答案 0 :(得分:4)
理想情况下,您会先将文件增大到所需的大小,这并非易事。要使用的API仅作为本机API存在,即SetFileValidData
,并且该流程需要特殊SE_MANAGE_VOLUME_PRIVILEGE
。 (巨大的)优势是文件增长到所需的大小而不首先填充0 。对于那些熟悉数据库的人来说,这被称为Instant File Initialization。
如果您不想解决这个问题,那么您可以通过传统方式扩展文件,但是您需要付出代价两次的代价,一次为0有效内容。
如果文件大小合适,编写内容的最佳API为WriteFileGather
。 Scatter / Gather IO允许您在任意偏移处写入任意文件段。但是,再次,只是本地人,没有管理对手......
MemoryMappedFile
...用于.Net 4.0。
没有内存映射IO您必须使用一个流来进行所有写入。这意味着您必须使用生成者 - 消费者模式,其中Web流生成缓冲区以进行写入(使用文件偏移进行注释以写入!),并且一个使用者获取这些缓冲区并将它们写入流出的适当位置。