package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
)

//文件目录树形结构节点
type dirTreeNode struct {
	name  string
	child []dirTreeNode
}

var iCount int = 0

//递归遍历文件目录
func getDirTree(pathName string) (dirTreeNode, error) {

	rd, err := ioutil.ReadDir(pathName)
	if err != nil {
		log.Fatalf("Read dir '%s' failed: %v", pathName, err)
	}
	var tree, childNode dirTreeNode
	tree.name = pathName
	var name, fullName string
	for _, fileDir := range rd {
		name = fileDir.Name()
		fullName = pathName + "/" + name
		if fileDir.IsDir() {
			childNode, err = getDirTree(fullName)
			if err != nil {
				log.Fatalf("Read dir '%s' failed: %v", fullName, err)
			}
		} else {
			childNode.name = name
			childNode.child = nil

			//读取文件内容并打印
			readLine(fullName, processLine)
			iCount++
		}
		tree.child = append(tree.child, childNode)
	}
	return tree, nil
}

//递归打印文件目录
func printDirTree(tree dirTreeNode, prefix string) {
	fmt.Println(prefix + tree.name)
	if len(tree.child) > 0 {
		prefix += "----"
		for _, childNode := range tree.child {
			printDirTree(childNode, prefix)
		}
	}
}

func processLine(line []byte) {
	os.Stdout.Write(line)
}

// read one file and use hookfn to process each line
func readLine(filePth string, hookfn func([]byte)) error {
	f, err := os.Open(filePth)
	if err != nil {
		return err
	}
	defer f.Close()

	bfRd := bufio.NewReader(f)
	for {
		line, err := bfRd.ReadBytes('\n')
		hookfn(line)    //放在错误处理前面,即使发生错误,也会处理已经读取到的数据。
		if err != nil { //遇到任何错误立即返回,并忽略 EOF 错误信息
			if err == io.EOF {
				return nil
			}
			return err
		}
	}

}

func main() {
	dirName := "Users/"
	tree, err := getDirTree(dirName)
	if err != nil {
		log.Fatalln("read dir", dirName, "fail: ", err)
	}

	fmt.Printf("\n")
	fmt.Println("File Count:", iCount)

	printDirTree(tree, "")

}

以上用的是ioutil.ReadDir的方法,然后用range遍历目录节点的list

ReadDir 函数

func ReadDir(dirname string) ([]os.FileInfo, error)

读取 dirname 指定的目录, 并返回一个根据文件名进行排序的目录节点列表。

 

遍历的过程可以用另一个方法:

使用filepath.Walk包中的功能path/filepath 它遍历一个文件树

filepath.WalkFunc,为树中的每个文件或目录调用一个类型的函数,包括根。
文件按词汇顺序走。
不遵循符号链接。
此示例中的代码列出了以当前目录为根的文件树中所有文件和目录的路径和大小。

err := filepath.Walk(".",
    func(path string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }
    fmt.Println(path, info.Size())
    return nil
})
if err != nil {
    log.Println(err)
}

 

 

 

 

另:

关于写文件

 WriteFile方法:

func check(e error) { 
if e != nil { 
panic(e) 
} 
}

 

var d1 = []byte(wireteString); 
err2 := ioutil.WriteFile(“./output2.txt”, d1, 0666) //写入文件(字节数组) 
check(err2)

WriteFile将data写入到filename指定的文件中。如果文件不存在,WriteFile将会创建该文件,且文件的权限是perm;如果文件存在,先清空文件内容再写入。

 

WriteString方法:

var testString = “测试n” 
var filename = “./output1.txt”; 
var f *os.File 
var err1 error; 
if checkFileIsExist(filename) { //如果文件存在 
f, err1 = os.OpenFile(filename, os.O_APPEND, 0666) //打开文件 
fmt.Println(“文件存在”); 
}else { 
f, err1 = os.Create(filename) //创建文件 
fmt.Println(“文件不存在”); 
} 
check(err1) 
n, err1 := io.WriteString(f, testString ) //写入文件(字符串) 
check(err1) 
fmt.Printf(“写入 %d 个字节n”, n);

 

 

 

另:

str2 := "hello"
    data2 := []byte(str2)
    fmt.Println(data2)
    str2 = string(data2[:])