1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// +build windows
package godirwalk
import (
"fmt"
"os"
)
// Scanner is an iterator to enumerate the contents of a directory.
type Scanner struct {
osDirname string
childName string
dh *os.File // dh is handle to open directory
de *Dirent
err error // err is the error associated with scanning directory
childMode os.FileMode
}
// NewScanner returns a new directory Scanner that lazily enumerates the
// contents of a single directory.
//
// scanner, err := godirwalk.NewScanner(dirname)
// if err != nil {
// fatal("cannot scan directory: %s", err)
// }
//
// for scanner.Scan() {
// dirent, err := scanner.Dirent()
// if err != nil {
// warning("cannot get dirent: %s", err)
// continue
// }
// name := dirent.Name()
// if name == "break" {
// break
// }
// if name == "continue" {
// continue
// }
// fmt.Printf("%v %v\n", dirent.ModeType(), dirent.Name())
// }
// if err := scanner.Err(); err != nil {
// fatal("cannot scan directory: %s", err)
// }
func NewScanner(osDirname string) (*Scanner, error) {
dh, err := os.Open(osDirname)
if err != nil {
return nil, err
}
scanner := &Scanner{
osDirname: osDirname,
dh: dh,
}
return scanner, nil
}
// NewScannerWithScratchBuffer returns a new directory Scanner that lazily
// enumerates the contents of a single directory. On platforms other than
// Windows it uses the provided scratch buffer to read from the file system. On
// Windows the scratch buffer parameter is ignored.
func NewScannerWithScratchBuffer(osDirname string, scratchBuffer []byte) (*Scanner, error) {
return NewScanner(osDirname)
}
// Dirent returns the current directory entry while scanning a directory.
func (s *Scanner) Dirent() (*Dirent, error) {
if s.de == nil {
s.de = &Dirent{
name: s.childName,
path: s.osDirname,
modeType: s.childMode,
}
}
return s.de, nil
}
// done is called when directory scanner unable to continue, with either the
// triggering error, or nil when there are simply no more entries to read from
// the directory.
func (s *Scanner) done(err error) {
if s.dh == nil {
return
}
if cerr := s.dh.Close(); err == nil {
s.err = cerr
}
s.childName, s.osDirname = "", ""
s.de, s.dh = nil, nil
}
// Err returns any error associated with scanning a directory. It is normal to
// call Err after Scan returns false, even though they both ensure Scanner
// resources are released. Do not call until done scanning a directory.
func (s *Scanner) Err() error {
s.done(nil)
return s.err
}
// Name returns the base name of the current directory entry while scanning a
// directory.
func (s *Scanner) Name() string { return s.childName }
// Scan potentially reads and then decodes the next directory entry from the
// file system.
//
// When it returns false, this releases resources used by the Scanner then
// returns any error associated with closing the file system directory resource.
func (s *Scanner) Scan() bool {
if s.dh == nil {
return false
}
s.de = nil
fileinfos, err := s.dh.Readdir(1)
if err != nil {
s.done(err)
return false
}
if l := len(fileinfos); l != 1 {
s.done(fmt.Errorf("expected a single entry rather than %d", l))
return false
}
fi := fileinfos[0]
s.childMode = fi.Mode() & os.ModeType
s.childName = fi.Name()
return true
}
|