1

我正在尝试在特定目录中创建 10,000 个文件夹。我有一个为每个文件夹创建随机名称的算法。

我遇到的问题是当我运行此代码时,它会停止创建大约 21 个目录。这MessageBox.Show()是调试,但是,它永远不会弹出。

this.WorkingDir是一个看起来像这样的字符串属性。

"C:\\Users\\Reapism\\Desktop\\Yo\\"

        DirectoryInfo directoryInfo;
        string dirName; // directory name
        const int dirNameLength = 15;

        for (int i = 0; i < 10000; i++) {
            dirName = GetRandomString(dirNameLength); // generates "unique name"
            try {
                directoryInfo = Directory.CreateDirectory(this.WorkingDir + dirName);
            } catch (Exception e) {
                MessageBox.Show($"{i} {dirName} failed. {e.ToString()}");
            }
        }

        // Inserting a breakpoint here yields 21 directories

        DirectoryInfo d = new DirectoryInfo(this.WorkingDir);
        DirectoryInfo[] directories = d.GetDirectories($"*");

        foreach (DirectoryInfo dir in directories) {
            try {
                Directory.Delete(dir.FullName);
            } catch (Exception e) {
                throw new FileNotFoundException($"Error deleting the directory!" + e.ToString());
            }
        }

有趣的是,当我使用调试器并逐步执行 for 循环的每次迭代来创建目录时,它会超过21 个目录,并且可能一直达到 10k。这会让我相信在一定时间内创建目录是有限制的。

令人不安的是没有抛出异常,循环只是停止了。

这是否与 CPU 的工作速度比磁盘报告或写入新文件夹的速度快有关?如果是这样,我该如何解决这个问题?此功能是定时功能,Thread.Sleep(50)不能使用例如。

4

3 回答 3

2

实时执行时,您的函数 GetRandomString 可能会引发异常。将其放入 try 块并检查。我尝试创建 10000 个名称为 1,2,3 ...10000 的文件夹,并且我已经创建了所有文件夹。

    for (int i = 0; i < 10000; ++i)
    {
        Directory.CreateDirectory(Path.Combine(WorkingDir, $"{i}"));
    }
于 2019-03-25T13:59:11.923 回答
2

关于更新GetRandomString()...

当您创建一个新实例Random而不传递种子时,默认构造函数将从Environment.TickCount- 自计算机启动以来的时间(以毫秒为单位)为新实例播种。由于这具有 1 毫秒的分辨率,因此您的代码很可能会创建许多Random具有相同种子值的实例。这意味着该方法每次都将返回相同的值,直到Environment.TickCount翻转到下一个值。

要解决这个问题,您应该使用单个Random实例并在所有调用中使用它。像这样的东西应该工作:

private Random _rnd = null;

private string GetRandomString(int length) 
{
    if (_rnd == null)
        _rnd = new Random();

    if (length < 1) 
        throw new ArgumentOutOfRangeException("Length must be greater than 0!");

    var sb = new StringBuilder(length);
    for (int i = 0; i < length; i++)
        sb.Append(charList[_rnd.Next(charList.Length)]);
    return sb.ToString();
}

它与您已经拥有的基本相同,但只创建一个Random实例。并且避免了你正在进行的所有讨厌的字符串组合,所以它会更快一点,对内存更友好。

如果您不关心实际名称,另一种方法是使用Guid.NewGuid()创建保证唯一值。

于 2019-03-26T03:35:05.770 回答
1

您的函数 GetRandomString 生成非唯一名称,因为您每次都创建新的 Random 。您可以使用与类实例一起创建一次的私有类成员 Random。我写了样本计数唯一名称。

string[] dirNames = new string[10000];

for (i = 0; i < 10000; ++i)
    dirNames[i] = GetRandomString(dirNameLength); // generates "unique name";

foreach (var dr in dirNames.GroupBy(x => x).Select(x => new { Name = x.Key, Count = x.Count() }).Where(x => x.Count > 1))
{
    Console.WriteLine($"{dr.Count} {dr.Name}");
}

尝试这个。Аnd 不要忘记文件名不区分大小写,所以你应该只使用 36 个字符,而不是 62 个字符。

private static readonly char[] charList = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
private static readonly Random _random = new Random();

private static string GetRandomString(int length)
{
    if (length < 1)
        throw new ArgumentOutOfRangeException("Length must be greater than 0!");

    return new string(Enumerable.Repeat(charList, length).Select(s => s[_random.Next(s.Length)]).ToArray());
}
于 2019-03-25T17:47:00.607 回答