分段FileStream写

时间:2013-10-17 10:22:22

标签: .net multithreading asynchronous .net-2.0

我使用分段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的最佳方法是什么?

1 个答案:

答案 0 :(得分:4)

理想情况下,您会先将文件增大到所需的大小,这并非易事。要使用的API仅作为本机API存在,即SetFileValidData,并且该流程需要特殊SE_MANAGE_VOLUME_PRIVILEGE。 (巨大的)优势是文件增长到所需的大小而不首先填充0 。对于那些熟悉数据库的人来说,这被称为Instant File Initialization

如果您不想解决这个问题,那么您可以通过传统方式扩展文件,但是您需要付出代价两次的代价,一次为0有效内容。

如果文件大小合适,编写内容的最佳API为WriteFileGather。 Scatter / Gather IO允许您在任意偏移处写入任意文件段。但是,再次,只是本地人,没有管理对手......

W / o scatter / gather IO另一个不错的选择是内存映射访问。幸运的是,它有一个托管API,MemoryMappedFile ...用于.Net 4.0。

没有内存映射IO您必须使用一个流来进行所有写入。这意味着您必须使用生成者 - 消费者模式,其中Web流生成缓冲区以进行写入(使用文件偏移进行注释以写入!),并且一个使用者获取这些缓冲区并将它们写入流出的适当位置。