FileInfo.Extension返回最后一个*.*模式还是其他内容?

30

我很好奇以下行为的确切表现:

FileInfo info = new FileInfo("C:/testfile.txt.gz");
string ext = info.Extension;

这会返回“.txt.gz”还是“.gz”?

如果有更多扩展名,比如“.txt.gz.zip”或类似的东西,行为会怎么样?

编辑:

明确一下,我已经测试过了。我想要一个属性的解释。


14
你跑过这段代码并查看它返回了什么吗?非常容易做到,因为你已经写好了这段代码。 - Gromer
2
当然,我只是想知道info.Extension的确切作用,这样我就可以围绕这些假设编写我的单元测试了 :) - Codeman
@Gromer Erwin 给了我我想要的东西——实际的代码,而不仅仅是经验测试。 - Codeman
1
对于那些给我点踩的人 - 我之所以问这个问题并不是因为我太懒而不想写自己的测试,而是因为我想知道幕后发生了什么。 - Codeman
3
我明白了。如果你以前没有使用过,ILSpy是一个非常不错的工具,可以查看各种 .Net 方法的作用。有时候它可能会很慢,但它非常适合了解 Framework 的编写方式。 - Gromer
1
@Gromer 我同意... 它也能让你深入了解模式和实践 - 所以无论你在做什么,它都是一个好工具。 - Phil Cooper
4个回答

47

它将返回 .gz,但 MSDN (FileSystemInfo.Extension Property) 的解释并不清楚为什么会这样:

"Extension 属性返回 FileSystemInfo 的扩展名,包括句点 (.)。例如,对于文件 c:\NewFile.txt,该属性返回“.txt”。"

因此,我使用 Reflector 查找了 Extension 属性的代码:

public string Extension
{
    get
    {
        int length = this.FullPath.Length;
        int startIndex = length;
        while (--startIndex >= 0)
        {
            char ch = this.FullPath[startIndex];
            if (ch == '.')
            {
                return this.FullPath.Substring(startIndex, length - startIndex);
            }
            if (((ch == Path.DirectorySeparatorChar) || (ch == Path.AltDirectorySeparatorChar)) || (ch == Path.VolumeSeparatorChar))
            {
                break;
            }
        }
        return string.Empty;
    }
}

该代码从文件路径的末尾开始逐个检查每个字符,直到找到一个点,然后返回从该点到文件路径结尾的子字符串。


1
那是一个实现细节,不是你应该依赖的东西。你应该依赖文档。实现细节可能会发生变化。 - user743382
1
@hvd,文档在这种情况下的行为不太清楚。来自MSDNExtension属性返回FileSystemInfo扩展名,包括句点(.)。例如,对于文件c:\NewFile.txt,此属性返回“.txt”。 - Codeman
@Pheonixblade9 我知道,我正在努力寻找能回答这个问题的文档。 :) - user743382
1
我觉得这很清楚。它返回“扩展名”。有什么不清楚的吗?我不明白混淆在哪里。 - Chris Dunaway
4
"Extenssion may be 'multiDotted', as in SaveFileDialog." 可以翻译为:"扩展名可以是“多点式”,比如在SaveFileDialog中。" - ephraim

10
[TestCase(@"C:/testfile.txt.gz", ".gz")]
[TestCase(@"C:/testfile.txt.gz.zip", ".zip")]
[TestCase(@"C:/testfile.txt.gz.SO.jpg", ".jpg")]
public void TestName(string fileName, string expected)
{
    FileInfo info = new FileInfo(fileName);
    string actual = info.Extension;
    Assert.AreEqual(actual, expected);
}

全部通过


7

它会从最后一个点返回扩展名,因为它无法猜测文件名的另一部分是否是扩展名的一部分。在 testfile.txt.gz 的情况下,你可以认为扩展名是 .txt.gz,但是对于 System.Data.dll 呢?扩展名应该是 .Data.dll 吗?很可能不是... 没有办法猜测,所以 Extension 属性不会尝试。


1
Windows有没有明确规定文件扩展名中可以包含一个句点?我从未见过这样的规定,因此我会认为文件扩展名是指最后一个句点之后的所有内容。 - Chris Dunaway

2
文件扩展名从最后一个点开始。不幸的是,FileSystemInfo.Extension 的文档没有回答这个问题,但它逻辑上必须返回与 Path.GetExtension 相同的值,因为该文档陈述:

备注

通过搜索路径中的句点 (.) 来获取路径的扩展名,从路径的最后一个字符开始,向路径的开头继续搜索。如果在 DirectorySeparatorChar 或 AltDirectorySeparatorChar 字符之前找到了句点,则返回的字符串包含句点和其后的字符;否则,返回 Empty。

有关常见 I/O 任务的列表,请参阅常见 I/O 任务。

如果有一个关于文件名的权威答案,那将会很好,但我找不到它。


“但是从逻辑上讲,它必须返回相同的值” - 除非您查找了Path.GetExtension()的代码,否则您如何确切地说呢?如果您已经查找过,请将其添加到您的帖子中。就目前而言,这只是您的一种假设,而您知道关于假设的那句话... - cogumel0
1
@cogumel0 我特意发布了这个答案,因为我不想查看代码。已经有一个查看代码的答案了。如果代码是错误或次优的,未来的.NET Framework更新可能会更改代码。如果文档中有关于文件扩展名的明确承诺,那么它的更改可能性要小得多。而我在这里的回答中的备注是我能找到的最接近的。 - user743382
我不介意你的评论,也不介意你没有发布代码,事实上,我很喜欢你从MSDN上找到并详细解释了它。然而,我强调的那句话承诺了一个不可辩驳的真理,但是因为你没有做任何事情来证明这个真理,我必须对它提出质疑。你凭什么毫无疑问地说FileSystemInfo.Extension 必须 返回与 Path.GetExtension 相同的值?我在MSDN上找不到任何证据证明这一点,如果你没有证据,那么很遗憾,你只是假设这两个行为相同。 - cogumel0
1
事实上,即使您查看了代码并意识到它们共享相同的代码或者Path.GetExtension只是在后台调用FileSystemInfo.Extension...就像您所说的,这可能随时更改,因此如果没有文档中的某些内容来显示,直到另行通知为止,这是情况,我认为您没有权利发表如此强烈的言论。简而言之,我喜欢您的回答,只是对“逻辑上必须”的部分感到冒犯,我认为“应该”更适合那里。 - cogumel0
@cogumel0 哦,现在我明白你是如何阅读我的回答的。那不是我想说的。通过“逻辑上必须”,我是说如果 Path.GetExtensionFileSystemInfo.Extension 使用不同的“扩展”定义,那么这将是不合逻辑的。为了使这些方法合乎逻辑,它们必须就定义达成一致。 - user743382
我理解你想表达的意思,但是虽然它可能是逻辑上正确的,但可能并不是真实的。完全有可能一个不调用另一个,而其中一个的代码得到更新时忘记了第二个。也可能其中一个有bug,而另一个没有等等。我只是在打太极,我相信你是对的,但除非你有证据来支持它,否则这仍然只是一种假设。 - cogumel0

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