最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang實踐指南之獲取目錄文件列表

 更新時間:2023年01月07日 12:46:10   作者:李遲  
在搭建項目中一般都會有確定項目根目錄的絕對路徑的需求,下面這篇文章主要給大家介紹了關(guān)于Golang實踐指南之獲取目錄文件列表的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

前言

獲取目錄下匹配某種規(guī)則的文件,返回文件列表,在開發(fā)中比較常用。本文實現(xiàn)此功能,并做了些擴展。

起因

筆者開發(fā)的內(nèi)部工具,需要查找各式文件,比如:

  • 數(shù)據(jù)文件,以csv結(jié)尾;
  • 信息文件,以md結(jié)尾(因為已有工具生成并渲染得html發(fā)布到網(wǎng)頁上,直接拿來使用);
  • 壓縮包,以zip結(jié)尾。

由于設(shè)計原因,部分不同各類的文件會在同一目錄出現(xiàn),因此,要實現(xiàn)一個接口用以獲取某個目錄下符合條件的文件。

設(shè)計思路如下:

  • 為簡單化,不遞歸查找子目錄,當(dāng)傳入的非目錄或不存在時,直接返回即可。
  • 設(shè)計是否帶目錄標志,有時僅需文件名稱,而不需要其目錄。
  • 設(shè)計返回文件列表數(shù)量,0表示所有文件,因此有時僅需要得到符合要求的第一個文件。
  • 設(shè)計是否排序標志,因為默認是升序,所以該標志實際是降序標志。

實現(xiàn)

為減少篇幅,僅摘錄必要的源碼。

根據(jù)匹配字符串(為描述方便,稱之為patten)的位置,需實現(xiàn)如下接口:

  • GetFileListBySuffix:patten 作為后綴,可按后綴名匹配。通過strings.HasSuffix判斷。
  • GetFileListByPrefix:同前,但是是前綴。通過strings.HasSuffix判斷。
  • GetFileListByKey:同上,在任意位置出現(xiàn)均可。通過strings.HasPrefix判斷。

另外實現(xiàn)os.FileInfo三個接口,達到降序排序目的。通過strings.Contains判斷。

封裝

代碼如下:

// 按文件名排序,可擴展至文件時間
type byName []os.FileInfo

//func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() } // 文件名升序,默認方式
func (f byName) Less(i, j int) bool { return f[i].Name() > f[j].Name() } // 文件名倒序
func (f byName) Len() int           { return len(f) }
func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }


// GetFileListBySuffix returns an ordered list of file paths.
// It recognize if given path is a file, and don't do recursive find.
func GetFileListBySuffix(dirPath, suffix string, needDir bool, isDescend bool, num int) ([]string, error) {
    if !IsExist(dirPath) {
        return nil, fmt.Errorf("given path does not exist: %s", dirPath)
    } else if IsFile(dirPath) {
        return []string{dirPath}, nil
    }

    // Given path is a directory.
    dir, err := os.Open(dirPath)
    if err != nil {
        return nil, err
    }

    fis, err := dir.Readdir(0)
    if err != nil {
        return nil, err
    }

    if isDescend {
        sort.Sort(byName(fis))
    }

    if num == 0 {
        num = len(fis)
    }
    files := make([]string, 0, num)
    for i := 0; i < num; i++ {
        fi := fis[i]
        if strings.HasSuffix(fi.Name(), suffix) {
            if needDir {
                files = append(files, filepath.Join(dirPath, fi.Name()))
            } else {
                files = append(files, fi.Name())
            }
        }
    }

    return files, nil
}

