파일 시스템 스캔을 수행하는 방법


104
  1. 폴더 경로가 주어지면 해당 폴더에있는 파일을 검색하는 함수를 작성해야합니다.
  2. 그런 다음 해당 폴더의 디렉토리 구조를 표시해야합니다.

2하는 방법을 알고 있습니다 (jstree를 사용하여 브라우저에 표시 할 것입니다).


2
디렉토리 트리를 재귀 적으로 통과하는 데 필요합니까?
newacct

답변:


194

편집 : 충분한 사람들이 여전히이 답변을 쳤으므로 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>

원래 답변 : 걷기 파일 경로의 인터페이스가 매주 변경되었습니다 . 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그런데 심볼릭 링크를 따르지 않습니다.
0xcaff

3
@FrancescoPasa filepath.Walk콜백은 심볼릭 링크 (파일과 디렉토리 모두)에서 트리거됩니다. 예 , 그것들을 따르지 않을 것이지만 콜백은 심볼릭 링크를 인식하고 추가 조치를 취 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 일 수 없으며 다른 제한은 없습니다. (지도입니까?) ..
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)인수를 당신이 뭔가를 할 필요가 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

"Walk는 심볼릭 링크를 따르지 않습니다."라는 점에 유의하십시오. 그렇게하는 함수를 작성하려는 경우 ioutil.ReadDir을 권장 합니다 . 내 벤치 마크 테스트에 따르면 파일 경로 보다 빠르고 메모리 사용량이 적습니다. .

또한 ioutil.ReadDir기본 문자열 비교 ( strA > strB)를 사용하여 기본 이름별로 파일을 정렬합니다 . devops 녀석으로서 저는 일반적으로 역 수치 비교를 수행하여 dir 이름을 정렬합니다 (예 : 최신 빌드 먼저). 그것이 또한 당신의 경우라면 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.