欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Go語言實(shí)現(xiàn)一個(gè)目錄樹打印工具

 更新時(shí)間:2025年06月17日 08:28:49   作者:嘆一曲當(dāng)時(shí)只道是尋常  
在日常開發(fā)中,我們經(jīng)常需要可視化項(xiàng)目的目錄結(jié)構(gòu),下面小編將介紹一款用Go語言開發(fā)的目錄樹打印工具,它不僅能生成美觀的目錄結(jié)構(gòu)圖,還提供多種實(shí)用功能

在日常開發(fā)中,我們經(jīng)常需要可視化項(xiàng)目的目錄結(jié)構(gòu)。無論是編寫文檔、分享項(xiàng)目結(jié)構(gòu),還是單純了解代碼布局,一個(gè)清晰的目錄樹展示都至關(guān)重要。今天我將介紹一款用Go語言開發(fā)的目錄樹打印工具,它不僅能生成美觀的目錄結(jié)構(gòu)圖,還提供多種實(shí)用功能!

功能亮點(diǎn)

多層級展示:支持自定義深度限制

隱藏文件處理:可選顯示隱藏文件/文件夾

多種輸出方式:控制臺(tái)打印、保存文件、復(fù)制到剪貼板

美觀可視化:使用emoji圖標(biāo)標(biāo)識(shí)不同類型

靈活連接線:可選的樹形連接線展示

智能排序:目錄優(yōu)先,按名稱排序

技術(shù)實(shí)現(xiàn)解析

核心數(shù)據(jù)結(jié)構(gòu)

type DirectoryPrinter struct {
    rootDir       string      // 根目錄路徑
    showHidden    bool        // 是否顯示隱藏文件
    currentDepth  int         // 當(dāng)前遞歸深度
    maxDepth      int         // 最大深度限制
    indentSymbol  string      // 縮進(jìn)符號(hào)(4個(gè)空格)
    folderSymbol  string      // 文件夾圖標(biāo)
    fileSymbol    string      // 文件圖標(biāo)
    output        []string    // 輸出內(nèi)容收集
    showConnector bool        // 是否顯示連接線
}

關(guān)鍵算法邏輯

1.文件排序策略:

目錄優(yōu)先于文件

相同類型按名稱升序排列

sort.Slice(filteredEntries, func(i, j int) bool {
    if filteredEntries[i].IsDir() != filteredEntries[j].IsDir() {
        return filteredEntries[i].IsDir()
    }
    return filteredEntries[i].Name() < filteredEntries[j].Name()
})

2.連接線生成邏輯:

非最后一項(xiàng):├──

最后一項(xiàng):└──

if dp.showConnector {
    isLast := index == total-1
    connector := "├── "
    if isLast {
        connector = "└── "
    }
    return fmt.Sprintf("%s%s?? %s\n", prefix, connector, entry.Name())
}

3.遞歸深度控制:

if dp.maxDepth > 0 && dp.currentDepth >= dp.maxDepth {
    return nil
}

使用指南

命令行參數(shù)

參數(shù)說明示例
--show-hidden顯示隱藏文件--show-hidden
--output-file保存到文件--output-file tree.txt
--copy-ClipBoard復(fù)制到剪貼板--copy-ClipBoard
--max-depth設(shè)置最大深度--max-depth 3
--show-connector顯示連接線--show-connector
--help顯示幫助--help

使用示例

基本用法(顯示當(dāng)前目錄結(jié)構(gòu)):

directory_printer

顯示隱藏文件并限制深度:

directory_printer --show-hidden --max-depth 2

保存到文件并顯示連接線:

directory_printer --output-file project_tree.txt --show-connector

輸出示例

?? my-project
    ?? src
        ?? controllers
        ?? models
        ?? views
    ?? config
    ?? public
        ?? css
        ?? js
        ?? images
    ?? README.md
    ?? .gitignore
    ?? go.mod

帶連接線版本:

?? my-project
├── ?? src
│   ├── ?? controllers
│   ├── ?? models
│   └── ?? views
├── ?? config
├── ?? public
│   ├── ?? css
│   ├── ?? js
│   └── ?? images
├── ?? README.md
├── ?? .gitignore
└── ?? go.mod

實(shí)現(xiàn)細(xì)節(jié)解析

根目錄處理

