.net 将路径作为字符串传递而不是使用DirectoryInfo/FileInfo的充分理由

yzuktlbb  于 2023-02-17  发布在  .NET
关注(0)|答案(7)|浏览(129)

在我的新代码中,我没有使用字符串来传递目录路径或文件名,而是使用DirectoryInfo和FileInfo,因为它们似乎封装了大量信息。
我见过很多使用字符串传递目录信息的代码,然后它们在很长的难以理解的语句中“拆分”、“中间”和“instr”,直到它们得到它们正在寻找的目录的一部分。
有什么好的理由把路径当作字符串来传递吗?

sycxhyv7

sycxhyv71#

总的来说,我认为将信息保存在FileInfo/DirectoryInfo中更好。这些类中有很多有用的功能,也有很多安全性,因为检查文件是否存在,查看最初指定的文件等都更容易。
唯一的地方,我会(潜在地)作为一个字符串,而不是使用FileInfo和DirectoryInfo传递路径是如果路径将被传递到AppDomain或进程之间,等等。
FileInfo和DirectoryInfo都可以很好地跨AppDomain边界工作(因为它们是可序列化的),但是在这种情况下,它们会有相当多的开销。
在这种情况下,我会坚持使用FileInfo和DirectoryInfo,除非我在分析过程中发现了明显的问题,并且我试图减少序列化数据的数量。如果我没有遇到性能问题,我会坚持使用这些类,因为它们提供了大量的安全性和功能。

sxpgvts3

sxpgvts32#

如果你需要的只是一条路径,那么DirectoryInfoFileInfo对于传递来说是非常沉重的。我更关心“split、mid和instr”垃圾。学习以下方法:
Path.GetFileName
Path.GetDirectoryName
Path.Combine
等等。
顺便说一句,这些都是System.IO.Path类的。

qpgpyjmq

qpgpyjmq3#

一旦路径在应用程序中(即不在纯文本配置文件中),就没有好的理由了。
唯一一次(我能想到的)它可能是有用的,是在与只接受路径作为字符串的代码进行互操作时。

eufgjt7s

eufgjt7s4#

我认为你确实需要一个类来封装一个文件或目录路径,而不是使用原始字符串并使用静态System.IO.Path类来操作它们。然而,I don't find DirectoryInfo and FileInfo suitable,因为它们似乎更倾向于做文件/目录操作,而不是路径操作。如果你为路径操作定制一个类,你可以提供更多用户友好的路径操作功能。

daolsyd0

daolsyd05#

路径字符串和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);
        }

这可能有点误导,如果代码传递FileInfos而不是字符串,您可能会看到ExistsLast[..]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) {}
x8goxv8g

x8goxv8g6#

我在将FileInfo传递到DMZ时遇到问题。据我所知(如果我说错了请纠正),FileInfo在反序列化时执行权限检查,但在DMZ中不起作用,并导致“找不到路径”。请创建并传递一个自定义对象,其中包含您的数据。

pu3pd22g

pu3pd22g7#

我找到了一个不使用这两个的好理由。说到底,路径是类型,通常通过字符串来表示,但它本身不是字符串,它有一些行为,如in this video (Just check the few seconds after seconds 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源代码样本中提取的样本。

相关问题