在循环突然停止的特定路径中创建 (N) 个目录

Creating (N) directories in a specific path in a loop stopping abruptly

我正在尝试在特定目录中创建 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)

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

    for (int i = 0; i < 10000; ++i)
    {
        Directory.CreateDirectory(Path.Combine(WorkingDir, $"{i}"));
    }

您的函数 GetRandomString 生成的名称不唯一,因为您每次都会创建新的 Random。您可以使用使用 class 实例创建一次的私有 class 成员 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());
}

关于 GetRandomString() 的更新...

当您创建 Random 的新实例而不传递种子时,default constructor 将从 Environment.TickCount 开始为新实例播种 - 自计算机启动以来的时间(以毫秒为单位) .由于它的分辨率为 1 毫秒,因此您的代码很可能会创建许多具有相同种子值的 Random 实例。这意味着该方法每次都会 return 相同的值,直到 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() 创建保证唯一的值。