【问题标题】:Segmented FileStream Write分段文件流写入
【发布时间】:2013-10-17 10:22:21
【问题描述】:

我使用分段 http 下载,使用范围 (HttpWebRequest.AddRanges()) 将文件分成几部分,然后加入所有部分。如果一个文件是 100 字节,我将它分成 4 个部分(0-24、25-49、50-74、75-99)并调用四次 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 的最佳方法是什么?

【问题讨论】:

  • 请不要只要求我们为您解决问题。向我们展示如何尝试自己解决问题,然后向我们确切地展示结果是什么,并告诉我们您为什么觉得它不起作用。请参阅“What Have You Tried?”了解您真正需要阅读的优秀文章。
  • @JohnSaunders 我填写了“myFile”(不使用部件)并得到了 System.IO.IOExeption(另一个线程可能导致操作系统文件句柄的位置发生意外变化)
  • 不清楚为什么会在一个线程上发生。
  • 我在直接写作中没有使用单线程(正如我在问题中所说)
  • 那么肯定,异常很明显:让每个线程使用单独的FileStream

标签: .net multithreading asynchronous .net-2.0


【解决方案1】:

理想情况下,您首先将文件增长到所需的大小,这并非易事。要使用的 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 流产生要写入的缓冲区(用要写入的文件偏移量进行注释!),并且一个消费者获取这些缓冲区并将它们写入输出流中的适当位置。

【讨论】:

  • 如果我在第一个 FileStream (SetLength()) 中设置文件的长度,然后在每个流/线程中从不同位置开始写入 (FileStream.Position) 可以保证我不会有线程问题和文件是否正确?
  • 至少你必须保护位置(一次只有一个线程可以设置位置并发出写入)。我会认为有一个专门的作家来做这件事(位置/写作)。
  • 不,我认为有四个 FileStream,每个从 Position=0、25、50、75 开始(对于 100 字节的文件)。
  • 您不能有四个文件流。 AFAIK 一个进程无法通过普通文件 IO API 多次打开同一个文件以进行写入。这其中内存映射 IO 会有所帮助,因为您可以在同一个文件中以不同的偏移量打开多个视图。
猜你喜欢
  • 1970-01-01
  • 2012-01-03
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 1970-01-01
  • 2012-04-06
  • 2015-11-24
  • 1970-01-01
相关资源
最近更新 更多