美文网首页程序员代码改变世界java
工作总结|文件系统模型的三种实现

工作总结|文件系统模型的三种实现

作者: 寒石 | 来源:发表于2016-11-18 23:26 被阅读189次

    最近在做关于压缩文件预览的需求,涉及到对于文件系统的目录结构进行简单的模拟。在实现过程中,尝试了三种实现方式,下文对三种实现方式做详细说明。

    传统目录结构

    使用递归构建文件二叉树结构

    • 最初的思路是:每次从输入流中读入一个结点,判断根据结点的路径名判断,如果是其子节点,则放入结点的右子树。如果是其同级结点,则放入其左子树中。(与上学时学的数据结构中多叉树转二叉树的区别在于:书上实现要求左孩子,右兄弟,我的实现是左兄弟,右孩子)
    • 类模型代码
    public class CompressedFileInfo {
        public String filePath;
        public String parentPath;
        private String name;
        public boolean isDirectory;
        private int levels;
        private CompressedFileInfo leftFriendInfo;
        private CompressedFileInfo rightChildInfo;
    }
    
    • 递归创建二叉树结构代码
      public void buildFileInfo(CompressedFileInfo root) {
              if (root == null) {
                  return;
              }
              if (root.levels == 0) {
                  if (root.rightChildInfo == null) {
                      root.rightChildInfo = this;
                      return;
                  } else {
                      root = root.rightChildInfo;
                  }
              }
              if (root.levels < levels) {
                  if (filePath.startsWith(root.filePath)) {
                      if (root.rightChildInfo == null) {
                          root.rightChildInfo = this;
                      } else {
                          buildFileInfo(root.rightChildInfo);
                      }
                  } else {
                      buildFileInfo(root.leftFriendInfo);
                  }
              } else if (root.levels == levels) {
                  if (parentPath == null || filePath.startsWith(root.filePath)) {
                      if (root.leftFriendInfo == null) {
                          root.leftFriendInfo = this;
                      } else {
                          buildFileInfo(root.leftFriendInfo);
                      }
                  } else {
                      Log.d("raytest", "Build Error");
                  }
              } else {
                  Log.e("raytest", "Build Error");
              }
      }
    
    • 采用二叉树构建的文件结构图如下所示:
    二叉树目录结构
    • 代码总结与分析
      在构建中,根据节点初始化的levels来对结点的层级数进行记录,在递归过程中,注意要结合父一级路径进行遍历。否则,可能会出现结点组织错误的问题。
      二叉树作为一种存储方式是一种很优雅的选择。但是对于我们项目中的需求来说,此种构建方式严重依赖于外部结点输入,必须保证从根节点,深度优先遍历,提供输入结点信息。否则并不能保证结点组织的准确性。同时二叉树递归遍历,在实际项目使用中,代码阅读性差,使用效率不高。所以,考虑到这些问题,我们决定采用多叉树型结构来实现文件结构

    使用递归构建文件树形结构

    • 采用树形结构存储,为了摆脱对外部结点输入的依赖,引入一个缓存Map来缓存所有输入结点,在结点输入完毕后,通过递归,构建树形结构,在摆脱外部输入的基础上,提高了程序的可读性。

    • 类模型代码

    public class DecompressFileItem extends FileItem {
        private String mParentPath;
        private List<FileItem> mChildList;
    }
    

    此处的FileItem可以理解为File对象属性的一些映射,包含一些获取文件名,获取文件路径之类的常用属性和方法。

    • 递归创建
    public void buildFileSys(Map<String, FileItem> nodeMap, DecompressFileItem paramInfo, boolean isRoot) {
            Map<String, FileItem> tempMap = new HashMap<>();
            tempMap.putAll(nodeMap);
            if (paramInfo == null || TextUtils.isEmpty(paramInfo.mData)) {
                return;
            }
            if (nodeMap == null || nodeMap.size() < 1) {
                return;
            }
            String paramPathKey = paramInfo.mData;
            if (isRoot) {
                paramPathKey = paramPathKey.substring(0, paramPathKey.lastIndexOf(File.separator));
                tempMap.remove(paramPathKey);
            } else {
                tempMap.remove(paramInfo.mData);
            }
            for (Map.Entry<String, FileItem> entry : tempMap.entrySet()) {
                DecompressFileItem item = (DecompressFileItem) entry.getValue();
                if (paramPathKey.equals(item.getParentPath())) {
                    if (paramInfo.mChildList == null) {
                        paramInfo.mChildList = new ArrayList<>();
                    }
                    paramInfo.mChildList.add(item);
                    item.buildFileSys(tempMap, item, false);
                }
            }
        }
    
    • 代码总结与分析
      在构建中,每次都将所有结点放置于一个暂存map中,将当前结点移除map中,并遍历剩余结点,将其子节点加入list中,递归遍历子节点,自此完成构建。
      此种实现,较为简单清晰,但是在实现过程中,由于实现路径写入错误,极有可能导致堆栈溢出。而且涉及文件结构处理,不可避免会涉及复杂结构,内存压力和堆栈溢出的风险这两个问题都需要考虑。所以,在老大Review完代码后,提出改写为迭代的方式进行创建。

    使用迭代创建文件树形结构

    • 在树形结构的基础上,我们对构建方法改造为使用迭代方式进行实现。

    • 迭代构建代码

    /**
     * called by root to create the file struct
     * @param nodeMap
     */
    public void buildFileSys(Map<String, FileItem> nodeMap) {
        if (nodeMap == null || nodeMap.size() < 1) {
            return;
        }
        for (Map.Entry<String, FileItem> entrySource : nodeMap.entrySet()) {
            String pathKey = entrySource.getKey();
            if (TextUtils.isEmpty(pathKey)) {
                continue;
            }
            DecompressFileItem pathItem = (DecompressFileItem) entrySource.getValue();
            if (pathItem == null) {
                continue;
            }
            for (Map.Entry<String, FileItem> entryCompare : nodeMap.entrySet()) {
                DecompressFileItem compareItem = (DecompressFileItem) entryCompare.getValue();
                if (compareItem == null) {
                    continue;
                }
                boolean isRootNode = compareItem.mData.equals(mData) && compareItem.mFileName.equals(mFileName);
                if (pathKey.equals(compareItem.getParentPath()) && !isRootNode) {
                    if (pathItem.mChildList == null) {
                        pathItem.mChildList = new ArrayList<FileItem>();
                    }
                    pathItem.mChildList.add(compareItem);
                    // build file count
                    if (pathItem.mIsDir) {
                        pathItem.mFileCount++;
                    }
                }
            }
        }
    }
    
    • 代码总结与分析
      此种构建方式相比于方式嵌套了两层循环,增加了代码的阅读难度,但是相对来说,还是比较简单,同时时间复杂度也只有O(n * n),相对来说还是一种不错的选择。
      同时在遍历的过程中,尝试去将一个结点所有子节点添加完毕后,就移除这个结点,可以减少时间复杂度,但是对于无序输入的结点,这样做,可能会出现,某个子节点已经被删除了,但它还未添加到其父结点中。╮(╯▽╰)╭
      如果大家对于构建类似的结构还有其他更好的建议,请大家不吝赐教(∩_∩)

    最后,附上银魂的一句吐槽:压力是导致秃顶的原因,所以请注意不要压力太大,但这样一来反而容易堆积压力,所以归根到底我们无能为力」

    相关文章

      网友评论

        本文标题:工作总结|文件系统模型的三种实现

        本文链接:https://www.haomeiwen.com/subject/iydspttx.html