dpi74187 2012-09-29 23:21
浏览 282
已采纳

使用go语言提取目录层次结构

I'm trying to extract the directory hierarchy of a folder into a datastructure in go language. filepath.Walk seems to be the way to go but all I can do so far is to print the names of files and folders. Here's what I'm using:

func main() {
    visit := func(path string, info os.FileInfo, err error) error {
        if info.IsDir() {
            fmt.Println("dir:  ", path)
        } else {
            fmt.Println("file: ", path)
        }
        return nil
    }

    err := filepath.Walk("./", visit)
    if err != nil {
        log.Fatal(err)
    }
}

this prints the names of folders like:

dir:   folder1
file:  folder1/file1.txt
file:  folder1/file2.txt
file:  folder1/file3.txt
file:  folder1/file4.txt
dir:   folder1/folder2
file:  folder1/folder2/file5.txt
file:  folder1/folder2/file6.txt
file:  folder1/folder2/file7.txt
file:  folder1/folder2/file8.txt
file:  folder1/folder2/file9.txt

for tree structure I thought about using something like:

type File struct {
    Name string
    Content string
}

type Folder struct {
    Name    string
    Files   []File
    Folders []Folder
}

but of course any suggestions are welcomed.

How can I convert this to a tree structure in go? Is there an easier way to do this?

  • 写回答

4条回答 默认 最新

  • dsnd7200 2012-09-30 07:34
    关注

    AFAIK there is nothing ready-made for this in the Go standard lib.

    Tree structures lend themselves well to a recursive approach. I defined addFile and addFolder methods on your File and Folder types. Starting with a root folder, you can then call these methods in Walk. If you get a/b/c, we'll be calling root.addFile(a, b, c), a.addFile(b, c), b.addFile(c).

    I also changed Folder.Folders to a map, because filepath.Walk always gives us full paths, so we can split those and look up their components in the folder map.

    Here is some quick and dirty code that probably has bugs and doesn't do full error checking. It only works for the current directory, but that should be easy to fix.

    I also added a String() method on Folder, which is recognized by the compiler and will be used when printing out instances of the type.

    package main
    
    import (
        "log"
        "os"
        "path/filepath"
        "strings"
    )
    
    type File struct {
        Name string
    }
    
    type Folder struct {
        Name    string
        Files   []File
        Folders map[string]*Folder
    }
    
    func newFolder(name string) *Folder {
        return &Folder{name, []File{}, make(map[string]*Folder)}
    }
    
    func (f *Folder) getFolder(name string) *Folder {
        if nextF, ok := f.Folders[name]; ok {
            return nextF
        } else {
            log.Fatalf("Expected nested folder %v in %v
    ", name, f.Name)
        }
        return &Folder{} // cannot happen
    }
    
    func (f *Folder) addFolder(path []string) {
        for i, segment := range path {
            if i == len(path)-1 { // last segment == new folder
                f.Folders[segment] = newFolder(segment)
            } else {
                f.getFolder(segment).addFolder(path[1:])
            }
        }
    }
    
    func (f *Folder) addFile(path []string) {
        for i, segment := range path {
            if i == len(path)-1 { // last segment == file
                f.Files = append(f.Files, File{segment})
            } else {
                f.getFolder(segment).addFile(path[1:])
                return
            }
        }
    }
    
    func (f *Folder) String() string {
        var str string
        for _, file := range f.Files {
            str += f.Name + string(filepath.Separator) + file.Name + "
    "
        }
        for _, folder := range f.Folders {
            str += folder.String()
        }
        return str
    }
    
    func main() {
        startPath := "."
        rootFolder := newFolder(startPath)
    
        visit := func(path string, info os.FileInfo, err error) error {
            segments := strings.Split(path, string(filepath.Separator))
            if info.IsDir() {
                if path != startPath {
                    rootFolder.addFolder(segments)
                }
            } else {
                rootFolder.addFile(segments)
            }
            return nil
        }
    
        err := filepath.Walk(startPath, visit)
        if err != nil {
            log.Fatal(err)
        }
    
        log.Printf("%v
    ", rootFolder)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?