วิธีการสแกนระบบไฟล์


104
  1. ฉันต้องเขียนฟังก์ชันซึ่งเมื่อกำหนดเส้นทางของโฟลเดอร์จะสแกนไฟล์ที่รูทที่โฟลเดอร์นั้น
  2. จากนั้นฉันต้องแสดงโครงสร้างไดเร็กทอรีที่โฟลเดอร์นั้น

ฉันรู้วิธีทำ 2 (ฉันจะใช้ jstree เพื่อแสดงในเบราว์เซอร์)


2
คุณต้องการใช้เพื่อผ่านแผนผังไดเรกทอรีแบบวนซ้ำหรือไม่?
newacct

คำตอบ:


195

แก้ไข : มีคนจำนวนมากที่ยังคงตอบคำตอบนี้ซึ่งฉันคิดว่าฉันจะอัปเดตสำหรับ Go1 API นี่คือตัวอย่างการทำงานของfilepath.Walk () ต้นฉบับอยู่ด้านล่าง

package main

import (
  "path/filepath"
  "os"
  "flag"
  "fmt"
)

func visit(path string, f os.FileInfo, err error) error {
  fmt.Printf("Visited: %s\n", path)
  return nil
} 


func main() {
  flag.Parse()
  root := flag.Arg(0)
  err := filepath.Walk(root, visit)
  fmt.Printf("filepath.Walk() returned %v\n", err)
}

โปรดทราบว่า filepath.Walk เดินตามแผนผังไดเรกทอรีแบบวนซ้ำ

นี่คือตัวอย่างการรัน:

$ mkdir -p dir1/dir2
$ touch dir1/file1 dir1/dir2/file2
$ go run walk.go dir1
Visited: dir1
Visited: dir1/dir2
Visited: dir1/dir2/file2
Visited: dir1/file1
filepath.Walk() returned <nil>

คำตอบเดิมดังนี้อินเตอร์เฟซสำหรับเส้นทางไฟล์ที่สามารถเดินได้มีการเปลี่ยนแปลง ณ weekly.2011-09-16 ดูhttp://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 โค้ดด้านล่างจะใช้ไม่ได้กับ GO เวอร์ชันวางจำหน่ายในอนาคตอันใกล้นี้

มีจริงเป็นฟังก์ชั่นใน lib มาตรฐานเพียงสำหรับการนี้: filepath.Walk

package main

import (
    "path/filepath"
    "os"
    "flag"
)

type visitor int

// THIS CODE NO LONGER WORKS, PLEASE SEE ABOVE
func (v visitor) VisitDir(path string, f *os.FileInfo) bool {
    println(path)
    return true
} 

func (v visitor) VisitFile(path string, f *os.FileInfo) {
    println(path)
}

func main() {
    root := flag.Arg(0)
    filepath.Walk(root, visitor(0), nil)
}

1
filepath.Walkไม่ได้ติดตาม symlink โดยวิธีการ
0xcaff

3
การfilepath.Walkเรียกกลับ@FrancescoPasa จะถูกทริกเกอร์บน symlink (ทั้งไฟล์และไดเร็กทอรี) ใช่มันจะไม่ติดตามพวกเขา แต่การเรียกกลับจะจดจำ symlink และดำเนินการต่อไปนั่นคือการติดตามfilepath.Walkเพื่อให้แน่ใจก่อนว่าเส้นทางนั้นยังไม่ได้รับการเยี่ยมชม
colm.anseo

15

นี่คือวิธีรับข้อมูลไฟล์สำหรับไฟล์ในไดเร็กทอรี

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    dirname := "." + string(filepath.Separator)
    d, err := os.Open(dirname)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    defer d.Close()
    fi, err := d.Readdir(-1)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    for _, fi := range fi {
        if fi.Mode().IsRegular() {
            fmt.Println(fi.Name(), fi.Size(), "bytes")
        }
    }
}

@peterSO: Readdir (-1) หมายถึงอะไร? เนื่องจาก Readdir ยอมรับเฉพาะประเภทสตริงและตามเอกสารประกอบ API สตริงจึงไม่สามารถเป็น NUL เท่านั้นและไม่มีข้อ จำกัด อื่น ๆ .. และประเภทการส่งคืนของ "fi" ใน Readdir เป็นอย่างไรจึงสามารถดำเนินการได้ (มันคือแผนที่?) ..
sateayam

@heike: ดูคำตอบที่แก้ไขของฉันซึ่งตอนนี้มีเอกสาร API ในขณะที่คุณสามารถดูReaddirพารามิเตอร์วิธีคือ ถ้า, ผลตอบแทนที่ได้ทั้งหมดจากไดเรกทอรีในชิ้นเดียว nintn <= 0ReaddirFileInfo
peterSO

