Cách thực hiện quét hệ thống tệp


104
  1. Tôi cần viết một hàm mà khi được cung cấp đường dẫn của một thư mục sẽ quét các tệp bắt nguồn từ thư mục đó.
  2. Và sau đó tôi cần hiển thị cấu trúc thư mục tại thư mục đó.

Tôi biết cách làm 2 (Tôi sẽ sử dụng jstree để hiển thị nó trong trình duyệt).


2
bạn có cần nó để đi qua cây thư mục một cách đệ quy không?
newacct

Câu trả lời:


194

CHỈNH SỬA : Có đủ người vẫn nhấn câu trả lời này, rằng tôi nghĩ rằng tôi sẽ cập nhật nó cho API Go1. Đây là một ví dụ hoạt động của filepath.Walk () . Bản gốc ở bên dưới.

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)
}

Xin lưu ý rằng filepath.Walk đi qua đệ quy cây thư mục.

Đây là một ví dụ chạy:

$ 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>

CÂU TRẢ LỜI GỐC SAU ĐÂY: Giao diện cho đường dẫn tệp đi bộ đã thay đổi kể từ hàng tuần. 2011-09-16, hãy xem http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 . Đoạn mã dưới đây sẽ không hoạt động cho các phiên bản phát hành của GO trong tương lai gần.

Thực ra có một chức năng trong lib tiêu chuẩn chỉ dành cho điều này: 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.Walknhân tiện không tuân theo các liên kết tượng trưng.
0xcaff

3
Gọi filepath.Walklại @FacescoPasa sẽ được kích hoạt trên các liên kết tượng trưng (cả tệp và thư mục). Có, nó sẽ không theo dõi chúng, nhưng lệnh gọi lại nhận ra một liên kết tượng trưng và thực hiện thêm hành động tức là một tiếp theo filepath.Walkđảm bảo trước tiên rằng đường dẫn chưa được truy cập.
colm.anseo

15

Đây là một cách để lấy thông tin tệp cho các tệp trong một thư mục.

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) có nghĩa là gì? vì Readdir chỉ chấp nhận loại chuỗi và dựa trên tài liệu API, một chuỗi chỉ có thể không phải là NUL và không có giới hạn nào khác .. và kiểu trả về của "fi" trong Readdir làm sao nó có thể được duyệt qua (có phải là bản đồ không?) ..
sateayam

@heike: Xem câu trả lời đã sửa đổi của tôi, hiện đã bao gồm tài liệu API. Như bạn có thể thấy, Readdirtham số phương thức là nmột int. Nếu n <= 0, Readdirtrả về tất cả FileInfotừ thư mục trong một lát.
peterSO

@RickSmith: Xem gói os func (FileMode) IsRegular.
peterSO

1
không được kén chọn nhưng việc đóng hoãn của bạn nên xảy ra trước khi kiểm tra lỗi.
Zanven

13

Đây là một ví dụ để lặp qua tất cả các tệp và thư mục một cách đệ quy. Lưu ý rằng nếu bạn muốn biết liệu đường dẫn bạn đang thêm vào có phải là một thư mục hay không, chỉ cần kiểm tra "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)
    }
}

Bạn đã sao chép và dán một chức năng? Các mainphương pháp không nên có ([]string, error)args và bạn cần phải làm điều gì đó với err. Trừ khi tại thời điểm trả lời nó đã hợp lệ? Chắc chắn là lỗi biên dịch trong các phiên bản gần đây hơn. Nếu không, rất hữu ích, cảm ơn bạn.
Steve


4

Gói tiêu chuẩn Go ioutilđã được tích hợp sẵn chức năng cho trường hợp này, xem ví dụ bên dưới

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

Lưu ý rằng "Walk không tuân theo các liên kết tượng trưng" vì vậy nếu bạn đang tìm cách viết một hàm làm được điều đó, tôi khuyên bạn nên sử dụng ioutil.ReadDir . Kiểm tra điểm chuẩn của riêng tôi cho thấy rằng nó nhanh hơn và ít tốn bộ nhớ hơn filepath.Glob .

Ngoài ra, ioutil.ReadDirsắp xếp các tệp theo tên cơ sở bằng cách sử dụng so sánh chuỗi cơ bản ( strA > strB). Với tư cách là một nhà phát triển, tôi thường sắp xếp các tên dir bằng cách so sánh số ngược (ví dụ: bản dựng mới nhất trước). Nếu đó cũng là trường hợp của bạn thì tốt hơn là bạn nên gọi trực tiếp os.ReadDir ( ioutil.ReadDirđang gọi điều này dưới vỏ bọc) và tự mình phân loại.

Đây là một ví dụ về ReadDirphần có sắp xếp theo kiểu số:

// 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

Bạn có thể muốn thực hiện chức năng cà ri ở đây, để bạn có thể sử dụng đầy đủ tìm kiếm

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
           }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.