【问题标题】:Creating a Random File in C#在 C# 中创建随机文件
【发布时间】:2010-12-13 18:28:01
【问题描述】:

我正在创建一个指定大小的文件——我不在乎里面有什么数据,虽然随机会很好。目前我正在这样做:

        var sizeInMB = 3; // Up to many Gb
        using (FileStream stream = new FileStream(fileName, FileMode.Create))
        {
            using (BinaryWriter writer = new BinaryWriter(stream))
            {
                while (writer.BaseStream.Length <= sizeInMB * 1000000)
                {
                    writer.Write("a"); //This could be random. Also, larger strings improve performance obviously
                }
                writer.Close();
            }
        }

这不是有效的,甚至不是正确的方法。有更高性能的解决方案吗?

感谢大家的回答。

编辑

对 2Gb 文件的以下方法进行了一些测试(时间以毫秒为单位):

方法 1:乔恩·斯基特

byte[] data = new byte[sizeInMb * 1024 * 1024];
Random rng = new Random();
rng.NextBytes(data);
File.WriteAllBytes(fileName, data);

不适用 - 2Gb 文件的内存不足异常

方法 2:乔恩·斯基特

byte[] data = new byte[8192];
Random rng = new Random();
using (FileStream stream = File.OpenWrite(fileName))
{
    for (int i = 0; i < sizeInMB * 128; i++)
    {
         rng.NextBytes(data);
         stream.Write(data, 0, data.Length);
    }
}

@1K - 45,868, 23,283, 23,346

@128K - 24,877, 20,585, 20,716

@8Kb - 30,426, 22,936, 22,936

方法 3 - Hans Passant(超快但数据不是随机的)

using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
    fs.SetLength(sizeInMB * 1024 * 1024);
}

257、287、3、3、2、3 等

【问题讨论】:

    标签: c# performance createfile


    【解决方案1】:

    嗯,一个非常简单的解决方案:

    byte[] data = new byte[sizeInMb * 1024 * 1024];
    Random rng = new Random();
    rng.NextBytes(data);
    File.WriteAllBytes(fileName, data);
    

    内存效率稍高的版本:)

    // Note: block size must be a factor of 1MB to avoid rounding errors :)
    const int blockSize = 1024 * 8;
    const int blocksPerMb = (1024 * 1024) / blockSize;
    byte[] data = new byte[blockSize];
    Random rng = new Random();
    using (FileStream stream = File.OpenWrite(fileName))
    {
        // There 
        for (int i = 0; i < sizeInMb * blocksPerMb; i++)
        {
            rng.NextBytes(data);
            stream.Write(data, 0, data.Length);
        }
    }
    

    但是,如果您在 非常 快速连续中多次执行此操作,每次都创建一个 Random 的新实例,您可能会得到重复的数据。有关更多信息,请参阅我的 article on randomness - 您可以使用 System.Security.Cryptography.RandomNumberGenerator... 或通过多次重复使用 Random 的同一实例来避免这种情况 - 需要注意的是它不是线程安全的。

    【讨论】:

    • 我会选择 128k 的块大小,这往往会在大多数 I/O 测试中提供卓越的性能。至少 4k,因为这是 32 位 Windows 操作系统上的页面大小。
    • @Ben:我会尽量避免使用 128K,因为这会在大对象堆上进行。不过我会把它提高到 8K :)
    • 也有人否决了这个问题。认为这是一次反对票的横冲直撞。
    【解决方案2】:

    没有比利用 NTFS 内置的稀疏文件支持更快的方法了,NTFS 是在硬盘上使用的 Windows 文件系统。这段代码在几分之一秒内创建了一个 1 GB 的文件:

    using System;
    using System.IO;
    
    class Program {
        static void Main(string[] args) {
            using (var fs = new FileStream(@"c:\temp\onegigabyte.bin", FileMode.Create, FileAccess.Write, FileShare.None)) {
                fs.SetLength(1024 * 1024 * 1024);
            }
        }
    }
    

    读取时,文件只包含零。

    【讨论】:

    • 创建文件时不需要显式启用稀疏性吗?
    • 不,但我确实在源代码上运行了反射器。 FileStream 中任何地方都没有DeviceIoControl(FSCTL_SET_SPARSE) 的迹象。您确定“在几分之一秒内”不是在工作中写入缓存吗?
    • 现在我确实尝试过了...文件属性显示“磁盘大小”==“总大小”,对于稀疏文件而言,情况并非如此。
    • 使其大于文件系统缓存的大小。
    • @Hans:我刚刚使用您的代码加上明显的更改创建了一个 26GB 的文件。我驱动器上的可用空间立即减少了 26GB。空簇可能不需要占用缓存中的空间,但它们肯定是在卷位图中分配的。对于稀疏文件,它们不会。
    【解决方案3】:

    您可以使用我创建的以下类来生成随机字符串

    using System;
    using System.Text;
    
    public class RandomStringGenerator
    {
        readonly Random random;
    
        public RandomStringGenerator()
        {
            random = new Random();
        }
        public string Generate(int length)
        {
            if (length < 0)
            {
                throw new ArgumentOutOfRangeException("length");
            }
            var stringBuilder = new StringBuilder();
    
            for (int i = 0; i < length; i++)
            {
                char ch = (char)random.Next(0,255 );
                stringBuilder.Append(ch);
            }
    
            return stringBuilder.ToString();
    
        }
    
    }
    

    为了使用

     int length = 10;
            string randomString = randomStringGenerator.Generate(length);
    

    【讨论】:

    • -1 这也会很慢,因为它特定于内存中的字符串,并且没有针对 OP 将数据直接写入文件的情况进行优化。无需使用字符(其大小是字节的两倍),也无需将整个字节字符串保留在内存中。
    • +1 以补偿反对票。解决方案不是最优的,但总比没有好,所以不赞成投票。
    【解决方案4】:

    创建大文件的有效方法:

        FileStream fs = new FileStream(@"C:\temp\out.dat", FileMode.Create);
        fs.Seek(1024 * 6, SeekOrigin.Begin);
        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
        fs.Write(encoding.GetBytes("test"), 0, 4);
        fs.Close();
    

    但是这个文件将是空的(除了最后的“测试”)。不清楚您到底要做什么——带有数据的大文件,或者只是大文件。您可以修改它以在文件中稀疏地写入一些数据,但不会完全填充它。 如果您确实希望整个文件充满随机数据,那么我能想到的唯一方法是使用上面 Jon 的随机字节。

    【讨论】:

      【解决方案5】:

      一种改进方法是用数据填充所需大小的缓冲区并一次性刷新所有数据。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多