A:增加工具函数;增加部分测试照片

This commit is contained in:
jimmy committed 2025-06-17 15:15:18 +08:00
1 parent 150d398db6
commit ae8f64d53b
23 files changed
+1850

No files matched your search

+1
View File
@@ -0,0 +1 @@
/frame/
Binary file not shown.

After

Width:  |  Height:  |  Size: 602 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

+497
View File
@@ -0,0 +1,497 @@
package utils
import (
"bufio"
"crypto/md5"
"crypto/sha256"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
)
// FileInfo 文件信息结构体
type FileInfo struct {
Name string `json:"name"`
Path string `json:"path"`
Size int64 `json:"size"`
ModTime time.Time `json:"mod_time"`
IsDir bool `json:"is_dir"`
Ext string `json:"ext"`
}
// 1. 检查文件或目录是否存在
func Exists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// 2. 检查是否为目录
func IsDir(path string) bool {
info, err := os.Stat(path)
if err != nil {
return false
}
return info.IsDir()
}
// 3. 检查是否为文件
func IsFile(path string) bool {
info, err := os.Stat(path)
if err != nil {
return false
}
return !info.IsDir()
}
// 4. 获取指定目录下的所有文件夹
func GetDirectories(dirPath string) ([]string, error) {
var dirs []string
entries, err := os.ReadDir(dirPath)
if err != nil {
return nil, fmt.Errorf("读取目录失败: %w", err)
}
for _, entry := range entries {
if entry.IsDir() {
dirs = append(dirs, entry.Name())
}
}
return dirs, nil
}
// 5. 获取指定目录下指定格式的文件
func GetFilesByExtension(dirPath string, extensions ...string) ([]string, error) {
var files []string
// 标准化扩展名(确保以.开头)
for i, ext := range extensions {
if !strings.HasPrefix(ext, ".") {
extensions[i] = "." + ext
}
extensions[i] = strings.ToLower(extensions[i])
}
entries, err := os.ReadDir(dirPath)
if err != nil {
return nil, fmt.Errorf("读取目录失败: %w", err)
}
for _, entry := range entries {
if !entry.IsDir() {
fileExt := strings.ToLower(filepath.Ext(entry.Name()))
for _, ext := range extensions {
if fileExt == ext {
files = append(files, entry.Name())
break
}
}
}
}
return files, nil
}
// 6. 找到指定目录下第一个符合格式的文件
func GetFirstFileByExtension(dirPath string, extensions ...string) (string, error) {
files, err := GetFilesByExtension(dirPath, extensions...)
if err != nil {
return "", err
}
if len(files) == 0 {
return "", fmt.Errorf("未找到符合扩展名的文件")
}
return files[0], nil
}
// 7. 递归获取目录下所有文件
func GetAllFiles(dirPath string, recursive bool) ([]FileInfo, error) {
var files []FileInfo
if recursive {
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
files = append(files, FileInfo{
Name: info.Name(),
Path: path,
Size: info.Size(),
ModTime: info.ModTime(),
IsDir: false,
Ext: filepath.Ext(info.Name()),
})
}
return nil
})
return files, err
} else {
entries, err := os.ReadDir(dirPath)
if err != nil {
return nil, fmt.Errorf("读取目录失败: %w", err)
}
for _, entry := range entries {
if !entry.IsDir() {
info, err := entry.Info()
if err != nil {
continue
}
files = append(files, FileInfo{
Name: info.Name(),
Path: filepath.Join(dirPath, info.Name()),
Size: info.Size(),
ModTime: info.ModTime(),
IsDir: false,
Ext: filepath.Ext(info.Name()),
})
}
}
return files, nil
}
}
// 递归获取目录下所有文件夹
func GetAllDirs(dirPath string, recursive bool) ([]FileInfo, error) {
var dirs []FileInfo
if recursive {
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 只收集目录,排除根目录本身
if info.IsDir() && path != dirPath {
dirs = append(dirs, FileInfo{
Name: info.Name(),
Path: path,
Size: 0, // 目录大小通常为0或不适用
ModTime: info.ModTime(),
IsDir: true,
Ext: "", // 目录没有扩展名
})
}
return nil
})
return dirs, err
} else {
entries, err := os.ReadDir(dirPath)
if err != nil {
return nil, fmt.Errorf("读取目录失败: %w", err)
}
for _, entry := range entries {
if entry.IsDir() {
info, err := entry.Info()
if err != nil {
continue
}
dirs = append(dirs, FileInfo{
Name: info.Name(),
Path: filepath.Join(dirPath, info.Name()),
Size: 0, // 目录大小通常为0或不适用
ModTime: info.ModTime(),
IsDir: true,
Ext: "", // 目录没有扩展名
})
}
}
return dirs, nil
}
}
// 8. 删除文件或目录
func Delete(path string) error {
if !Exists(path) {
return fmt.Errorf("路径不存在: %s", path)
}
return os.RemoveAll(path)
}
// 9. 创建目录(递归创建)
func CreateDir(dirPath string) error {
return os.MkdirAll(dirPath, 0755)
}
// 10. 复制文件
func CopyFile(src, dst string) error {
sourceFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("打开源文件失败: %w", err)
}
defer sourceFile.Close()
// 确保目标目录存在
dstDir := filepath.Dir(dst)
if err := CreateDir(dstDir); err != nil {
return fmt.Errorf("创建目标目录失败: %w", err)
}
destFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("创建目标文件失败: %w", err)
}
defer destFile.Close()
_, err = io.Copy(destFile, sourceFile)
if err != nil {
return fmt.Errorf("复制文件失败: %w", err)
}
return nil
}
// 11. 移动/重命名文件
func MoveFile(src, dst string) error {
// 确保目标目录存在
dstDir := filepath.Dir(dst)
if err := CreateDir(dstDir); err != nil {
return fmt.Errorf("创建目标目录失败: %w", err)
}
return os.Rename(src, dst)
}
// 12. 读取文件全部内容
func ReadFile(filePath string) (string, error) {
content, err := os.ReadFile(filePath)
if err != nil {
return "", fmt.Errorf("读取文件失败: %w", err)
}
return string(content), nil
}
// 13. 按行读取文件
func ReadFileLines(filePath string) ([]string, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, fmt.Errorf("打开文件失败: %w", err)
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("读取文件失败: %w", err)
}
return lines, nil
}
// 14. 写入文件内容
func WriteFile(filePath, content string) error {
// 确保目录存在
dir := filepath.Dir(filePath)
if err := CreateDir(dir); err != nil {
return fmt.Errorf("创建目录失败: %w", err)
}
return os.WriteFile(filePath, []byte(content), 0644)
}
// 15. 追加写入文件
func AppendFile(filePath, content string) error {
// 确保目录存在
dir := filepath.Dir(filePath)
if err := CreateDir(dir); err != nil {
return fmt.Errorf("创建目录失败: %w", err)
}
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("打开文件失败: %w", err)
}
defer file.Close()
_, err = file.WriteString(content)
return err
}
// 16. 获取文件大小
func GetFileSize(filePath string) (int64, error) {
info, err := os.Stat(filePath)
if err != nil {
return 0, fmt.Errorf("获取文件信息失败: %w", err)
}
return info.Size(), nil
}
// 17. 获取文件修改时间
func GetModTime(filePath string) (time.Time, error) {
info, err := os.Stat(filePath)
if err != nil {
return time.Time{}, fmt.Errorf("获取文件信息失败: %w", err)
}
return info.ModTime(), nil
}
// 18. 获取文件扩展名
func GetExtension(filePath string) string {
return filepath.Ext(filePath)
}
// 19. 获取文件名(不含扩展名)
func GetFileName(filePath string) string {
base := filepath.Base(filePath)
ext := filepath.Ext(base)
return strings.TrimSuffix(base, ext)
}
// 20. 获取文件基本名称(含扩展名)
func GetBaseName(filePath string) string {
return filepath.Base(filePath)
}
// 21. 获取文件目录
func GetDir(filePath string) string {
return filepath.Dir(filePath)
}
// 22. 计算文件MD5哈希值
func GetFileMD5(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", fmt.Errorf("打开文件失败: %w", err)
}
defer file.Close()
hash := md5.New()
if _, err := io.Copy(hash, file); err != nil {
return "", fmt.Errorf("计算哈希失败: %w", err)
}
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}
// 23. 计算文件SHA256哈希值
func GetFileSHA256(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", fmt.Errorf("打开文件失败: %w", err)
}
defer file.Close()
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
return "", fmt.Errorf("计算哈希失败: %w", err)
}
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}
// 24. 清空目录内容(保留目录本身)
func CleanDir(dirPath string) error {
entries, err := os.ReadDir(dirPath)
if err != nil {
return fmt.Errorf("读取目录失败: %w", err)
}
for _, entry := range entries {
path := filepath.Join(dirPath, entry.Name())
if err := os.RemoveAll(path); err != nil {
return fmt.Errorf("删除 %s 失败: %w", path, err)
}
}
return nil
}
// 25. 获取目录大小
func GetDirSize(dirPath string) (int64, error) {
var size int64
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
size += info.Size()
}
return nil
})
return size, err
}
// 26. 格式化文件大小
func FormatFileSize(bytes int64) string {
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%d B", bytes)
}
div, exp := int64(unit), 0
for n := bytes / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}
// 27. 搜索文件(按文件名模式)
func SearchFiles(dirPath, pattern string, recursive bool) ([]string, error) {
var matches []string
if recursive {
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
matched, err := filepath.Match(pattern, info.Name())
if err != nil {
return err
}
if matched {
matches = append(matches, path)
}
}
return nil
})
return matches, err
} else {
entries, err := os.ReadDir(dirPath)
if err != nil {
return nil, fmt.Errorf("读取目录失败: %w", err)
}
for _, entry := range entries {
if !entry.IsDir() {
matched, err := filepath.Match(pattern, entry.Name())
if err != nil {
return nil, err
}
if matched {
matches = append(matches, filepath.Join(dirPath, entry.Name()))
}
}
}
return matches, nil
}
}
// 28. 获取当前工作目录
func GetCurrentDir() (string, error) {
return os.Getwd()
}
// 29. 改变工作目录
func ChangeDir(dirPath string) error {
return os.Chdir(dirPath)
}
+349
View File
@@ -0,0 +1,349 @@
package utils
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"fmt"
"hash"
"io"
"os"
"runtime"
"strings"
"sync"
)
// HashType 定义支持的Hash算法类型
type HashType int
const (
MD5 HashType = iota
SHA1
SHA256
SHA512
)
// 缓冲区大小配置
const (
SmallFileThreshold = 1024 * 1024 // 1MB,小文件阈值
DefaultBufferSize = 64 * 1024 // 64KB,默认缓冲区
LargeBufferSize = 1024 * 1024 // 1MB,大文件缓冲区
)
// HashResult 存储Hash计算结果
type HashResult struct {
Filename string
Hash string
Error error
Size int64
}
// getHasher 根据类型返回对应的Hash实例
func getHasher(hashType HashType) hash.Hash {
switch hashType {
case MD5:
return md5.New()
case SHA1:
return sha1.New()
case SHA256:
return sha256.New()
case SHA512:
return sha512.New()
default:
return sha256.New()
}
}
// getHasherName 获取Hash算法名称
func getHasherName(hashType HashType) string {
switch hashType {
case MD5:
return "MD5"
case SHA1:
return "SHA1"
case SHA256:
return "SHA256"
case SHA512:
return "SHA512"
default:
return "SHA256"
}
}
// HashString 计算字符串的Hash值
func HashString(data string, hashType HashType) string {
hasher := getHasher(hashType)
hasher.Write([]byte(data))
return fmt.Sprintf("%x", hasher.Sum(nil))
}
// HashBytes 计算字节数组的Hash值
func HashBytes(data []byte, hashType HashType) string {
hasher := getHasher(hashType)
hasher.Write(data)
return fmt.Sprintf("%x", hasher.Sum(nil))
}
// HashFile 计算单个文件的Hash值(自动选择优化策略)
func HashFile(filename string, hashType HashType) (string, error) {
file, err := os.Open(filename)
if err != nil {
return "", err
}
defer file.Close()
// 获取文件信息
fileInfo, err := file.Stat()
if err != nil {
return "", err
}
hasher := getHasher(hashType)
// 根据文件大小选择不同的处理策略
if fileInfo.Size() <= SmallFileThreshold {
// 小文件:直接读取
return hashSmallFile(file, hasher)
} else {
// 大文件:使用缓冲区
return hashLargeFile(file, hasher, fileInfo.Size())
}
}
// hashSmallFile 处理小文件
func hashSmallFile(file *os.File, hasher hash.Hash) (string, error) {
_, err := io.Copy(hasher, file)
if err != nil {
return "", err
}
return fmt.Sprintf("%x", hasher.Sum(nil)), nil
}
// hashLargeFile 处理大文件
func hashLargeFile(file *os.File, hasher hash.Hash, fileSize int64) (string, error) {
// 根据文件大小动态调整缓冲区
bufferSize := DefaultBufferSize
if fileSize > 100*1024*1024 { // 大于100MB使用更大缓冲区
bufferSize = LargeBufferSize
}
buffer := make([]byte, bufferSize)
for {
n, err := file.Read(buffer)
if n > 0 {
hasher.Write(buffer[:n])
}
if err == io.EOF {
break
}
if err != nil {
return "", err
}
}
return fmt.Sprintf("%x", hasher.Sum(nil)), nil
}
// HashFileWithProgress 计算文件Hash值并提供进度回调
func HashFileWithProgress(filename string, hashType HashType, progressCallback func(processed, total int64)) (string, error) {
file, err := os.Open(filename)
if err != nil {
return "", err
}
defer file.Close()
fileInfo, err := file.Stat()
if err != nil {
return "", err
}
hasher := getHasher(hashType)
buffer := make([]byte, DefaultBufferSize)
var processed int64
for {
n, err := file.Read(buffer)
if n > 0 {
hasher.Write(buffer[:n])
processed += int64(n)
if progressCallback != nil {
progressCallback(processed, fileInfo.Size())
}
}
if err == io.EOF {
break
}
if err != nil {
return "", err
}
}
return fmt.Sprintf("%x", hasher.Sum(nil)), nil
}
// HashMultipleFiles 并发计算多个文件的Hash值
func HashMultipleFiles(filenames []string, hashType HashType) []HashResult {
// 使用CPU核心数作为并发数
numWorkers := runtime.NumCPU()
jobs := make(chan string, len(filenames))
results := make(chan HashResult, len(filenames))
// 启动工作协程
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for filename := range jobs {
hash, err := HashFile(filename, hashType)
var size int64
if err == nil {
if fileInfo, statErr := os.Stat(filename); statErr == nil {
size = fileInfo.Size()
}
}
results <- HashResult{
Filename: filename,
Hash: hash,
Error: err,
Size: size,
}
}
}()
}
// 发送任务
go func() {
for _, filename := range filenames {
jobs <- filename
}
close(jobs)
}()
// 等待所有工作完成
go func() {
wg.Wait()
close(results)
}()
// 收集结果
var hashResults []HashResult
for result := range results {
hashResults = append(hashResults, result)
}
return hashResults
}
// CompareFiles 比较两个文件是否相同(通过Hash值)
func CompareFiles(file1, file2 string, hashType HashType) (bool, error) {
hash1, err := HashFile(file1, hashType)
if err != nil {
return false, err
}
hash2, err := HashFile(file2, hashType)
if err != nil {
return false, err
}
return hash1 == hash2, nil
}
// FindDuplicates 在文件列表中查找重复文件
func FindDuplicates(filenames []string, hashType HashType) map[string][]string {
results := HashMultipleFiles(filenames, hashType)
duplicates := make(map[string][]string)
for _, result := range results {
if result.Error == nil {
duplicates[result.Hash] = append(duplicates[result.Hash], result.Filename)
}
}
// 只保留有重复的Hash
for hash, files := range duplicates {
if len(files) <= 1 {
delete(duplicates, hash)
}
}
return duplicates
}
// VerifyFileIntegrity 验证文件完整性
func VerifyFileIntegrity(filename, expectedHash string, hashType HashType) (bool, error) {
actualHash, err := HashFile(filename, hashType)
if err != nil {
return false, err
}
// 不区分大小写比较
return strings.EqualFold(actualHash, expectedHash), nil
}
// HashFileMultipleAlgorithms 使用多种算法计算文件Hash
func HashFileMultipleAlgorithms(filename string, hashTypes []HashType) (map[string]string, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
// 创建多个hasher
hashers := make(map[HashType]hash.Hash)
for _, hashType := range hashTypes {
hashers[hashType] = getHasher(hashType)
}
// 创建MultiWriter
var writers []io.Writer
for _, hasher := range hashers {
writers = append(writers, hasher)
}
multiWriter := io.MultiWriter(writers...)
// 一次读取,多重计算
_, err = io.Copy(multiWriter, file)
if err != nil {
return nil, err
}
// 收集结果
results := make(map[string]string)
for hashType, hasher := range hashers {
hashName := getHasherName(hashType)
results[hashName] = fmt.Sprintf("%x", hasher.Sum(nil))
}
return results, nil
}
// 便捷函数
func MD5File(filename string) (string, error) {
return HashFile(filename, MD5)
}
func SHA1File(filename string) (string, error) {
return HashFile(filename, SHA1)
}
func SHA256File(filename string) (string, error) {
return HashFile(filename, SHA256)
}
func SHA512File(filename string) (string, error) {
return HashFile(filename, SHA512)
}
func MD5String(data string) string {
return HashString(data, MD5)
}
func SHA256String(data string) string {
return HashString(data, SHA256)
}
+164
View File
@@ -0,0 +1,164 @@
package utils
import (
"fmt"
"log"
"time"
)
func main() {
// 1. 计算字符串Hash
fmt.Println("=== 字符串Hash ===")
text := "Hello, World!"
fmt.Printf("MD5: %s\n", MD5String(text))
fmt.Printf("SHA256: %s\n", SHA256String(text))
// 2. 计算单个文件Hash
fmt.Println("\n=== 单个文件Hash ===")
filename := "example.txt"
if hash, err := SHA256File(filename); err != nil {
log.Printf("计算文件Hash失败: %v", err)
} else {
fmt.Printf("文件 %s 的 SHA256: %s\n", filename, hash)
}
// 3. 带进度的文件Hash计算
fmt.Println("\n=== 带进度的Hash计算 ===")
progressCallback := func(processed, total int64) {
percentage := float64(processed) / float64(total) * 100
fmt.Printf("\r进度: %.2f%% (%d/%d bytes)", percentage, processed, total)
}
if hash, err := HashFileWithProgress(filename, SHA256, progressCallback); err != nil {
log.Printf("计算失败: %v", err)
} else {
fmt.Printf("\n最终Hash: %s\n", hash)
}
// 4. 并发计算多个文件
fmt.Println("\n=== 并发计算多个文件 ===")
files := []string{"file1.txt", "file2.txt", "file3.txt"}
results := HashMultipleFiles(files, SHA256)
for _, result := range results {
if result.Error != nil {
fmt.Printf("文件 %s 计算失败: %v\n", result.Filename, result.Error)
} else {
fmt.Printf("文件 %s (%.2f KB): %s\n",
result.Filename,
float64(result.Size)/1024,
result.Hash)
}
}
// 5. 计算目录下所有文件
// fmt.Println("\n=== 目录Hash计算 ===")
// dirResults, err := HashDirectory("./testdir", SHA256, true)
// if err != nil {
// log.Printf("计算目录Hash失败: %v", err)
// } else {
// for _, result := range dirResults {
// if result.Error == nil {
// fmt.Printf("%s: %s\n", result.Filename, result.Hash)
// }
// }
// }
// 6. 查找重复文件
fmt.Println("\n=== 查找重复文件 ===")
allFiles := []string{"file1.txt", "file2.txt", "file3.txt", "file1_copy.txt"}
duplicates := FindDuplicates(allFiles, SHA256)
for hash, files := range duplicates {
fmt.Printf("Hash %s 的重复文件:\n", hash[:16]+"...")
for _, file := range files {
fmt.Printf(" - %s\n", file)
}
}
// 7. 比较两个文件
fmt.Println("\n=== 文件比较 ===")
if same, err := CompareFiles("file1.txt", "file2.txt", SHA256); err != nil {
log.Printf("文件比较失败: %v", err)
} else {
if same {
fmt.Println("两个文件内容相同")
} else {
fmt.Println("两个文件内容不同")
}
}
// 8. 验证文件完整性
fmt.Println("\n=== 文件完整性验证 ===")
expectedHash := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" // 空文件的SHA256
if valid, err := VerifyFileIntegrity("empty.txt", expectedHash, SHA256); err != nil {
log.Printf("验证失败: %v", err)
} else {
if valid {
fmt.Println("文件完整性验证通过")
} else {
fmt.Println("文件完整性验证失败")
}
}
// 9. 多算法同时计算
fmt.Println("\n=== 多算法Hash计算 ===")
hashTypes := []HashType{
MD5,
SHA1,
SHA256,
SHA512,
}
multiHashes, err := HashFileMultipleAlgorithms(filename, hashTypes)
if err != nil {
log.Printf("多算法计算失败: %v", err)
} else {
for algorithm, hash := range multiHashes {
fmt.Printf("%s: %s\n", algorithm, hash)
}
}
// 10. 获取文件详细信息
// fmt.Println("\n=== 文件详细信息 ===")
// if fileInfo, err := GetFileInfo(filename, SHA256); err != nil {
// log.Printf("获取文件信息失败: %v", err)
// } else {
// fmt.Printf("文件名: %s\n", fileInfo.Name)
// fmt.Printf("路径: %s\n", fileInfo.Path)
// fmt.Printf("大小: %d bytes\n", fileInfo.Size)
// fmt.Printf("Hash类型: %s\n", fileInfo.HashType)
// fmt.Printf("Hash值: %s\n", fileInfo.Hash)
// }
// 11. 性能测试示例
fmt.Println("\n=== 性能测试 ===")
start := time.Now()
_, err = SHA256File("largefile.txt")
if err != nil {
log.Printf("大文件Hash计算失败: %v", err)
} else {
duration := time.Since(start)
fmt.Printf("大文件Hash计算耗时: %v\n", duration)
}
}
// 创建测试文件的辅助函数
func createTestFiles() {
// 这个函数可以用来创建一些测试文件
testData := []struct {
filename string
content string
}{
{"file1.txt", "Hello World"},
{"file2.txt", "Go Programming"},
{"file3.txt", "Hash Utils Test"},
{"file1_copy.txt", "Hello World"}, // 与file1.txt内容相同
{"empty.txt", ""},
}
for _, test := range testData {
// 创建文件的代码...
fmt.Printf("需要创建测试文件: %s\n", test.filename)
}
}
+194
View File
@@ -0,0 +1,194 @@
package utils
import (
"fmt"
"os"
"runtime"
"time"
)
// SystemInfo 系统信息结构体
type SystemInfo struct {
OS string `json:"os"`
Arch string `json:"arch"`
CPUCount int `json:"cpu_count"`
Is64Bit bool `json:"is_64_bit"`
Hostname string `json:"hostname"`
Username string `json:"username"`
GoVersion string `json:"go_version"`
Compiler string `json:"compiler"`
NumGoroutine int `json:"num_goroutine"`
}
// CPUInfo CPU信息结构体
type CPUInfo struct {
ModelName string `json:"model_name"`
Cores int `json:"cores"`
Threads int `json:"threads"`
Frequency string `json:"frequency"`
Usage float64 `json:"usage"`
}
// MemoryInfo 内存信息结构体
type MemoryInfo struct {
Total uint64 `json:"total"`
Available uint64 `json:"available"`
Used uint64 `json:"used"`
UsedPct float64 `json:"used_percent"`
}
// DiskInfo 磁盘信息结构体
type DiskInfo struct {
Path string `json:"path"` // 磁盘路径
Total uint64 `json:"total"` // 总空间 (字节)
Free uint64 `json:"free"` // 可用空间 (字节)
Used uint64 `json:"used"` // 已使用空间 (字节)
UsedPct float64 `json:"used_percent"` // 使用百分比
FileSystem string `json:"file_system"` // 文件系统类型
}
// NetworkInfo 网络信息结构体
type NetworkInfo struct {
InterfaceName string `json:"interface_name"`
IPAddress string `json:"ip_address"`
MACAddress string `json:"mac_address"`
MTU int `json:"mtu"`
}
// ProcessInfo 进程信息结构体
type ProcessInfo struct {
PID int `json:"pid"`
PPID int `json:"ppid"`
Name string `json:"name"`
CPUPercent float64 `json:"cpu_percent"`
MemoryUsage uint64 `json:"memory_usage"`
}
// SysUtils 系统工具类
type SysUtils struct{}
// NewSysUtils 创建新的系统工具实例
func NewSysUtils() *SysUtils {
return &SysUtils{}
}
// GetSystemInfo 获取基本系统信息
func (s *SysUtils) GetSystemInfo() SystemInfo {
hostname, _ := os.Hostname()
username := os.Getenv("USER")
if username == "" {
username = os.Getenv("USERNAME") // Windows
}
return SystemInfo{
OS: runtime.GOOS,
Arch: runtime.GOARCH,
CPUCount: runtime.NumCPU(),
Is64Bit: s.Is64Bit(),
Hostname: hostname,
Username: username,
GoVersion: runtime.Version(),
Compiler: runtime.Compiler,
NumGoroutine: runtime.NumGoroutine(),
}
}
// GetCurrentProcessInfo 获取当前进程信息
func (s *SysUtils) GetCurrentProcessInfo() ProcessInfo {
pid := os.Getpid()
ppid := os.Getppid()
var m runtime.MemStats
runtime.ReadMemStats(&m)
return ProcessInfo{
PID: pid,
PPID: ppid,
Name: os.Args[0],
MemoryUsage: m.Alloc,
}
}
// GetSystemUptime 获取系统启动时间
func (s *SysUtils) GetSystemUptime() time.Duration {
return s.getSystemUptime()
}
// FormatBytes 格式化字节数为人类可读格式
func (s *SysUtils) FormatBytes(bytes uint64) string {
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%d B", bytes)
}
div, exp := uint64(unit), 0
for n := bytes / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}
// PrintSystemInfo 打印完整的系统信息
func (s *SysUtils) PrintSystemInfo() {
fmt.Println("========== 系统信息 ==========")
sysInfo := s.GetSystemInfo()
fmt.Printf("操作系统: %s\n", sysInfo.OS)
fmt.Printf("架构: %s\n", sysInfo.Arch)
fmt.Printf("CPU核心数: %d\n", sysInfo.CPUCount)
fmt.Printf("64位系统: %v\n", sysInfo.Is64Bit)
fmt.Printf("主机名: %s\n", sysInfo.Hostname)
fmt.Printf("用户名: %s\n", sysInfo.Username)
fmt.Printf("Go版本: %s\n", sysInfo.GoVersion)
fmt.Printf("编译器: %s\n", sysInfo.Compiler)
fmt.Printf("Goroutine数量: %d\n", sysInfo.NumGoroutine)
fmt.Println("\n========== CPU信息 ==========")
cpuInfo := s.GetCPUInfo()
fmt.Printf("型号: %s\n", cpuInfo.ModelName)
fmt.Printf("核心数: %d\n", cpuInfo.Cores)
fmt.Printf("线程数: %d\n", cpuInfo.Threads)
fmt.Println("\n========== 内存信息 ==========")
memInfo := s.GetMemoryInfo()
fmt.Printf("总内存: %s\n", s.FormatBytes(memInfo.Total))
fmt.Printf("已用内存: %s\n", s.FormatBytes(memInfo.Used))
fmt.Printf("可用内存: %s\n", s.FormatBytes(memInfo.Available))
fmt.Printf("使用率: %.2f%%\n", memInfo.UsedPct)
fmt.Println("\n========== 磁盘信息 ==========")
diskInfo, _ := s.GetDiskUsage(".")
if diskInfo != nil {
fmt.Printf("路径: %s\n", diskInfo.Path)
fmt.Printf("总空间: %s\n", s.FormatBytes(diskInfo.Total))
fmt.Printf("已用空间: %s\n", s.FormatBytes(diskInfo.Used))
fmt.Printf("可用空间: %s\n", s.FormatBytes(diskInfo.Free))
fmt.Printf("使用率: %.2f%%\n", diskInfo.UsedPct)
}
fmt.Println("\n========== 网络接口 ==========")
networkInfos := s.GetNetworkInterfaces()
for _, netInfo := range networkInfos {
fmt.Printf("接口: %s\n", netInfo.InterfaceName)
fmt.Printf("IP地址: %s\n", netInfo.IPAddress)
fmt.Printf("MAC地址: %s\n", netInfo.MACAddress)
fmt.Printf("MTU: %d\n", netInfo.MTU)
fmt.Println("---")
}
fmt.Println("\n========== GPU信息 ==========")
gpus := s.GetGPUInfo()
for i, gpu := range gpus {
fmt.Printf("GPU %d: %s\n", i+1, gpu)
}
fmt.Println("\n========== 进程信息 ==========")
processInfo := s.GetCurrentProcessInfo()
fmt.Printf("进程ID: %d\n", processInfo.PID)
fmt.Printf("父进程ID: %d\n", processInfo.PPID)
fmt.Printf("进程名: %s\n", processInfo.Name)
fmt.Printf("内存使用: %s\n", s.FormatBytes(processInfo.MemoryUsage))
fmt.Println("\n========== 系统运行时间 ==========")
uptime := s.GetSystemUptime()
fmt.Printf("运行时间: %s\n", uptime.String())
}
+98
View File
@@ -0,0 +1,98 @@
package utils
import (
"net"
"runtime"
"unsafe"
)
// Is64Bit 检查系统是否为64位
func (s *SysUtils) Is64Bit() bool {
return unsafe.Sizeof(uintptr(0)) == 8
}
// GetNetworkInterfaces 获取网络接口信息
func (s *SysUtils) GetNetworkInterfaces() []NetworkInfo {
var networkInfos []NetworkInfo
interfaces, err := net.Interfaces()
if err != nil {
return networkInfos
}
for _, iface := range interfaces {
// 跳过回环接口和未启用的接口
if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
var ipAddr string
for _, addr := range addrs {
if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
ipAddr = ipNet.IP.String()
break
}
}
}
if ipAddr != "" {
networkInfo := NetworkInfo{
InterfaceName: iface.Name,
IPAddress: ipAddr,
MACAddress: iface.HardwareAddr.String(),
MTU: iface.MTU,
}
networkInfos = append(networkInfos, networkInfo)
}
}
return networkInfos
}
// GetCPUInfo 获取CPU信息
func (s *SysUtils) GetCPUInfo() CPUInfo {
cpuInfo := CPUInfo{
Cores: runtime.NumCPU(),
Threads: runtime.NumCPU(), // 在Go中通常相等
}
// 调用平台特定的方法来获取详细信息
s.getCPUInfoPlatform(&cpuInfo)
return cpuInfo
}
// GetMemoryInfo 获取内存信息
func (s *SysUtils) GetMemoryInfo() MemoryInfo {
var memInfo MemoryInfo
// 调用平台特定的方法
s.getMemoryInfoPlatform(&memInfo)
if memInfo.Total > 0 {
memInfo.UsedPct = float64(memInfo.Used) / float64(memInfo.Total) * 100
}
return memInfo
}
// GetDiskUsage 获取磁盘使用情况
func (s *SysUtils) GetDiskUsage(path string) (*DiskInfo, error) {
return s.getDiskUsagePlatform(path)
}
// GetAllDisksInfo 跨平台获取所有磁盘信息
func (s *SysUtils) GetAllDisksInfo() ([]*DiskInfo, error) {
return s.getAllDisksInfoPlatform()
}
// GetGPUInfo 获取GPU信息
func (s *SysUtils) GetGPUInfo() []string {
return s.getGPUInfoPlatform()
}
+171
View File
@@ -0,0 +1,171 @@
//go:build darwin
// +build darwin
package utils
import (
"fmt"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"syscall"
"time"
)
// getCPUInfoPlatform 获取macOS下的CPU信息
func (s *SysUtils) getCPUInfoPlatform(info *CPUInfo) {
cmd := exec.Command("sysctl", "-n", "machdep.cpu.brand_string")
output, err := cmd.Output()
if err != nil {
return
}
info.ModelName = strings.TrimSpace(string(output))
}
// getMemoryInfoPlatform 获取macOS下的内存信息
func (s *SysUtils) getMemoryInfoPlatform(info *MemoryInfo) {
cmd := exec.Command("sysctl", "-n", "hw.memsize")
output, err := cmd.Output()
if err != nil {
return
}
total, err := strconv.ParseUint(strings.TrimSpace(string(output)), 10, 64)
if err != nil {
return
}
info.Total = total
// 获取可用内存需要更复杂的计算,这里简化处理
var m runtime.MemStats
runtime.ReadMemStats(&m)
info.Used = m.Sys
info.Available = info.Total - info.Used
}
// getDiskUsagePlatform macOS平台获取磁盘信息
func (s *SysUtils) getDiskUsagePlatform(path string) (*DiskInfo, error) {
var stat syscall.Statfs_t
err := syscall.Statfs(path, &stat)
if err != nil {
return nil, fmt.Errorf("获取磁盘信息失败: %w", err)
}
total := stat.Blocks * uint64(stat.Bsize)
free := stat.Bavail * uint64(stat.Bsize)
used := total - free
usedPct := float64(used) / float64(total) * 100
// 获取文件系统类型
fsType := "APFS" // macOS默认文件系统
return &DiskInfo{
Path: path,
Total: total,
Free: free,
Used: used,
UsedPct: usedPct,
FileSystem: fsType,
}, nil
}
// getAllDisksInfoPlatform macOS平台获取所有磁盘信息
func (s *SysUtils) getAllDisksInfoPlatform() ([]*DiskInfo, error) {
var disks []*DiskInfo
// 获取挂载的卷
cmd := exec.Command("df", "-h")
output, err := cmd.Output()
if err != nil {
// 如果df命令失败,使用默认路径
commonPaths := []string{"/", "/System/Volumes/Data"}
for _, path := range commonPaths {
if _, err := os.Stat(path); err == nil {
diskInfo, err := s.GetDiskUsage(path)
if err != nil {
continue
}
disks = append(disks, diskInfo)
}
}
return disks, nil
}
lines := strings.Split(string(output), "\n")
for i, line := range lines {
if i == 0 || line == "" { // 跳过标题行和空行
continue
}
fields := strings.Fields(line)
if len(fields) >= 6 {
mountPoint := fields[5]
// 过滤掉一些虚拟文件系统
if strings.HasPrefix(mountPoint, "/dev") ||
strings.HasPrefix(mountPoint, "/private/var/vm") {
continue
}
diskInfo, err := s.GetDiskUsage(mountPoint)
if err != nil {
continue
}
disks = append(disks, diskInfo)
}
}
return disks, nil
}
// getGPUInfoPlatform 获取macOS下的GPU信息
func (s *SysUtils) getGPUInfoPlatform() []string {
var gpus []string
// 使用system_profiler获取GPU信息
cmd := exec.Command("system_profiler", "SPDisplaysDataType")
output, err := cmd.Output()
if err != nil {
return gpus
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.Contains(line, "Chipset Model:") {
parts := strings.Split(line, ":")
if len(parts) > 1 {
gpu := strings.TrimSpace(parts[1])
gpus = append(gpus, gpu)
}
}
}
return gpus
}
// getSystemUptime 获取macOS系统启动时间
func (s *SysUtils) getSystemUptime() time.Duration {
cmd := exec.Command("sysctl", "-n", "kern.boottime")
output, err := cmd.Output()
if err != nil {
return 0
}
// 解析输出格式: { sec = 1234567890, usec = 123456 }
line := strings.TrimSpace(string(output))
if strings.Contains(line, "sec =") {
parts := strings.Split(line, "sec =")
if len(parts) > 1 {
secPart := strings.Split(parts[1], ",")[0]
secPart = strings.TrimSpace(secPart)
sec, err := strconv.ParseInt(secPart, 10, 64)
if err == nil {
bootTime := time.Unix(sec, 0)
return time.Since(bootTime)
}
}
}
return 0
}
+200
View File
@@ -0,0 +1,200 @@
//go:build linux
// +build linux
package utils
import (
"bufio"
"fmt"
"os"
"os/exec"
"strconv"
"strings"
"syscall"
"time"
)
// getCPUInfoPlatform 获取Linux下的CPU信息
func (s *SysUtils) getCPUInfoPlatform(info *CPUInfo) {
file, err := os.Open("/proc/cpuinfo")
if err != nil {
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "model name") {
parts := strings.Split(line, ":")
if len(parts) > 1 {
info.ModelName = strings.TrimSpace(parts[1])
break
}
}
}
}
// getMemoryInfoPlatform 获取Linux下的内存信息
func (s *SysUtils) getMemoryInfoPlatform(info *MemoryInfo) {
file, err := os.Open("/proc/meminfo")
if err != nil {
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
if len(fields) < 2 {
continue
}
value, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
continue
}
value *= 1024 // Convert KB to bytes
switch fields[0] {
case "MemTotal:":
info.Total = value
case "MemAvailable:":
info.Available = value
}
}
if info.Total > 0 && info.Available > 0 {
info.Used = info.Total - info.Available
}
}
// getDiskUsagePlatform Linux平台获取磁盘信息
func (s *SysUtils) getDiskUsagePlatform(path string) (*DiskInfo, error) {
var stat syscall.Statfs_t
err := syscall.Statfs(path, &stat)
if err != nil {
return nil, fmt.Errorf("获取磁盘信息失败: %w", err)
}
total := stat.Blocks * uint64(stat.Bsize)
free := stat.Bavail * uint64(stat.Bsize)
used := total - free
usedPct := float64(used) / float64(total) * 100
return &DiskInfo{
Path: path,
Total: total,
Free: free,
Used: used,
UsedPct: usedPct,
FileSystem: "ext4", // Linux通常是ext4,这里简化处理
}, nil
}
// getAllMountPoints 获取所有挂载点
func (s *SysUtils) getAllMountPoints() ([]string, error) {
// 读取/proc/mounts文件
content, err := os.ReadFile("/proc/mounts")
if err != nil {
return nil, fmt.Errorf("读取挂载点失败: %w", err)
}
var mountPoints []string
lines := strings.Split(string(content), "\n")
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) >= 2 {
mountPoint := fields[1]
// 过滤掉一些虚拟文件系统
if !strings.HasPrefix(mountPoint, "/proc") &&
!strings.HasPrefix(mountPoint, "/sys") &&
!strings.HasPrefix(mountPoint, "/dev") &&
mountPoint != "/" {
mountPoints = append(mountPoints, mountPoint)
}
}
}
return mountPoints, nil
}
// getAllDisksInfoPlatform Linux平台获取所有磁盘信息
func (s *SysUtils) getAllDisksInfoPlatform() ([]*DiskInfo, error) {
var disks []*DiskInfo
// 通常检查根目录和常见挂载点
commonPaths := []string{"/", "/home", "/var", "/tmp"}
for _, path := range commonPaths {
if _, err := os.Stat(path); err == nil {
diskInfo, err := s.GetDiskUsage(path)
if err != nil {
continue
}
disks = append(disks, diskInfo)
}
}
// 也可以尝试从挂载点获取
mountPoints, err := s.getAllMountPoints()
if err == nil {
for _, mount := range mountPoints {
diskInfo, err := s.GetDiskUsage(mount)
if err != nil {
continue
}
// 检查是否已经存在
exists := false
for _, d := range disks {
if d.Path == diskInfo.Path {
exists = true
break
}
}
if !exists {
disks = append(disks, diskInfo)
}
}
}
return disks, nil
}
// getGPUInfoPlatform 获取Linux下的GPU信息
func (s *SysUtils) getGPUInfoPlatform() []string {
var gpus []string
// 尝试使用lspci获取GPU信息
cmd := exec.Command("lspci")
output, err := cmd.Output()
if err != nil {
return gpus
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.Contains(strings.ToLower(line), "vga") ||
strings.Contains(strings.ToLower(line), "3d") ||
strings.Contains(strings.ToLower(line), "display") {
gpus = append(gpus, strings.TrimSpace(line))
}
}
return gpus
}
// getSystemUptime 获取Linux系统启动时间
func (s *SysUtils) getSystemUptime() time.Duration {
file, err := os.Open("/proc/uptime")
if err != nil {
return 0
}
defer file.Close()
var uptime float64
fmt.Fscanf(file, "%f", &uptime)
return time.Duration(uptime) * time.Second
}
+10
View File
@@ -0,0 +1,10 @@
package utils
import (
"testing"
)
func TestSysUtils(t *testing.T) {
sys_u := NewSysUtils()
sys_u.PrintSystemInfo()
}
+166
View File
@@ -0,0 +1,166 @@
//go:build windows
// +build windows
package utils
import (
"fmt"
"os/exec"
"strings"
"syscall"
"time"
"unsafe"
)
// getCPUInfoPlatform 获取Windows下的CPU信息
func (s *SysUtils) getCPUInfoPlatform(info *CPUInfo) {
cmd := exec.Command("wmic", "cpu", "get", "name", "/value")
output, err := cmd.Output()
if err != nil {
return
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.HasPrefix(line, "Name=") {
info.ModelName = strings.TrimSpace(strings.TrimPrefix(line, "Name="))
break
}
}
}
// getMemoryInfoPlatform 获取Windows下的内存信息
func (s *SysUtils) getMemoryInfoPlatform(info *MemoryInfo) {
kernel32 := syscall.NewLazyDLL("kernel32.dll")
globalMemoryStatusEx := kernel32.NewProc("GlobalMemoryStatusEx")
type memoryStatusEx struct {
dwLength uint32
dwMemoryLoad uint32
ullTotalPhys uint64
ullAvailPhys uint64
ullTotalPageFile uint64
ullAvailPageFile uint64
ullTotalVirtual uint64
ullAvailVirtual uint64
ullAvailExtendedVirtual uint64
}
var memStatus memoryStatusEx
memStatus.dwLength = uint32(unsafe.Sizeof(memStatus))
ret, _, _ := globalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memStatus)))
if ret != 0 {
info.Total = memStatus.ullTotalPhys
info.Available = memStatus.ullAvailPhys
info.Used = info.Total - info.Available
}
}
// getDiskUsagePlatform Windows平台获取磁盘信息
func (s *SysUtils) getDiskUsagePlatform(path string) (*DiskInfo, error) {
kernel32 := syscall.NewLazyDLL("kernel32.dll")
getDiskFreeSpaceEx := kernel32.NewProc("GetDiskFreeSpaceExW")
var freeBytesAvailable uint64
var totalNumberOfBytes uint64
var totalNumberOfFreeBytes uint64
pathPtr, _ := syscall.UTF16PtrFromString(path)
ret, _, _ := getDiskFreeSpaceEx.Call(
uintptr(unsafe.Pointer(pathPtr)),
uintptr(unsafe.Pointer(&freeBytesAvailable)),
uintptr(unsafe.Pointer(&totalNumberOfBytes)),
uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)),
)
if ret == 0 {
return nil, fmt.Errorf("获取磁盘信息失败")
}
used := totalNumberOfBytes - totalNumberOfFreeBytes
usedPct := float64(used) / float64(totalNumberOfBytes) * 100
return &DiskInfo{
Path: path,
Total: totalNumberOfBytes,
Free: totalNumberOfFreeBytes,
Used: used,
UsedPct: usedPct,
FileSystem: "NTFS", // Windows通常是NTFS,这里简化处理
}, nil
}
// getAllDrivesWindows 获取所有磁盘驱动器列表
func (s *SysUtils) getAllDrivesWindows() ([]string, error) {
kernel32 := syscall.NewLazyDLL("kernel32.dll")
getLogicalDrives := kernel32.NewProc("GetLogicalDrives")
ret, _, _ := getLogicalDrives.Call()
if ret == 0 {
return nil, fmt.Errorf("获取驱动器列表失败")
}
var drives []string
for i := 0; i < 26; i++ {
if ret&(1<<uint(i)) != 0 {
drive := string(rune('A'+i)) + ":\\"
drives = append(drives, drive)
}
}
return drives, nil
}
// getAllDisksInfoPlatform Windows平台获取所有磁盘信息
func (s *SysUtils) getAllDisksInfoPlatform() ([]*DiskInfo, error) {
var disks []*DiskInfo
drives, err := s.getAllDrivesWindows()
if err != nil {
return nil, err
}
for _, drive := range drives {
diskInfo, err := s.GetDiskUsage(drive)
if err != nil {
continue // 跳过无法访问的驱动器
}
disks = append(disks, diskInfo)
}
return disks, nil
}
// getGPUInfoPlatform 获取Windows下的GPU信息
func (s *SysUtils) getGPUInfoPlatform() []string {
var gpus []string
// 使用wmic获取GPU信息
cmd := exec.Command("wmic", "path", "win32_VideoController", "get", "name", "/value")
output, err := cmd.Output()
if err != nil {
return gpus
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.HasPrefix(line, "Name=") && len(line) > 5 {
gpu := strings.TrimSpace(strings.TrimPrefix(line, "Name="))
if gpu != "" {
gpus = append(gpus, gpu)
}
}
}
return gpus
}
// getSystemUptime 获取Windows系统启动时间
func (s *SysUtils) getSystemUptime() time.Duration {
kernel32 := syscall.NewLazyDLL("kernel32.dll")
getTickCount64 := kernel32.NewProc("GetTickCount64")
ret, _, _ := getTickCount64.Call()
return time.Duration(ret) * time.Millisecond
}