用golang递归构建无限级树状目录json数据和数据库

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/details/53150691

http://studygolang.com/wr?u=http%3a%2f%2f88250.b3log.org%2fgolang-ztree

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sort"
)

func main() {
	rootpath := "D:\\projects"

	root := FileNode{"projects", rootpath, []*FileNode{}}
	fileInfo, _ := os.Lstat(rootpath)

	walk(rootpath, fileInfo, &root)

	data, _ := json.Marshal(root)

	fmt.Printf("%s", data)
}

type FileNode struct {
	Name      string      `json:"name"`
	Path      string      `json:"path"`
	FileNodes []*FileNode `json:"children"`
}

func walk(path string, info os.FileInfo, node *FileNode) {
	// 列出当前目录下的所有目录、文件
	files := listFiles(path)

	// 遍历这些文件
	for _, filename := range files {
		// 拼接全路径
		fpath := filepath.Join(path, filename)

		// 构造文件结构
		fio, _ := os.Lstat(fpath)

		// 将当前文件作为子节点添加到目录下
		child := FileNode{filename, fpath, []*FileNode{}}
		node.FileNodes = append(node.FileNodes, &child)

		// 如果遍历的当前文件是个目录,则进入该目录进行递归
		if fio.IsDir() {
			walk(fpath, fio, &child)
		}
	}

	return
}

func listFiles(dirname string) []string {
	f, _ := os.Open(dirname)

	names, _ := f.Readdirnames(-1)
	f.Close()

	sort.Strings(names)

	return names
}

利用自我内部循环——也就是无限递归——避免之前用那种比较傻的方式:4级菜单就用4个struct嵌套。并循环for也是4层。

if fio.IsDir() {
			walk(fpath, fio, &child)
		}

实现无限级struct嵌套,转成json,供treeview使用,即无限级树状菜单。

数据库结构用可以理解的传统的parentid,而不用那种left和right的树:https://segmentfault.com/q/1010000000126370/a-1020000000126714

好吧我忘了提一个很dirty的方法。

如果你的树深度是可预期的话,有个超简单的数据结构。你需要3个字段来表达这个树:

  1. id,本节点的primary key
  2. parent_id,其值为父节点的primary key
  3. key,忘了学名叫啥了,你可以称为线索
  4. level,表示当前节点到根节点的距离

其中,key字段的值为:从跟节点到父节点的primary key,中间用任意非数字符号分割。

例如以下树状结构

├── a
│   ├── d
│   │   ├── p
│   │   ├── q
│   │   └── r
│   ├── e
│   └── f
├── b
│   ├── x
│   ├── y
│   └── z
├── c

对应的数据库表值为:

| id | value | parent_id | key   | level |                                
| 1  | a     | 0         | "-"    | 1     |
| 2  | b     | 0         | "-"    | 1     |
| 3  | c     | 0         | "-"    | 2     |
| 4  | d     | 1         | "1-"   | 2     |
| 5  | e     | 1         | "1-"   | 2     |
| 6  | f     | 1         | "1-"   | 2     |
| 7  | x     | 2         | "2-"   | 2     |
| 8  | y     | 2         | "2-"   | 2     |
| 9  | z     | 2         | "2-"   | 2     |
| 10 | p     | 4         | "1-4-" | 3     |
| 11 | q     | 4         | "1-4-" | 3     |
| 12 | r     | 4         | "1-4-" | 3     |

于是,在给定一个节点d的时候,

  1. 查找d的所有子孙节点:select * from table_name where key like "${d.key}-${d.id}-%"
  2. 查找某个节点的所有子节点:select * from table_name where key like "${d.key}-${d.id}-%" and level=${d.level}+1

这个设计,结构非常简单。key和level是辅助字段,维护这两个字段成本很低,即使全部重建要比MPT简单多了。

yegle2.5k 声望

yegle的数据错了吧?根节点的 key应该是"" 吧。查找d的所有子孙节点应该是 select * from table_name where key like "${d.key}${d.id}-%" 查找子节点应该是: select * from table_name where key like "${d.key}${d.id}-%" and level=${d.level}+1

Rory_Ye · 2014年06月28日

+1

的确,应该按照@Rory_Ye 说的才对。否则,一级节点无法查看自己的子孙节点。

faker · 6月3日

我刚去看了Modified Preorder Tree,我有疑问的是如果我添加一个字节点,那么数据库的表不是都得改?这个树和线段树类似啊。

tansumanong · 6月8日

当我没说,原来是数据库,我以为是 java web,哈哈

tansumanong · 6月8日

查询的时候用的是like,会高效吗?

play175 · 7月7日

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏每日一篇技术文章

Metal_入门02_带你走流程

Metal 系列教程 Metal_入门01_为什么要学习它 Metal_入门02_带你走流程

1231
来自专栏LinXunFeng的专栏

打造Moya便捷解析库,提供RxSwift拓展

1323
来自专栏LhWorld哥陪你聊算法

【Linux篇】--awk的使用

awk是一个强大的文本分析工具。相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。 简单来说awk就是把文件逐行的读入,(空格...

1442
来自专栏零基础使用Django2.0.1打造在线教育网站

零基础使用Django2.0.1打造在线教育网站(七):数据库字段的定义(上)

努力与运动兼备~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

3656
来自专栏生信宝典

Linux学习-文件排序和FASTA文件操作

环境变量的补充 PATH只是众多环境变量中的一个变量,用于存储可执行文件所在的目录,以便在用户输入命令时可以查询的到。尤其是自己写的脚本或安装的程序,系统不会知...

27210
来自专栏流浪猫的golang

golang mongoDB 的集合创建以及增删改查操作

mongo官方没有golang 的官方驱动,但是有一个社区驱动: http://labix.org/mgo api文档:https://godoc.or...

2103
来自专栏零基础使用Django2.0.1打造在线教育网站

在线网站搭建(七):数据库字段的定义(上)

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

1972
来自专栏生信技能树

linux命令行文本操作一文就够

主要是 awk/grep/sed这三驾马车,加上vi这个神器,最后辅助一些小工具,包括 wc,cat,diff,join,paste,cut,uniq 这里 简...

4829
来自专栏JackeyGao的博客

Django小技巧17: QuerySets的latest和earliest方法

就像QuerySets的first和last方法一样, Django 还提供了earliest和latest方法. 用于获取最早和最新的数据,增强代码的可读性.

2562
来自专栏SDNLAB

Open vSwitch系列之openflow版本兼容

众所周知Open vSwitch支持的openflow版本从1.0到1.5版本(当前Open vSwitch版本是2.3.2)通过阅读代码,处理openflow...

57313

扫码关注云+社区

领取腾讯云代金券