从目录中选择随机文件

4

有什么建议可以改进这个方法吗?我目前正在使用它从壁纸目录中选择单个壁纸

我知道不应该再使用arraylist了,但我想不到其他的替代方法。另外,我不确定如何在目录信息中过滤多种类型的文件(例如jpg,gif和png)。

任何建议或调整都将非常棒。

private string getrandomfile(string path)
        {
            ArrayList al = new ArrayList();
            DirectoryInfo di = new DirectoryInfo(path);
            FileInfo[] rgFiles = di.GetFiles("*.*");
            foreach (FileInfo fi in rgFiles)
            {
                al.Add(fi.FullName);
            }

            Random r = new Random();
            int x = r.Next(0,al.Count);

            return al[x].ToString();

        }

感谢

崩溃

5个回答

11

为什么不使用LINQ:

var files = Directory.GetFiles(path, "*.*").Where(s => Regex.Match(s, @"\.(jpg|gif|png)$").Success);
string randFile = path + files.ToList()[r.Next(0, files.Count())];

5

和往常一样,有多种方法可以解决问题。我基于 tvanfosson 的答案进行了改进,不是因为这个方法“更”正确,而是因为我认为这是一个有用的方法。

private static string getRandomFile(string path)
{
    try
    {
        var extensions = new string[] { ".png", ".jpg", ".gif" };

        var di = new DirectoryInfo(path);
        return (di.GetFiles("*.*")
                            .Where(f => extensions.Contains(f.Extension
                                                               .ToLower()))
                            .OrderBy(f => Guid.NewGuid())
                            .First()).FullName ;              
    }
    catch { return ""; }
}

2

更改为使用单个伪随机数生成器实例。

// Use a class variable so that the RNG is only created once.
private Random generator;
private Random Generator
{
    get
    {
        if (this.generator == null)
        {
           this.generator = new Random();
        }
        return this.generator;
    }
}
private string getrandomfile(string path)
{
    string file = null;
    if (!string.IsNullOrEmpty(path))
    {
        var extensions = new string[] { ".png", ".jpg", ".gif" };
        try
        {
            var di = new DirectoryInfo(path);
            var rgFiles = di.GetFiles("*.*")
                            .Where( f => extensions.Contains( f.Extension
                                                               .ToLower() );
            int fileCount = rgFiles.Count();
            if (fileCount > 0)
            {
                int x = this.Generator.Next( 0, fileCount );
                file = rgFiles.ElementAt(x).FullName;
            }
        }
        // probably should only catch specific exceptions
        // throwable by the above methods.
        catch {}
    }
    return file;
}

1
我不反对使用它,但为什么每个人都如此热爱Var呢?我认为这并不是最佳实践。 - Crash893
1
我认为这更易读。由于C#是强类型语言,因此您不会失去类型安全性,并且通常从赋值的右侧可以明确类型,因此您不会失去语义。 - tvanfosson
似乎rgFiles.length无效。你是指count吗?通常我不会问,但我对linq不太熟悉。如果我使用.count<>,我需要在<>之间指定计数吗? - Crash893
哎呀,我只在一个地方进行了更正,但是另一个地方没有。是的,应该使用.Count()而不是length,因为它不是数组,而是IEnumerable<FileInfo>。 - tvanfosson
你的 return file; 语句位于 if(...) 内部,应该会导致编译错误(并非所有路径都有返回值)。 - Erich Mirabal

2

你真的需要ArrayList吗?一旦生成了随机数,你应该能够消除它并直接使用数组。此外,如果路径由用户指定,你应该检查路径是否有效。


我同意这个观点,我认为LINQ有些过度设计了。 - andrewrk

1

我做了一些更改

这是我最终使用的代码,我删掉了一些条件语句,因为它们并不重要(如果没有文件,它会返回null,无需测试两次)。我还纠正了一些小的语法错误,有一个用户指出返回应该向下移动。

关于随机类,我不确定为什么不断调用它是不好的,但我认为这并不必要,因为这只会每10到15分钟运行一次。即使这样,它也只会在找到文件时才创建类。

感谢大家的帮助(tvanfosson)

private string getrandomfile2(string path)
    {
        string file = null;
        if (!string.IsNullOrEmpty(path))
        {
            var extensions = new string[] { ".png", ".jpg", ".gif" };
            try
            {
                var di = new DirectoryInfo(path);
                var rgFiles = di.GetFiles("*.*").Where( f => extensions.Contains( f.Extension.ToLower()));
                Random R = new Random();
                file = rgFiles.ElementAt(R.Next(0,rgFiles.Count())).FullName;
            }
            // probably should only catch specific exceptions
            // throwable by the above methods.
            catch {}
        }
        return file;
    }

谢谢。这帮助我为我写的面向5岁孩子的登录训练应用程序随机加载图片。 - meffordm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接