rootName := filepath.Base(rootDir)
if rootName == "." {
    // 獲取當(dāng)前工作目錄的絕對路徑
    absPath, err := filepath.Abs(rootDir)
    if err != nil {
        rootName = "current_directory"
    } else {
        rootName = filepath.Base(absPath)
    }
}
printer.output = append(printer.output, fmt.Sprintf("?? %s\n", rootName))

輸出處理邏輯

// 保存到文件
if *outputFile != "" {
    err = saveToFile(*outputFile, printer.output)
}

// 復(fù)制到剪貼板
if *copyClipBoard {
    content := strings.Join(printer.output, "")
    err = clipboard.WriteAll(content)
}

???????// 控制臺(tái)輸出
fmt.Println("\n=== Directory Structure ===")
for _, line := range printer.output {
    fmt.Print(line)
}

遞歸目錄遍歷

childPrinter := &DirectoryPrinter{
    rootDir:       filepath.Join(dp.rootDir, entry.Name()),
    showHidden:    dp.showHidden,
    currentDepth:  dp.currentDepth + 1,
    maxDepth:      dp.maxDepth,
    indentSymbol:  dp.indentSymbol,
    folderSymbol:  dp.folderSymbol,
    fileSymbol:    dp.fileSymbol,
    output:        dp.output,
    showConnector: dp.showConnector,
}
if err := childPrinter.printDirectory(); err != nil {
    return err
}
dp.output = childPrinter.output

附錄

完整代碼

package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/atotto/clipboard"
)

type DirectoryPrinter struct {
	rootDir       string
	showHidden    bool
	currentDepth  int
	maxDepth      int
	indentSymbol  string
	folderSymbol  string
	fileSymbol    string
	output        []string
	showConnector bool // 新增字段控制是否顯示連接線
}

func (dp *DirectoryPrinter) printDirectory() error {
	// 檢查是否超過最大深度
	if dp.maxDepth > 0 && dp.currentDepth >= dp.maxDepth {
		return nil
	}

	entries, err := os.ReadDir(dp.rootDir)
	if err != nil {
		return err
	}

	// 過濾隱藏文件
	var filteredEntries []os.DirEntry
	for _, entry := range entries {
		if dp.showHidden || !strings.HasPrefix(entry.Name(), ".") {
			filteredEntries = append(filteredEntries, entry)
		}
	}

	// 按類型(目錄優(yōu)先)和名稱排序
	sort.Slice(filteredEntries, func(i, j int) bool {
		// 首先按類型排序(目錄在前)
		if filteredEntries[i].IsDir() != filteredEntries[j].IsDir() {
			return filteredEntries[i].IsDir()
		}
		// 同類型按名稱排序
		return filteredEntries[i].Name() < filteredEntries[j].Name()
	})

	total := len(filteredEntries)
	for i, entry := range filteredEntries {
		prefix := strings.Repeat(dp.indentSymbol, dp.currentDepth)
		var line string
		if entry.IsDir() {
			line = dp.buildFolderLine(prefix, i, total, entry)
		} else {
			line = dp.buildFileLine(prefix, i, total, entry)
		}
		dp.output = append(dp.output, line)

		// 遞歸處理子文件夾
		if entry.IsDir() {
			childPrinter := &DirectoryPrinter{
				rootDir:       filepath.Join(dp.rootDir, entry.Name()),
				showHidden:    dp.showHidden,
				currentDepth:  dp.currentDepth + 1,
				maxDepth:      dp.maxDepth,
				indentSymbol:  dp.indentSymbol,
				folderSymbol:  dp.folderSymbol,
				fileSymbol:    dp.fileSymbol,
				output:        dp.output,
				showConnector: dp.showConnector,
			}
			if err := childPrinter.printDirectory(); err != nil {
				return err
			}
			dp.output = childPrinter.output
		}
	}

	return nil
}

func (dp *DirectoryPrinter) buildFolderLine(prefix string, index, total int, entry os.DirEntry) string {
	if dp.showConnector {
		isLast := index == total-1
		connector := "├── "
		if isLast {
			connector = "└── "
		}
		return fmt.Sprintf("%s%s?? %s\n", prefix, connector, entry.Name())
	}
	return fmt.Sprintf("%s?? %s\n", prefix, entry.Name())
}