// as GetFileListBySuffix, but for Prefix
func GetFileListByPrefix(dirPath, suffix string, needDir bool, isDescend bool, num int) ([]string, error) {
    if !IsExist(dirPath) {
        return nil, fmt.Errorf("given path does not exist: %s", dirPath)
    } else if IsFile(dirPath) {
        return []string{dirPath}, nil
    }

    // Given path is a directory.
    dir, err := os.Open(dirPath)
    if err != nil {
        return nil, err
    }

    fis, err := dir.Readdir(0)
    if err != nil {
        return nil, err
    }

    if isDescend {
        sort.Sort(byName(fis))
    }

    if num == 0 {
        num = len(fis)
    }
    files := make([]string, 0, num)
    for i := 0; i < num; i++ {
        fi := fis[i]
        if strings.HasPrefix(fi.Name(), suffix) {
            if needDir {
                files = append(files, filepath.Join(dirPath, fi.Name()))
            } else {
                files = append(files, fi.Name())
            }
        }
    }

    return files, nil
}

// 根據(jù)關(guān)鍵字查找
func GetFileListByKey(dirPath, key string, needDir bool, isDescend bool, num int) ([]string, error) {
    if !IsExist(dirPath) {
        return nil, fmt.Errorf("given path does not exist: %s", dirPath)
    } else if IsFile(dirPath) {
        return []string{dirPath}, nil
    }

    // Given path is a directory.
    dir, err := os.Open(dirPath)
    if err != nil {
        return nil, err
    }

    fis, err := dir.Readdir(0)
    if err != nil {
        return nil, err
    }

    if isDescend {
        sort.Sort(byName(fis))
    }

    if num == 0 {
        num = len(fis)
    }
    files := make([]string, 0, num)
    for i := 0; i < num; i++ {
        fi := fis[i]
        if strings.Contains(fi.Name(), key) {
            if needDir {
                files = append(files, filepath.Join(dirPath, fi.Name()))
            } else {
                files = append(files, fi.Name())
            }
        }
    }

    return files, nil
}

測試及結(jié)果

測試用到的目錄及文件如下:

