Reputation: 1355
I would like my program to iterate through all drives on a Windows system and search for a particular file type. Right now, I can run the program and pass it a drive letter to start from, but I want it to search on all drives automatically. Currently, I would need to do something like this:
C:\> program.exe C:
C:\> program.exe D:
C:\> program.exe E:
I want the program to get a list of all drives and iterate through all of them without the user having to specify the drive letter. Is this possible using Go?
Similar to this question Listing All Physical Drives (Windows) but using Go instead of C.
Upvotes: 10
Views: 12352
Reputation: 1
You can use the windows
package:
package main
import (
"golang.org/x/sys/windows"
"strings"
"unicode/utf16"
)
func drives() ([]string, error) {
n, e := windows.GetLogicalDriveStrings(0, nil)
if e != nil { return nil, e }
a := make([]uint16, n)
windows.GetLogicalDriveStrings(n, &a[0])
s := string(utf16.Decode(a))
return strings.Split(strings.TrimRight(s, "\x00"), "\x00"), nil
}
func main() {
a, e := drives()
if e != nil {
panic(e)
}
for _, s := range a {
println(s)
}
}
https://pkg.go.dev/golang.org/x/sys/windows#GetLogicalDriveStrings
Upvotes: 4
Reputation: 57639
You can call the function GetLogicalDrives
and match the letters according to the bit map.
Something like:
package main
import (
"fmt"
"syscall"
)
func main() {
kernel32, _ := syscall.LoadLibrary("kernel32.dll")
getLogicalDrivesHandle, _ := syscall.GetProcAddress(kernel32, "GetLogicalDrives")
var drives []string
if ret, _, callErr := syscall.Syscall(uintptr(getLogicalDrivesHandle), 0, 0, 0, 0); callErr != 0 {
// handle error
} else {
drives = bitsToDrives(uint32(ret))
}
fmt.Printf("%v", drives)
}
func bitsToDrives(bitMap uint32) (drives []string) {
availableDrives := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
for i := range availableDrives {
if bitMap & 1 == 1 {
drives = append(drives, availableDrives[i])
}
bitMap >>= 1
}
return
}
Upvotes: 14
Reputation: 438
You can use the gopsutil lib:
package main
import (
"fmt"
"github.com/shirou/gopsutil/disk"
)
func main() {
partitions, _ := disk.Partitions(false)
for _, partition := range partitions {
fmt.Println(partition.Mountpoint)
}
}
Upvotes: 10
Reputation: 462
The easist way is write own function with try to open "drive" folder mentioned by Volker.
import "os"
func getdrives() (r []string){
for _, drive := range "ABCDEFGHIJKLMNOPQRSTUVWXYZ"{
f, err := os.Open(string(drive)+":\\")
if err == nil {
r = append(r, string(drive))
f.Close()
}
}
return
}
Upvotes: 6
Reputation: 53
Or you can call GetLogicalDriveStrings directly:
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
kernel32, err := syscall.LoadDLL("kernel32.dll")
getLogicalDriveStringsHandle, err := kernel32.FindProc("GetLogicalDriveStringsA")
buffer := [1024]byte{}
bufferSize := uint32(len(buffer))
drives := []string{}
hr, _, _ := getLogicalDriveStringsHandle.Call(uintptr(unsafe.Pointer(&bufferSize)), uintptr(unsafe.Pointer(&buffer)))
if hr == 0 {
fmt.Print("There was an error")
} else {
// Deal with the buffer, you need to split it
}
}
Upvotes: 5