func (dp *DirectoryPrinter) buildFileLine(prefix string, index, total int, entry os.DirEntry) string {
	if dp.showConnector {
		isLast := index == total-1
		connector := "├── "
		if isLast {
			connector = "└── "
		}
		return fmt.Sprintf("%s%s?? %s\n", prefix, connector, entry.Name())
	}
	return fmt.Sprintf("%s?? %s\n", prefix, entry.Name())
}

func usage() {
	fmt.Println("Usage: directory_printer [OPTIONS] [PATH]")
	fmt.Println("\nOptions:")
	fmt.Println("  --show-hidden               Include hidden files and directories")
	fmt.Println("  --output-file <file_path>   Save the directory structure to a file")
	fmt.Println("  --copy-ClipBoard            Copy Directory structure to clipboard")
	fmt.Println("  --max-depth <number>        Maximum directory depth to display (0 for all levels, 1 for root only)")
	fmt.Println("  --show-connector            Show connector characters (├── and └──)")
	fmt.Println("  --help                      Display this help message")
	fmt.Println("\nExample:")
	fmt.Println("  directory_printer --show-hidden --max-depth 2 --output-file output.txt /path/to/directory")
}

func isDirectory(path string) bool {
	fileInfo, err := os.Stat(path)
	if err != nil {
		return false
	}
	return fileInfo.IsDir()
}

func saveToFile(filePath string, content []string) error {
	file, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	for _, line := range content {
		if _, err := file.WriteString(line); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	showHidden := flag.Bool("show-hidden", false, "Include hidden files and directories")
	outputFile := flag.String("output-file", "", "Save the directory structure to a file")
	copyClipBoard := flag.Bool("copy-ClipBoard", true, "Copy Directory structure to clipboard")
	maxDepth := flag.Int("max-depth", 0, "Maximum directory depth to display (0 for all levels, 1 for root only)")
	showConnector := flag.Bool("show-connector", false, "Show connector characters (├── and └──)")
	help := flag.Bool("help", false, "Display this help message")
	flag.Parse()

	if *help {
		usage()
		os.Exit(0)
	}

	var rootDir string
	if len(flag.Args()) == 0 {
		rootDir = "."
	} else {
		rootDir = flag.Arg(0)
	}

	if !isDirectory(rootDir) {
		fmt.Printf("Error: %s is not a valid directory\n", rootDir)
		os.Exit(1)
	}

	printer := &DirectoryPrinter{
		rootDir:       rootDir,
		showHidden:    *showHidden,
		currentDepth:  0,
		maxDepth:      *maxDepth,
		indentSymbol:  "    ", // 使用4個(gè)空格作為視覺縮進(jìn)
		folderSymbol:  "",
		fileSymbol:    "",
		output:        []string{},
		showConnector: *showConnector,
	}

	rootName := filepath.Base(rootDir)
	if rootName == "." {
		// 獲取當(dāng)前工作目錄的絕對路徑
		absPath, err := filepath.Abs(rootDir)
		if err != nil {
			rootName = "current_directory"
		} else {
			rootName = filepath.Base(absPath)
		}
	}
	printer.output = append(printer.output, fmt.Sprintf("?? %s\n", rootName))
	// 增加根目錄的縮進(jìn)
	printer.currentDepth = 1

	err := printer.printDirectory()
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(1)
	}

	if *outputFile != "" {
		err = saveToFile(*outputFile, printer.output)
		if err != nil {
			fmt.Printf("Failed to save to file: %v\n", err)
			os.Exit(1)
		}
		fmt.Printf("Directory structure saved to: %s\n", *outputFile)
	}
	if *copyClipBoard {
		content := strings.Join(printer.output, "")
		err = clipboard.WriteAll(content)
		if err != nil {
			fmt.Printf("Failed to copy to clipboard: %v\n", err)
		} else {
			fmt.Println("Directory structure copied to clipboard")
		}
	}

	fmt.Println("\n=== Directory Structure ===")
	for _, line := range printer.output {
		fmt.Print(line)
	}
}

總結(jié)

這款Go語言實(shí)現(xiàn)的目錄樹打印工具通過簡潔的代碼實(shí)現(xiàn)了強(qiáng)大的功能,無論是開發(fā)者快速查看項(xiàng)目結(jié)構(gòu),還是編寫技術(shù)文檔時(shí)展示目錄布局,它都是一個(gè)得力的助手。清晰的emoji標(biāo)識(shí)、靈活的輸出選項(xiàng)和可定制的顯示深度,讓它成為你開發(fā)工具箱中不可或缺的一員。