$ tree foo/
foo/
|-- bar_1.json
|-- bar_10.json
|-- bar_2.json
|-- bar_20.json
|-- bar_3.json
|-- log.1
|-- log.10
|-- log.2
|-- log.20
`-- log.3

0 directories, 10 files

前綴匹配調(diào)用:

list, err1 := GetFileListByPrefix("./foo", "log", true, false, 0)
fmt.Println(list, err1)

結(jié)果:

[foo\log.1 foo\log.10 foo\log.2 foo\log.20 foo\log.3] <nil>

后綴匹配調(diào)用:

list, err1 = GetFileListBySuffix("./foo", "json", true, false, 0)
fmt.Println(list, err1)

結(jié)果:

[foo\bar_1.json foo\bar_10.json foo\bar_2.json foo\bar_20.json foo\bar_3.json] <nil>

一般匹配調(diào)用:

list, err1 = GetFileListByKey("./foo", "1", true, false, 0)
fmt.Println(list, err1)

結(jié)果:

[foo\bar_1.json foo\bar_10.json foo\log.1 foo\log.10] <nil>

從結(jié)果分析,符合預(yù)期。

擴展

優(yōu)化接口

從前面封裝的接口代碼分析,絕大部分代碼是相同的,僅僅是讀取后對文件名稱的判斷不同而已。因此,可以將它們合成一個接口。設(shè)計如下:

  • patten額外添加*,通過*位置匹配前綴(foo*)、后綴(*foo)、中間(*foo*,即包含該關(guān)鍵字)。
  • 在內(nèi)部判斷并去掉*。其余機制同前。

代碼如下:

func GetFileListByKey_new(dirPath, patten string, needDir bool, isDescend bool, num int) ([]string, error) {
    if !IsExist(dirPath) {
        return nil, fmt.Errorf("given path does not exist: %s", dirPath)
    } else if IsFile(dirPath) { // 如果是文件,返回該文件
        return []string{dirPath}, nil
    }

    if len(patten) < 2 {
        return nil, fmt.Errorf("given patten len < 2")
    }

    // 默認為中間
    pos := 3
    rpatten := patten

    if patten[0] == '*' && patten[len(patten)-1] == '*' { // 一般
        rpatten = patten[1 : len(patten)-1]
        pos = 3
    } else if patten[0] == '*' { // 后綴
        pos = 1
        rpatten = patten[1:]
    } else if patten[len(patten)-1] == '*' { // 前綴
        rpatten = patten[:len(patten)-1]
        pos = 2
    }

    // Given path is a directory.
    dir, err := os.Open(dirPath)
    if err != nil {
        return nil, err
    }

    fis, err := dir.Readdir(0)
    if err != nil {
        return nil, err
    }

    fnum := len(fis)
    if fnum == 0 {
        return []string{}, nil
    }

    if isDescend {
        sort.Sort(byName(fis))
    }

    if num == 0 {
        num = fnum
    } else {
        if num > fnum {  // 如指定數(shù)量多于實際的,則使用實際
            num = fnum
        }
    }
    files := make([]string, 0, num)

    checkFile := func(filename string) bool {
        if pos == 1 {
            return strings.HasSuffix(filename, rpatten)
        } else if pos == 2 {
            return strings.HasPrefix(filename, rpatten)
        } else if pos == 3 {
            return strings.Contains(filename, rpatten)
        }
        return true
    }
    for i := 0; i < num; i++ {
        fi := fis[i]
        if checkFile(fi.Name()) {
            if needDir {
                files = append(files, filepath.Join(dirPath, fi.Name()))
            } else {
                files = append(files, fi.Name())
            }
        }
    }

    return files, nil

調(diào)用如下:

list, err1 = GetFileListByKey_new("./foo", "log*", true, false, 0)
fmt.Println(list, err1)
list, err1 = GetFileListByKey_new("./foo", "*json", true, false, 0)
fmt.Println(list, err1)
list, err1 = GetFileListByKey_new("./foo/", "*1*", true, false, 0)
fmt.Println(list, err1)

結(jié)果如下:

[foo\log.1 foo\log.10 foo\log.2 foo\log.20 foo\log.3] <nil>

[foo\bar_1.json foo\bar_10.json foo\bar_2.json foo\bar_20.json foo\bar_3.json] <nil>

[foo\bar_1.json foo\bar_10.json foo\log.1 foo\log.10] <nil>

正則表達式

雖然目前未使用到,但還是實現(xiàn)了按正則表達式來匹配文件名的接口,實現(xiàn)如下:

// 根據(jù)正規(guī)正則表達式查找
func GetFileListByPatten(dirPath, patten string, needDir bool, isDescend bool, num int) ([]string, error) {
    if !IsExist(dirPath) {
        return nil, fmt.Errorf("given path does not exist: %s", dirPath)
    } else if IsFile(dirPath) {
        return []string{dirPath}, nil
    }

    // Given path is a directory.
    dir, err := os.Open(dirPath)
    if err != nil {
        return nil, err
    }

    fis, err := dir.Readdir(0)
    if err != nil {
        return nil, err
    }

    fnum := len(fis)
    if fnum == 0 {
        return []string{}, nil
    }

    if isDescend {
        sort.Sort(byName(fis))
    }

    if num == 0 {
        num = fnum
    } else {
        if num > fnum { // 如指定數(shù)量多于實際的,則使用實際
            num = fnum
        }
    }

    match := func(str string, patten string) bool {
        rep := regexp.MustCompile(patten)
        ret := rep.MatchString(str)
        return ret
    }

    files := make([]string, 0, num)
    for i := 0; i < num; i++ {
        fi := fis[i]
        if match(fi.Name(), patten) {
            if needDir {
                files = append(files, filepath.Join(dirPath, fi.Name()))
            } else {
                files = append(files, fi.Name())
            }
        }
    }

    return files, nil
}

調(diào)用如下:

list, err1 = GetFileListByPatten("./foo", `log.+`, true, false, 0)
fmt.Println(`log.+ : `, list, err1)
list, err1 = GetFileListByPatten("./foo/", `[a-z0-9_]*.json`, true, false, 0)
fmt.Println(`[a-z0-9_]*.json : `, list, err1)

結(jié)果如下:

log.+ :  [foo\log.1 foo\log.10 foo\log.2 foo\log.20 foo\log.3] <nil>
[a-z0-9_]*.json :  [foo\bar_1.json foo\bar_10.json foo\bar_2.json foo\bar_20.json foo\bar_3.json] <nil>

說明:正則表達式一定要符合要求,否則不識別。

帶數(shù)字的文件名稱排序

前面的測試結(jié)果:

[foo\log.1 foo\log.10 foo\log.2 foo\log.20 foo\log.3]

可以看到,文件的排序不是我們想象中那樣的順序,實際上,從字符串比較(因為代碼就是使用這個方式)的角度看,上述排序是正常的。如要達到想象的順序,則要修改比較方式,重新實現(xiàn)os.FileInfo中的Less接口。

因為帶數(shù)字的文件名稱有各式各樣,此處假定按文件的“后綴名”數(shù)字由大到小排序。實際上,這是真實的的場合:某工程程序產(chǎn)生的日志,按超過指定大小會自動創(chuàng)建新的文件,后綴帶數(shù)字即表達有多少個日志文件。

代碼如下:

// 按帶數(shù)字的文件名排序
type byNumericalFilename []os.FileInfo

func (f byNumericalFilename) Len() int      { return len(f) }
func (f byNumericalFilename) Swap(i, j int) { f[i], f[j] = f[j], f[i] }

func (f byNumericalFilename) Less(i, j int) bool {
    pathA := f[i].Name()
    pathB := f[j].Name()

    // !! 根據(jù)需求,文件最后是數(shù)字,按其值降序排序,示例:ddd.log.x.1 ddd.log.x.2
    // 如有其它者,也可以修改
    a, err1 := strconv.Atoi(pathA[strings.LastIndex(pathA, ".")+1:])
    b, err2 := strconv.Atoi(pathB[strings.LastIndex(pathB, ".")+1:])

    // 整體文件(不含后綴名)名稱排序,名稱是數(shù)字,如1.txt 2.txt 10.txt
    // a, err1 := strconv.Atoi(pathA[0:strings.LastIndex(pathA, ".")])
    // b, err2 := strconv.Atoi(pathB[0:strings.LastIndex(pathB, ".")])

    // 有錯誤,默認降序
    if err1 != nil || err2 != nil {
        return pathA > pathB
    }

    // 按數(shù)字降序
    return a > b
}


func getFileListByPrefix(dirPath, suffix string, needDir bool, num int) ([]string, error) {
    if !isExist(dirPath) {
        return nil, fmt.Errorf("given path does not exist: %s", dirPath)
    } else if isFile(dirPath) {
        return []string{dirPath}, nil
    }

    // Given path is a directory.
    dir, err := os.Open(dirPath)
    if err != nil {
        return nil, err
    }

    fis, err := dir.Readdir(0)
    if err != nil {
        return nil, err
    }

    fnum := len(fis)
    if fnum == 0 {
        return []string{}, nil
    }

    sort.Sort(byNumericalFilename(fis))

    if num == 0 {
        num = fnum
    } else {
        if num > fnum {
            num = fnum
        }
    }
    files := make([]string, 0, num)
    for i := 0; i < num; i++ {
        fi := fis[i]
        if strings.HasPrefix(fi.Name(), suffix) {
            if needDir {
                files = append(files, filepath.Join(dirPath, fi.Name()))
            } else {
                files = append(files, fi.Name())
            }
        }
    }

    return files, nil
}

調(diào)用如下:

list, err1 = getFileListByPrefix("./foo/", `log`, true, 0)
fmt.Println(`sort number : `, list, err1)

結(jié)果如下:

sort number :  [foo\log.20 foo\log.10 foo\log.3 foo\log.2 foo\log.1] <nil>

從結(jié)果看,已實現(xiàn)根據(jù)數(shù)字從大到小排序。

總結(jié)

文中所實現(xiàn)的接口,已應(yīng)用到筆者實際的工程。目前未發(fā)現(xiàn)有什么問題。

隔了一天的PS:

由于傳遞參數(shù)可以指定文件數(shù)量,當(dāng)指定的數(shù)量多了實際數(shù)量時,會報錯,需要加上判斷。在“優(yōu)化接口”及后面小節(jié)的代碼中已修正,前面由于實際中不使用,故保留。

有時話真的不是說得太滿。記之并以此為鑒。

到此這篇關(guān)于Golang實踐指南之獲取目錄文件列表的文章就介紹到這了,更多相關(guān)Golang獲取目錄文件列表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang基礎(chǔ)教程之字符串string實例詳解

    Golang基礎(chǔ)教程之字符串string實例詳解

    這篇文章主要給大家介紹了關(guān)于Golang基礎(chǔ)教程之字符串string的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Go語言實現(xiàn)釘釘發(fā)送通知

    Go語言實現(xiàn)釘釘發(fā)送通知

    本文通過代碼給大家介紹了Go語言實現(xiàn)釘釘發(fā)送通知,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-11-11
  • 解決老版本goland無法調(diào)試新版本go的問題

    解決老版本goland無法調(diào)試新版本go的問題

    這篇文章主要給大家介紹了如何解決老版本goland無法調(diào)試新版本go的問題,文中通過代碼示例給大家講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下
    2023-11-11
  • Go語言的互斥鎖的詳細使用

    Go語言的互斥鎖的詳細使用

    本文主要介紹了Go語言的互斥鎖的詳細使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Go語言參數(shù)傳遞是傳值還是傳引用

    Go語言參數(shù)傳遞是傳值還是傳引用

    Go?語言到底是傳值(值傳遞),還是傳引用(引用傳遞)?本文就詳細介紹一下,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • golang類型斷言的實現(xiàn)示例

    golang類型斷言的實現(xiàn)示例

    在Go語言中,類型斷言用于從接口類型獲取其具體類型的值,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10
  • Golang?Gin?中間件?Next()方法示例詳解

    Golang?Gin?中間件?Next()方法示例詳解

    這篇文章主要介紹了Golang?Gin?中間件?Next()方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • 使用gorm.Scopes函數(shù)實現(xiàn)復(fù)用查詢邏輯示例

    使用gorm.Scopes函數(shù)實現(xiàn)復(fù)用查詢邏輯示例

    這篇文章主要為大家介紹了使用gorm.Scopes函數(shù)實現(xiàn)復(fù)用查詢邏輯示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • GoZero中make后返回數(shù)據(jù)與原數(shù)據(jù)不對齊的幾種解決方案

    GoZero中make后返回數(shù)據(jù)與原數(shù)據(jù)不對齊的幾種解決方案

    在Go語言中,make是用來創(chuàng)建切片、映射(map)和通道(channel)的內(nèi)建函數(shù),但是,在使用 make 創(chuàng)建切片時,若不理解如何正確使用其返回值,可能會遇到數(shù)據(jù)對不上或結(jié)果不符合預(yù)期的情況,本文將分析在GoZero或其他基于Go的應(yīng)用中,使用make時可能導(dǎo)致的問題及解決方案
    2025-01-01
  • golang解析yaml文件操作

    golang解析yaml文件操作

    這篇文章主要介紹了golang解析yaml文件操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評論

大兴区| 大城县| 广宗县| 永福县| 铁岭市| 张家港市| 泸水县| 泽库县| 汾阳市| 长岭县| 龙井市| 奉贤区| 景宁| 柯坪县| 田东县| 郸城县| 晋城| 玛沁县| 衡南县| 宁海县| 临泽县| 永泰县| 左权县| 福海县| 自治县| 鹿邑县| 花莲县| 韩城市| 修水县| 岚皋县| 宁津县| 手游| 黎城县| 临邑县| 兴文县| 清水河县| 莎车县| 偏关县| 淮北市| 泸西县| 新郑市|