使用字符串作为路径而不是使用DirectoryInfo/FileInfo的好处

19
在我的新代码中,我使用字符串传递目录路径或文件名。相反,我使用DirectoryInfo和FileInfo,因为它们似乎封装了很多信息。
我看到很多代码使用字符串来传递目录信息,然后他们使用"split"、"mid"和"instr"等长且难以理解的语句,直到找到他们所需的目录部分。
有什么好的理由将路径作为字符串传递吗?
7个回答

13

总的来说,我认为保留在FileInfo/DirectoryInfo中的信息更好。这些类中有很多有用的功能,并且在检查文件是否存在、查看最初指定的文件等方面有很多安全性。

我唯一会(潜在地)将路径作为字符串传递而不使用FileInfo和DirectoryInfo的情况是,如果该路径要在应用程序域之间或进程之间传递等。

FileInfo和DirectoryInfo在应用程序域边界上都可以正常工作(因为它们是可序列化的),但是在这种情况下它们具有相当多的开销。如果数据来回传输频繁,可能会产生影响。

在这种情况下,我会坚持使用FileInfo和DirectoryInfo,除非我在分析过程中发现性能问题,并且我正在尝试减少序列化数据的量。如果我没有遇到性能问题,我会继续使用这些类,因为它们提供了很多安全和功能。


1
请注意,如果文件已更改其存在或修改的时间戳,则需要创建新的FileInfo / DirectoryInfo。 - sighol

7

DirectoryInfoFileInfo如果你只需要一个路径,那么它们使用起来非常繁重。我更关心"split and mid and instr"这些琐碎的东西。学习如何使用:

Path.GetFileName
Path.GetDirectoryName
Path.Combine
等等...

这些都是来自于System.IO.Path类。


记住,当您将一个实例传递给一个函数时,它传递的是引用的副本,而不是整个对象的副本!因此,您实际上只是传递了指针的副本... - John Rasch
我认为问题不在于传递了多少字节,而是使用FileInfo/DirectoryInfo时的开销,因为它必须以各种方式探测文件以缓存有关它的信息。 - Steven Sudit

6

如果路径在应用程序中(即不在纯文本配置文件中),那么没有好的理由。

唯一有用的情况(我能想到的)是与仅接受路径作为字符串的代码进行交互时。


2

需要记住的一点是,路径字符串和FileInfo之间的一个重要区别可以总结如下:

FileInfo反映了文件信息的实例化时的状态 - 它可以被删除/修改,但FileInfo不会反映这一点。

[TestMethod]
        public void TestFileInfo()
        {
            var path = @"C:\Users\bjarmuz\Desktop\aybabtu.txt";
            File.WriteAllText(path, "All your base are belong to us!");
            var file = new FileInfo(path);

            Assert.IsTrue(file.Exists);
            File.Delete(file.FullName);
            Assert.IsTrue(file.Exists);
            Assert.IsFalse(File.Exists(file.FullName));
        }

  [TestMethod]
        public void TestFileInfo()
        {
            var path = @"C:\Users\bjarmuz\Desktop\aybabtu.txt";
            File.WriteAllText(path, "All your base are belong to us!");
            Thread.Sleep(1000);

            var file = new FileInfo(path);
            var date = DateTime.UtcNow;

            Assert.IsTrue(file.LastWriteTimeUtc< date);

            File.WriteAllText(path, "No!");
            Assert.IsTrue(File.GetLastWriteTimeUtc(file.FullName)> date);

            Assert.IsFalse(file.LastWriteTimeUtc > date);
        }

这可能会有些误导性,如果您的代码传递的是FileInfo而不是字符串,则可能会看到诸如Exists或Last[..]Time等属性的错误结果 - 如果使用File.Get[...]()方法,则不会发生这种情况。
然而,另一方面,您也不应该依赖于File.Exists()方法 - 因为文件可能会在您运行测试后创建/删除。正确的方式是不进行此检查,而是接受它可能会抛出IO异常(并准备好适当地处理它)。更多信息请参见这篇伟大的文章https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/ 此外,FileInfo / DirectoryInfo的一个重要优点是保护您的方法(和方法的使用者)免受以下情况的影响:
void SaveEntity(Entity theThing, string path)
{
    //now, based on the signature, you don't know whether you need file path or directory path

}

//void SaveEntity(Entity theThing, DirectoryInfo path) {}
//void SaveEntity(Entity theThing, FileInfo path) {}

对的,你需要意识到这一点,并且如果你想要最新的值,就调用FileInfo的"Refresh"方法。 - sa.he

1

0

在将FileInfo传递给DMZ时,我遇到了问题。据我所知 - 如果我错了,请纠正我 - FileInfo在反序列化时执行权限检查,而这在DMZ中不起作用,会导致“路径未找到”的错误。相反,创建并传递一个带有您需要的数据的自定义对象。


0

我找到了一个不使用它们的好理由。 归根结底,路径是一种类型,通常通过字符串表示,但它本身不是字符串,它有一些行为,如在这个视频中(只需检查60秒后的几秒钟)所解释。

这个视频本身提供了一个很好的文件路径管理解决方案,这是一个很好的起点,无论您正在寻找什么其他行为。

唯一的缺点可能是在极高性能环境下会有一些内存开销,但如果您不创建数百个路径对象,则大多数情况下没有理由不使用以下代码:

//This class provides all the rules for your application about how to handle a path as a value
public record FilePath
{
    public string Path { get; }
    
    public FilePath (string path) => 
        Path = 
            string.IsNullOrWhiteSpace (path) 
                ? throw new ArgumentException ("path cannot be null or empty") :
            System.IO.Path.GetInvalidPathChars().Intersect (path).Any()
                ? throw new ArgumentException ("Path contains illegal characters")
                : System.IO.Path.GetFullPath (path.Trim());
            
    public override string ToString() => Path;
    
    //Note on linux environments you would make it case sensitive
    public virtual bool Equals (FilePath? other) => 
        (Path).Equals (other?.Path, StringComparison.InvariantCultureIgnoreCase);

    public override int GetHashCode() => Path.ToLowerInvariant().GetHashCode();

    public static implicit operator FilePath (string name) => new FilePath (name);

    public FileInfo GetInfo() => new FileInfo (Path);

    public FilePath Combine (params string[] paths) =>
        System.IO.Path.Combine (paths.Prepend (Path).ToArray());
}

感谢Joe Albahari,视频中有关于C#更多有趣的内容可以了解。

示例取自LinQPad 7源代码样例。


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