golang基于window下实现文件遍历(效率高于filepath.Wlak)
package main
import (
"fmt"
"os"
"path"
"path/filepath"
"syscall"
"time"
"unsafe"
)
const MAX_PATH = 260
type FILETIME struct {
dwLowDateTime uint32
dwHighDateTime uint32
}
type WIN32_FIND_DATAW struct {
dwFileAttributes uint32
ftCreationTime FILETIME
ftLastAccessTime FILETIME
ftLastWriteTime FILETIME
nFileSizeHigh uint32
nFileSizeLow uint32
dwReserved0 uint32
dwReserved1 uint32
cFileName [MAX_PATH]uint16
cAlternateFileName [14]uint16
dwFileType uint32
dwCreatorType uint32
wFinderFlags uint16
FileName string
}
type IndexEntry2 struct {
Name string
Path string
Size uint64
}
var (
kernel32 = syscall.NewLazyDLL("Kernel32.dll")
procFindFirstFileW = kernel32.NewProc("FindFirstFileW")
procFindNextFileW = kernel32.NewProc("FindNextFileW")
procFindClose = kernel32.NewProc("FindClose")
)
type HANDLE uintptr
const (
FILE_ATTRIBUTE_DIRECTORY = 0x10
)
func FindFirstFileW(lpFileName string, lpFindFileData *WIN32_FIND_DATAW) HANDLE {
name, _ := syscall.UTF16PtrFromString(lpFileName)
pathPtr := uintptr(unsafe.Pointer(name))
handle, _, _ := procFindFirstFileW.Call(pathPtr, uintptr(unsafe.Pointer(lpFindFileData)), 0)
return HANDLE(handle)
}
func FindNextFileW(hFindFile HANDLE, lpFindFileData *WIN32_FIND_DATAW) bool {
ret, _, _ := procFindNextFileW.Call(uintptr(hFindFile), uintptr(unsafe.Pointer(lpFindFileData)), 0)
return ret != 0
}
func FindClose(hFindFile HANDLE) bool {
ret, _, _ := procFindClose.Call(uintptr(hFindFile))
return ret != 0
}
func FindFileWin(dir string) []IndexEntry2 {
list := make([]IndexEntry2, 0)
var findData WIN32_FIND_DATAW
globalPath := dir + "\\*"
hFindFile := FindFirstFileW(globalPath, &findData)
if hFindFile != 0 {
defer FindClose(hFindFile)
for {
fileName := syscall.UTF16ToString(findData.cFileName[:])
//文件夾
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 {
if (fileName != "..") && (fileName != ".") {
subPath := path.Join(dir, fileName)
list = append(list, FindFileWin(subPath)...)
}
} else {
list = append(list, IndexEntry2{
Name: fileName,
Size: uint64(findData.nFileSizeLow) | (uint64(findData.nFileSizeHigh) << 32),
Path: path.Join(dir, fileName),
})
}
if !FindNextFileW(hFindFile, &findData) {
break // End of search
}
}
}
return list
}
func FileWalk(dir string) []IndexEntry2 {
list := make([]IndexEntry2, 0)
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
list = append(list, IndexEntry2{
Path: path,
Size: uint64(info.Size()),
Name: info.Name(),
})
return nil
})
return list
}
func main() {
startTime := time.Now()
// Replace the path with the desired directory path
dir := `E:\`
fmt.Println(len(FindFileWin(dir)))
// fmt.Println(len(FileWalk(dir)))
fmt.Printf("共花费时间 %.3f seconds\n", time.Since(startTime).Seconds())
}