在C#中预分配文件空间?

时间:2008-09-19 01:50:52

标签: c# file file-io

我正在创建一个下载应用程序,我希望在实际下载之前预先在硬盘上分配文件,因为它们可能相当大,没有人喜欢看到“此驱动器已满,请删除一些文件和再试一次。”所以,从那个角度来看,我写了这个。

// Quick, and very dirty
System.IO.File.WriteAllBytes(filename, new byte[f.Length]);

它起作用,至少你下载一个几百MB的文件,甚至可能是GB的文件,如果没有完全消除页面文件并完全杀死你的系统内存,你就会把Windows扔进吵架的狂热中。糟糕。

所以,通过更多的启示,我开始使用以下算法。

using (FileStream outFile = System.IO.File.Create(filename))
{
    // 4194304 = 4MB; loops from 1 block in so that we leave the loop one 
    // block short
    byte[] buff = new byte[4194304];
    for (int i = buff.Length; i < f.Length; i += buff.Length)
    {
        outFile.Write(buff, 0, buff.Length);
    }
    outFile.Write(buff, 0, f.Length % buff.Length);
}

这很有效,并且不会遇到最后一个解决方案的严重内存问题。它仍然很慢,特别是在较旧的硬件上,因为它将数据(可能是GB的)数据写出到磁盘。

问题是:有没有更好的方法来完成同样的事情?有没有办法告诉Windows创建一个x大小的文件,只需在文件系统上分配空间,而不是实际写出一吨数据。我根本不关心初始化文件中的数据(我正在使用的协议 - bittorrent - 为它发送的文件提供哈希值,因此随机未初始化数据的最坏情况是我得到了一个幸运的巧合和部分文件是对的。)

3 个答案:

答案 0 :(得分:25)

FileStream.SetLength就是你想要的。语法:

public override void SetLength(
    long value
)

答案 1 :(得分:5)

如果你必须创建文件,我认为你可以做这样的事情:

using (FileStream outFile = System.IO.File.Create(filename))
{
    outFile.Seek(<length_to_write>-1, SeekOrigin.Begin);
    OutFile.WriteByte(0);
}

其中length_to_write是要写入的文件的大小(以字节为单位)。我不确定我的C#语法是否正确(不是在计算机上进行测试),但我过去在C ++中做过类似的事情并且它有效。

答案 2 :(得分:2)

不幸的是,你不能仅仅通过寻求最终来做到这一点。这会将文件长度设置为巨大的,但实际上可能不会为存储分配磁盘块。所以当你去写文件时,它仍然会失败。