zoukankan      html  css  js  c++  java
  • 重新整理 .net core 实践篇—————文件系统[二十二]

    前言

    简单介绍一下文件系统。

    正文

    文件系统,主要是下面3个接口组成:

    1. IFileProvider

    2. IFileInfo

    3. IDirectoryContents

    那么他们的实现是:

    1. physicalFileProvider 物理文件提供程序

    2. enbeddedFileProvider 嵌入式文件提供程序

    3. compositeFileProvider 组合文件提供程序

    /// <summary>A read-only file provider abstraction.</summary>
    public interface IFileProvider
    {
    /// <summary>Locate a file at the given path.</summary>
    /// <param name="subpath">Relative path that identifies the file.</param>
    /// <returns>The file information. Caller must check Exists property.</returns>
    IFileInfo GetFileInfo(string subpath);
    
    /// <summary>Enumerate a directory at the given path, if any.</summary>
    /// <param name="subpath">Relative path that identifies the directory.</param>
    /// <returns>Returns the contents of the directory.</returns>
    IDirectoryContents GetDirectoryContents(string subpath);
    
    /// <summary>
    /// Creates a <see cref="T:Microsoft.Extensions.Primitives.IChangeToken" /> for the specified <paramref name="filter" />.
    /// </summary>
    /// <param name="filter">Filter string used to determine what files or folders to monitor. Example: **/*.cs, *.*, subFolder/**/*.cshtml.</param>
    /// <returns>An <see cref="T:Microsoft.Extensions.Primitives.IChangeToken" /> that is notified when a file matching <paramref name="filter" /> is added, modified or deleted.</returns>
    IChangeToken Watch(string filter);
    }
    

    IFileProvider A read-only file provider abstraction

    只读文件提供程序抽象。

    那么这个三个方法分别是:

    1. GetFileInfo 获取指定文件

    2. GetDirectoryContents 获取指定目录,subpath是相对路径

    看下其返回值IDirectoryContents:

      public interface IDirectoryContents : IEnumerable<IFileInfo>, IEnumerable
      {
        /// <summary>True if a directory was located at the given path.</summary>
        bool Exists { get; }
      }
    

    其继承IEnumerable说明其实可以遍历文件的,同时有一个Exists 方法,判断这个目录是否存在

    IFileInfo 可以获取的信息如下:

      public interface IFileInfo
      {
        /// <summary>
        /// True if resource exists in the underlying storage system.
        /// </summary>
        bool Exists { get; }
    
        /// <summary>
        /// The length of the file in bytes, or -1 for a directory or non-existing files.
        /// </summary>
        long Length { get; }
    
        /// <summary>
        /// The path to the file, including the file name. Return null if the file is not directly accessible.
        /// </summary>
        string PhysicalPath { get; }
    
        /// <summary>
        /// The name of the file or directory, not including any path.
        /// </summary>
        string Name { get; }
    
        /// <summary>When the file was last modified</summary>
        DateTimeOffset LastModified { get; }
    
        /// <summary>
        /// True for the case TryGetDirectoryContents has enumerated a sub-directory
        /// </summary>
        bool IsDirectory { get; }
    
        /// <summary>
        /// Return file contents as readonly stream. Caller should dispose stream when complete.
        /// </summary>
        /// <returns>The file stream</returns>
        Stream CreateReadStream();
      }
    

    这里面有一个IsDirectory 属性,看来目录也是当成了文件的,这样设计可能是兼容linux的原因吧,一切皆文件。

    1. 第三个 Watch,看到IChangeToken 就知道肯定是搞监听的。

    测试:

    static void Main(string[] args)
    {
    	IFileProvider provider = new PhysicalFileProvider(AppDomain.CurrentDomain.BaseDirectory);
    
    	var contents = provider.GetDirectoryContents("/");
    
    	foreach (var item in contents)
    	{
    		Console.WriteLine(item.Name);
    	}
    
    	Console.ReadLine();
    }
    

    打印根目录全部文件。

    查看内嵌文件:

    在根目录创建emb.html,设置为内嵌。

    里面为:

    <!DOCTYPE html>
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        这个是一个内嵌文件
    </body>
    </html>
    

    测试代码:

    IFileProvider provider = new EmbeddedFileProvider(typeof(Program).Assembly);
    
    var html = provider.GetFileInfo("emb.html");
    
    Console.ReadLine();
    
    

    结果:

    下面看下组合文件提供程序:

    static void Main(string[] args)
    {
    	IFileProvider provider1 = new PhysicalFileProvider(AppDomain.CurrentDomain.BaseDirectory);
    
    	IFileProvider provider2 = new EmbeddedFileProvider(typeof(Program).Assembly);
    
    	IFileProvider providerSum = new CompositeFileProvider(provider1, provider2);
    
    	var contents = providerSum.GetDirectoryContents("/");
    	foreach (var item in contents)
    	{
    		Console.WriteLine(item.Name);
    	}
    
    	Console.ReadLine();
    }
    

    简单看下这个组合是如何实现的。

    public CompositeFileProvider(params IFileProvider[] fileProviders)
    {
      this._fileProviders = fileProviders ?? Array.Empty<IFileProvider>();
    }
    

    先是放置在一个数组中,名为_fileProviders 。

    看下GetDirectoryContents:

    public IDirectoryContents GetDirectoryContents(string subpath)
    {
      return (IDirectoryContents) new CompositeDirectoryContents((IList<IFileProvider>) this._fileProviders, subpath);
    }
    

    看下CompositeDirectoryContents:

    public CompositeDirectoryContents(IList<IFileProvider> fileProviders, string subpath)
    {
      if (fileProviders == null)
    	throw new ArgumentNullException(nameof (fileProviders));
      this._fileProviders = fileProviders;
      this._subPath = subpath;
    }
    

    然后遍历的时候调用:

    /// <summary>Creates an enumerator for all files in all providers given.
    /// Ensures each item in the collection is distinct.</summary>
    /// <returns>An enumerator over all files in all given providers</returns>
    public IEnumerator<IFileInfo> GetEnumerator()
    {
      this.EnsureFilesAreInitialized();
      return (IEnumerator<IFileInfo>) this._files.GetEnumerator();
    }
    

    查看EnsureFilesAreInitialized:

    private void EnsureFilesAreInitialized()
    {
      this.EnsureDirectoriesAreInitialized();
      if (this._files != null)
    	return;
      this._files = new List<IFileInfo>();
      HashSet<string> stringSet = new HashSet<string>();
      for (int index = 0; index < this._directories.Count; ++index)
      {
    	foreach (IFileInfo fileInfo in (IEnumerable<IFileInfo>) this._directories[index])
    	{
    	  if (stringSet.Add(fileInfo.Name))
    		this._files.Add(fileInfo);
    	}
      }
    }
    

    继续查看EnsureDirectoriesAreInitialized:

    private void EnsureDirectoriesAreInitialized()
    {
      if (this._directories != null)
    	return;
      this._directories = new List<IDirectoryContents>();
      foreach (IFileProvider fileProvider in (IEnumerable<IFileProvider>) this._fileProviders)
      {
    	IDirectoryContents directoryContents = fileProvider.GetDirectoryContents(this._subPath);
    	if (directoryContents != null && directoryContents.Exists)
    	{
    	  this._exists = true;
    	  this._directories.Add(directoryContents);
    	}
      }
    }
    

    这样看来就是每隔文件的provider 调用GetDirectoryContents,然后再次遍历套娃把文件信息都放入List _files,然后遍历的时候遍历的就是_files。

    功能挺少的,这样看来必须是同一个subpath,只能在外面根目录做文章。

    以上只是个人整理,如有错误,望请指点。

    下一节路由与终结点。

  • 相关阅读:
    C#基础系列——一场风花雪月的邂逅:接口和抽象类
    C#进阶系列——动态Lamada(二:优化)
    C#进阶系列——动态Lamada
    JS组件系列——Bootstrap Table 表格行拖拽(二:多行拖拽)
    JS组件系列——Bootstrap Table 表格行拖拽
    C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建
    C#进阶系列——MEF实现设计上的“松耦合”(四):构造函数注入
    C#进阶系列——DDD领域驱动设计初探(六):领域服务
    C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用
    C#进阶系列——DDD领域驱动设计初探(四):WCF搭建
  • 原文地址:https://www.cnblogs.com/aoximin/p/14881547.html
Copyright © 2011-2022 走看看