@RickSmith: os func (FileMode) IsRegularแพคเกจดู
peterSO

1
อย่าจู้จี้จุกจิก แต่การปิดการเลื่อนเวลาของคุณควรเกิดขึ้นก่อนการตรวจสอบข้อผิดพลาด
Zanven

13

นี่คือตัวอย่างของการวนซ้ำไฟล์และไดเรกทอรีทั้งหมดแบบวนซ้ำ โปรดทราบว่าหากคุณต้องการทราบว่าเส้นทางที่คุณต่อท้ายเป็นไดเร็กทอรีหรือไม่ให้เลือก "f.IsDir ()"

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    searchDir := "c:/path/to/dir"

    fileList := []string{}
    err := filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error {
        fileList = append(fileList, path)
        return nil
    })

    for _, file := range fileList {
        fmt.Println(file)
    }
}

คุณคัดลอกและวางฟังก์ชันหรือไม่ mainวิธีไม่ควรมี([]string, error)args errและคุณจำเป็นต้องทำอะไรกับ เว้นแต่ในขณะที่ตอบถูก? ข้อผิดพลาดในการคอมไพล์แน่นอนในเวอร์ชันล่าสุด มิฉะนั้นจะมีประโยชน์มากขอบคุณ
Steve


4

แพคเกจมาตรฐาน Go ioutilมีฟังก์ชันในตัวสำหรับสถานการณ์กรณีนี้ดูตัวอย่างด้านล่าง

func searchFiles(dir string) { // dir is the parent directory you what to search
    files, err := ioutil.ReadDir(dir)
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        fmt.Println(file.Name())
    }
}

1

โปรดทราบว่า "เดินไม่เป็นไปตามการเชื่อมโยงสัญลักษณ์" ดังนั้นหากคุณกำลังมองหาที่จะเขียนฟังก์ชั่นที่ไม่ว่าผมขอแนะนำให้ioutil.ReadDir ทดสอบมาตรฐานของตัวเองแสดงให้เห็นว่ามันเร็วขึ้นและมีหน่วยความจำน้อยเข้มข้นกว่าfilepath.Glob

นอกจากนี้ioutil.ReadDirกำลังจัดเรียงไฟล์ตามชื่อฐานโดยใช้การเปรียบเทียบสตริงพื้นฐาน ( strA > strB) ในฐานะคนที่แต่งตัวประหลาดฉันมักจะเรียงลำดับชื่อ dir โดยทำการเปรียบเทียบตัวเลขย้อนกลับ (เช่น build ล่าสุดก่อน) หากเป็นเช่นนั้นคุณควรเรียกos.ReadDirโดยตรง ( ioutil.ReadDirเรียกสิ่งนี้ภายใต้ฝาครอบ) และทำการเรียงลำดับด้วยตัวเอง

นี่คือตัวอย่างของReadDirส่วนที่มีการเรียงลำดับตัวเลข:

// ReadDirNumSort - Same as ioutil/ReadDir but uses returns a Numerically
// Sorted file list.
//
// Taken from https://golang.org/src/io/ioutil/ioutil.go
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Modified Sort method to use Numerically sorted names instead.
// It also allows reverse sorting.
func ReadDirNumSort(dirname string, reverse bool) ([]os.FileInfo, error) {
    f, err := os.Open(dirname)
    if err != nil {
        return nil, err
    }
    list, err := f.Readdir(-1)
    f.Close()
    if err != nil {
        return nil, err
    }
    if reverse {
        sort.Sort(sort.Reverse(byName(list)))
    } else {
        sort.Sort(byName(list))
    }
    return list, nil
}

// byName implements sort.Interface.
type byName []os.FileInfo

func (f byName) Len() int      { return len(f) }
func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f byName) Less(i, j int) bool {
    nai, err := strconv.Atoi(f[i].Name())
    if err != nil {
        return f[i].Name() < f[j].Name()
    }
    naj, err := strconv.Atoi(f[j].Name())
    if err != nil {
        return f[i].Name() < f[j].Name()
    }
    return nai < naj
}

0

คุณอาจต้องการทำหน้าที่แกงที่นี่เพื่อให้คุณสามารถใช้ประโยชน์จากการค้นหาได้อย่างเต็มที่

func visit(files *[]string) filepath.WalkFunc {
    return func (path string, info os.FileInfo, err error) error {
               // maybe do this in some if block
               *files = append(*files, path)
               return nil
           }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.