在循环突然停止的特定路径中创建 (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()
创建保证唯一的值。
我正在尝试在特定目录中创建 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()
创建保证唯一的值。