到此這篇關(guān)于基于Go語言實(shí)現(xiàn)一個(gè)目錄樹打印工具的文章就介紹到這了,更多相關(guān)Go目錄樹打印內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang xorm及time.Time自定義解決json日期格式的問題

    golang xorm及time.Time自定義解決json日期格式的問題

    這篇文章主要介紹了golang xorm及time.Time自定義解決json日期格式的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang?json?庫中的RawMessage功能原理

    Golang?json?庫中的RawMessage功能原理

    今天我們來學(xué)習(xí)一個(gè) Golang 官方 json 庫提供了一個(gè)經(jīng)典能力RawMessage,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • go?打包運(yùn)行文件在windows,liunx運(yùn)行

    go?打包運(yùn)行文件在windows,liunx運(yùn)行

    這篇文章主要介紹了go?打包運(yùn)行文件在windows,liunx運(yùn)行的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • GoLang?channel關(guān)閉狀態(tài)相關(guān)操作詳解

    GoLang?channel關(guān)閉狀態(tài)相關(guān)操作詳解

    Channel?和?goroutine?的結(jié)合是?Go?并發(fā)編程的大殺器。而?Channel?的實(shí)際應(yīng)用也經(jīng)常讓人眼前一亮,通過與?select,cancel,timer?等結(jié)合,它能實(shí)現(xiàn)各種各樣的功能。接下來,我們就要介紹GoLang?channel關(guān)閉狀態(tài)相關(guān)操作
    2022-10-10
  • gin正確多次讀取http?request?body內(nèi)容實(shí)現(xiàn)詳解

    gin正確多次讀取http?request?body內(nèi)容實(shí)現(xiàn)詳解

    這篇文章主要為大家介紹了gin正確多次讀取http?request?body內(nèi)容實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • golang踩坑實(shí)戰(zhàn)之channel的正確使用方式

    golang踩坑實(shí)戰(zhàn)之channel的正確使用方式

    Golang?channel是Go語言中一個(gè)非常重要的特性,除了用來處理并發(fā)編程的任務(wù)中,它還可以用來進(jìn)行消息傳遞和事件通知,這篇文章主要給大家介紹了關(guān)于golang踩坑實(shí)戰(zhàn)之channel的正確使用方式,需要的朋友可以參考下
    2023-06-06
  • 詳解Go語言如何利用上下文進(jìn)行并發(fā)計(jì)算

    詳解Go語言如何利用上下文進(jìn)行并發(fā)計(jì)算

    在Go編程中,上下文(context)是一個(gè)非常重要的概念,它包含了與請求相關(guān)的信息,本文主要來和大家討論一下如何在并發(fā)計(jì)算中使用上下文,感興趣的可以了解下
    2024-02-02
  • Golang對MongoDB數(shù)據(jù)庫的操作簡單封裝教程

    Golang對MongoDB數(shù)據(jù)庫的操作簡單封裝教程

    mongodb官方?jīng)]有關(guān)于go的mongodb的驅(qū)動(dòng),因此只能使用第三方驅(qū)動(dòng),mgo就是使用最多的一種。下面這篇文章主要給大家介紹了關(guān)于利用Golang對MongoDB數(shù)據(jù)庫的操作簡單封裝的相關(guān)資料,需要的朋友可以參考下
    2018-07-07
  • Golang設(shè)計(jì)模式之組合模式講解

    Golang設(shè)計(jì)模式之組合模式講解

    這篇文章主要介紹了Golang設(shè)計(jì)模式之組合模式,組合模式針對于特定場景,如文件管理、組織管理等,使用該模式能簡化管理,使代碼變得非常簡潔
    2023-01-01
  • golang?channel多協(xié)程通信常用方法底層原理全面解析

    golang?channel多協(xié)程通信常用方法底層原理全面解析

    channel?是?goroutine?與?goroutine?之間通信的重要橋梁,借助?channel,我們能很輕易的寫出一個(gè)多協(xié)程通信程序,今天,我們就來看看這個(gè)?channel?的常用用法以及底層原理
    2023-09-09

最新評論