11

我在这样的目录中有文件

0-0.jpeg
0-1.jpeg
0-5.jpeg
0-9.jpeg
0-10.jpeg
0-12.jpeg

……

当我加载文件时:

FileInfo[] files = di.GetFiles();

他们的顺序错误(他们应该像上面那样):

0-0.jpeg
0-1.jpeg
0-10.jpeg
0-12.jpeg
0-5.jpeg
0-9.jpeg

如何解决?

我试图对它们进行排序,但没有办法:

1) Array.Sort(files, (f1, f2) => f1.Name.CompareTo(f2.Name));

2) Array.Sort(files, (x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.Name, y.Name)); 
4

7 回答 7

20

我知道这可能会迟到,但这是另一种完美的解决方案

FileInfo[] files = di.GetFiles().OrderBy(n => Regex.Replace(n.Name, @"\d+", n => n.Value.PadLeft(4, '0')));

在中使用正则表达式替换OrderBy Clause

Regex.Replace(n.Name, @"\d+", n => n.Value.PadLeft(4, '0'))

那么这是做什么的,它pads是文件名中每个数字长度为 4 个字符的数值:

0-0.jpeg     ->   0000-0000.jpeg
0-1.jpeg     ->   0000-0001.jpeg
0-5.jpeg     ->   0000-0005.jpeg
0-9.jpeg     ->   0000-0009.jpeg
0-10.jpeg    ->   0000-0010.jpeg
0-12.jpeg    ->   0000-0012.jpeg

但这仅发生在OrderBy子句中,它不会以任何方式触及原始文件名。您最终在数组中的顺序是“人类自然”顺序。

于 2017-09-10T16:58:15.097 回答
7

按字母顺序,“错误”的顺序实际上是正确的。如果您希望它按数字排序,那么您需要:

  1. 将文件名转换为数字列表并对它们进行排序
  2. 以字母和数字排序相同的方式命名文件(0-001.jpeg 和 0-030.jpg)
  3. 依靠文件创建时间进行排序(假设文件是​​按顺序创建的)。

有关#3 的示例,请参见Sorting Directory.GetFiles()的答案。

于 2012-08-22T16:15:10.423 回答
5

请参阅此处的“CustomSort”功能。

List<string> list = new List<string>() { 
                    "0-5.jpeg",
                    "0-9.jpeg",
                    "0-0.jpeg",
                    "0-1.jpeg",
                    "0-10.jpeg",
                    "0-12.jpeg"};
list.CustomSort().ToList().ForEach(x => Console.WriteLine(x));

它的输出:

0-0.jpeg
0-1.jpeg
0-5.jpeg
0-9.jpeg
0-10.jpeg
0-12.jpeg
于 2012-08-22T16:22:10.373 回答
4

为了解决这个问题,您可以使用StrCmpLogicalW windows API。

有关详细信息,请参阅这篇文章

于 2013-10-19T07:15:22.200 回答
1

为您的特定情况实施比较方法并将其用于Array.Sort.

private int CompareByNumericName(FileInfo firstFile, FileInfo secondFile)
{
    /* First remove '0-' and '.jpeg' from both filenames then... */

    int firstFileNumericName = Int32.Parse(firstFile.Name);
    int secondFileNumericName = Int32.Parse(secondFile.Name);

    return firstFileNumericName.CompareTo(secondFileNumericName);
}

 

FileInfo[] files = di.GetFiles();
Array.Sort<FileInfo>(files, CompareByNumericName);
于 2019-08-23T14:11:24.133 回答
0

您的文件名似乎是结构化的。如果您只是对它们进行排序,它们将作为普通字符串进行排序。你需要:

  1. 将文件名解析为其组成部分。
  2. 将数字段转换为数值。
  3. 按所需顺序比较该结构以获得预期的整理顺序。

就个人而言,我会创建一个类来表示文件名中隐含的结构。也许它应该包装FileInfo. 该类的构造函数应将文件名解析为其组成部分并适当地实例化该类的属性。

该类应该实现IComparable/ IComparable<T>(或者您可以创建一个实现Comparer)。

对您的对象进行排序,然后它们应该按照您想要的整理顺序出现。

如果看起来您的文件名由 3 部分组成:

  • 一个高阶数值(我们称之为'hi'),
  • 一个低阶数值(我们称之为'lo'),
  • 和一个扩展名(我们称之为'ext')

所以你的班级可能看起来像

public class MyFileInfoWrapper : IComparable<MyFileInfoWrapper>,IComparable
{
  public MyFileInfoWrapper( FileInfo fi )
  {
    // your implementation here
    throw new NotImplementedException() ;
  }

  public int    Hi         { get ; private set ; }
  public int    Lo         { get ; private set ; }
  public string Extension  { get ; private set ; }

  public FileInfo FileInfo { get ; private set ; }

  public int CompareTo( MyFileInfoWrapper other )
  {
    int cc ;
    if      ( other   == null     ) cc = -1 ;
    else if ( this.Hi <  other.Hi ) cc = -1 ;
    else if ( this.Hi >  other.Hi ) cc = +1 ;
    else if ( this.Lo <  other.Lo ) cc = -1 ;
    else if ( this.Lo >  other.Lo ) cc = +1 ;
    else                            cc = string.Compare( this.Extension , other.Extension , StringComparison.InvariantCultureIgnoreCase ) ;
    return cc ;
  }

  public int CompareTo( object obj )
  {
    int cc ;
    if      ( obj == null              ) cc = -1 ;
    else if ( obj is MyFileInfoWrapper ) cc = CompareTo( (MyFileInfoWrapper) obj ) ;
    else throw new ArgumentException("'obj' is not a 'MyFileInfoWrapper' type.", "obj") ;
    return cc ;
  }

}
于 2012-08-22T17:02:26.683 回答
0

这是我的解决方案。我首先解析了文件路径,然后定义了顺序规则。

对于以下代码,您需要命名空间System.Text.RegularExpressions

Regex parseFileNameForNaturalSortingRegex = new Regex(
    @"
        ^
        (?<DirectoryName>.*)
        (?<FullFileName>
            (?<FileNameBasePart>[^/\\]*)
            (?<FileNameNumericPart>\d+)?
            (?>
            \.
            (?<FileNameExtension>[^./\\]+)
            )?
        )
        $
    ",
    RegexOptions.IgnorePatternWhitespace | RegexOptions.RightToLeft
);

FileInfo[] filesOrdered = System.IO.Directory.GetFiles(@"C:\my\source\directory")
    .Select(fi =>
    {
        Match match = parseFileNameForNaturalSortingRegex.Match(fi.FullName);
        return new
        {
            FileInfo = fi,
            DirectoryName = match.Groups["DirectoryName"].Value,
            FullFileName = match.Groups["FullFileName"].Value,
            BasePart = match.Groups["FileNameBasePart"].Value,
            NumericPart = match.Groups["FileNameNumericPart"].Success ? int.Parse(match.Groups["FileNameNumericPart"].Value) : -1,
            HasFileNameExtension = match.Groups["FileNameExtension"].Success,
            FileNameExtension = match.Groups["FileNameExtension"].Value
        };
    })
    .OrderBy(r => r.DirectoryName)
    .ThenBy(r => r.BasePart)
    .ThenBy(r => r.NumericPart)
    .ThenBy(r => r.HasFileNameExtension)
    .ThenBy(r => r.FileNameExtension)
    .Select(r => r.FileInfo)
    .ToArray();
于 2020-04-29T21:33:18.250 回答