You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现数组层级文件目录结构的指定路径存在性检查?

目录路径匹配功能实现

需要实现的功能:针对数组层级存储的文件目录结构,通过System->Main->Drivers这类路径字符串,检查对应资源(目录或文件)是否存在,并返回匹配结果:

  • 输入存在的目录路径,返回该目录下的文件列表;
  • 输入存在的文件路径,返回该文件对象;
  • 输入不存在的路径,返回undefined或NaN。

我耗时3小时编写的代码完全无法满足需求,最终在Michael M.和chill 389cc的帮助下完成了正确的has方法实现,相关代码如下:

示例代码

const Files = [
    {
      Name: 'System',
      Type: 'directory',
      Value: [
        {
          Name: 'Main',
          Type: 'directory',
          Value: [
            {
              Name: 'Drivers',
              Type: 'directory',
              Value: [
                {
                  Name: 'Startup',
                  Type: 'file',
                  Value: new FileSystem.File('Startup', 0x1, 'test blah blah'),
                },
              ],
            },
          ],
        },
      ],
    },
  ];

BlahBlah.has(Files, 'System->Main->Drivers');
// 返回该目录下的文件列表 [File]
BlahBlah.has(Files, 'System->Main->Drivers->Startup');
// 返回对应文件对象 File
BlahBlah.has(Files, 'System->Main->Drivers->AnyWhere');
// 返回 undefined
BlahBlah.has(Files, 'System->Main->AnyRandomDirectory');
// 返回 NaN

初始实现代码

function text2Binary(str: string, spliter: string = ' '): string {
  return str
    .split('')
    .map(function (char) {
      return char.charCodeAt(0).toString(2);
    })
    .join(spliter);
}

export function FileTypeFromNumber(e: number) {
  if (typeof e != 'number')
    try {
      e = Number(e);
    } catch (_) {
      return null;
    }

  return {
    0x1: {
      Name: 'Executable File',
      Extension: 'exe',
    },
    0x2: {
      Name: 'Text Document',
      Extension: 'txt',
    },
  }[e];
}

export type FileTypes =
  | 0x1
  | 0x2
  | 0x3
  | 0x4
  | 0x5
  | 0x6
  | 0x7
  | 0x8
  | 0x9
  | null;
export class File {
  Name: string;
  Type: {
    Name: string;
    Extension: string;
  };
  Content: string;
  Size: number;
  constructor(name: string, type: FileTypes, content: string) {
    this.Name = name;
    this.Type = FileTypeFromNumber(type);
    this.Content = content;
    this.Size = text2Binary(content, '').length;
  }
}

export class Directory {
  public Name: string;

  public Files: (File | Directory)[] = [];

  constructor(name: string) {
    this.Name = name;
  }

  addFile(file: File | Directory) {
    this.Files.push(file);
  }

  getFile(name: string): null | (File | Directory)[] {
    if (typeof name != 'string')
      try {
        name = String(name);
      } catch (_) {
        return null;
      }

    const Result = this.Files.filter((e) => e.Name == name);

    return Result.length == 0 ? null : Result;
  }

  getSize() {
    return this.Files.map((e) =>
      e instanceof Directory ? e.getSize() : e.Size
    ).reduce((a, b) => a + b, 0);
  }

  has(name) {
    return this.Files.some((e) => e.Name == name);
  }

  getJSON() {
    return this.Files.map((e) => ({ ...e }));
  }
}
interface x {
  Content: string;
  Name: string;
  Size: number;
  Type: string;
}

export function ConvertFromJSONtoDirectory(json: any[]) {
  return json.map((value) => {
    const isDirectory = value.Type == 'directory';
    if (!isDirectory) {
      return value.Value;
    }
    const self = new Directory(value.Name);
    ConvertFromJSONtoDirectory(value.Value).map((e) => self.addFile(e));
    return self;
  });
}

export default class DirectorySystem {
  Memory: Map<any, any>;
  Current: string | null;

  constructor(Current = null) {
    this.Memory = new Map();
    this.Current = Current;
  }

  addDirectory(directory: Directory): null | true {
    if (!(directory instanceof Directory)) return null;

    if (this.Memory.has(directory.Name)) return null;

    this.Memory.set(directory.Name, directory);
    return true;
  }

  getDirectory(DirectoryName: string): boolean | Directory {
    if (typeof DirectoryName != 'string')
      try {
        DirectoryName = String(DirectoryName);
      } catch (_) {
        return null;
      }

    const Result = this.Memory.has(DirectoryName);

    return Result ? this.Memory.get(DirectoryName) : Result;
  }

  getDirectoryCurrent() {
    if (this.Current == null) return this;
  }

  changeDirectory(by: -1 | 1, value: string) {
    if (by == -1) {
      if (this.Current == null) return null;

      if (this.Current.includes('->')) {
        this.Current = this.Current.split('->').slice(0, -1).join('->');
      } else {
        this.Current = null;
      }

      return this.Current;
    } else if (by == 1) {
      let Position = [this.Current, value].join('->');
      if (this.Current == null) {
        Position = Position.split('->').slice(1).join('->');
      }
      let Result = this.has(Position);
      console.log(Result);
    }
  }

  has(query: string) {
    try {
      return query.split('->').reduce((a, b) => {
        if (Array.isArray(a)) {
          const f = a.filter((e) => e['Name'] == b);
          if (a.length > 0) {
            return f['Files'];
          } else {
            return a;
          }
        }
        return a['Files'];
      }, this.getJSON());
    } catch (_) {
      return false;
    }
  }

  getJSON(): x[][] {
    return [...this.Memory.values()].reduce((a, b) => {
      a[b.Name] = b.getJSON();
      return a;
    }, {});
  }
}

最终正确实现的has方法

has(
    query: string,
    overwrite = null
  ) {
    // 如果overwrite参数不为空,则使用该参数作为初始资源列表
    let files = overwrite == null ? this.getJSON() : overwrite;
    // 将路径字符串分割为节点数组,过滤空字符串
    const QueryParams = query.split('->').filter(String);
    // 无查询参数时返回当前传入的资源列表
    if (QueryParams.length == 0) return overwrite;
    if (Array.isArray(files)) {
      const SearchFor = QueryParams.shift();
      // 在当前层级查找匹配名称的资源
      const Result = files.filter((e) => {
        if (e instanceof Directory) {
          return e.Name == SearchFor;
        }
        return e.Name == SearchFor;
      })[0];
      // 未找到匹配资源,返回undefined
      if (!Result) return undefined;
      // 找到文件且无剩余路径节点,返回该文件对象
      if (Result instanceof File) return QueryParams.length == 0 ? Result : undefined;
      // 找到目录且无剩余路径节点,返回该目录下的文件列表
      if (Result instanceof Directory && QueryParams.length == 0) return Result.Files;
      // 名称不匹配或仍有路径节点但目录为空,返回NaN
      if (
        Result.Name != SearchFor ||
        (QueryParams.length != 0 && Result.Files.length == 0)
      )
        return NaN;
      // 递归调用,继续处理剩余路径节点
      return this.has(QueryParams.join('->'), Result.Files);
    } else {
      // 处理对象类型的资源结构,查找对应节点
      const Result = files[QueryParams.shift()];
      return !Result ? undefined : this.has(QueryParams.join('->'), Result);
    }
  }

内容的提问来源于stack exchange,提问作者Wraithdev2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 00:05:10