常用业务代码

go语言在.csv文件中加入超链接 #

func main() {
	// 打开文件以写入 CSV 数据
	file, err := os.Create("output.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	// 创建 CSV writer
	writer := csv.NewWriter(file)
	defer writer.Flush()

	// 写入 CSV 头部
	header := []string{"File Name", "Hyperlink"}
	writer.Write(header)

	// 模拟一些文件名和相对路径数据
	fileData := []struct {
		FileName     string
		RelativePath string
	}{
		{"video.MP4", "./d/video.MP4"},
		// 添加更多文件名和相对路径
	}

	// 写入文件名和相对路径数据到 CSV 文件
	for _, data := range fileData {
		// 构建超链接字符串
		hyperlinkFormula := `=HYPERLINK("` + data.RelativePath + `", "` + data.FileName + `")`
		row := []string{data.FileName, hyperlinkFormula}
		writer.Write(row)
	}

	// 刷新 CSV writer 缓冲区,确保所有数据被写入文件
	writer.Flush()
}

通过ffmpeg获取视频文件信息 #

//videopath := api.GetMountPoint() + common.FixPathWithSeparator(v.FullPath, "\\")
	//vv, iserr := video.GetVideoInfo.Stat(videopath)
	//taskMutex.Lock()
	//tasked++
	//taskMutex.Unlock()
	//if !iserr {
	//	data.Duration = int(math.Floor(vv.Length)) //秒
	//	data.FrameRate = int(math.Floor(vv.Fps))
	//	data.FrameHeight = int(vv.Height)
	//	data.FrameWidth = int(vv.Width)
	//	data.Resolution = strconv.Itoa(data.FrameWidth) + " * " + strconv.Itoa(data.FrameHeight)
	//}
	//data.UserId=
	//width, height, duration, _, err := getVideoSize(videopath)
	//if err == nil {
	//	data.Duration, _ = strconv.Atoi(duration) //秒
	//	//data.FrameRate = int(math.Floor(vv.Fps))
	//	data.Resolution = strconv.Itoa(width * height)
	//	data.FrameHeight = height
	//	data.FrameWidth = width
	//}
// import ffmpeg "github.com/u2takey/ffmpeg-go"   发现时间效果差不多 都是底层启动多个exe执行
func getVideoSize(fileName string) (width, height int, duration, rframerate string, err error) {
	//log.Println("Getting video size for", fileName)
	data, err := ffmpeg.Probe(fileName)
	if err != nil {
		fmt.Println(err.Error())
		return 0, 0, "", "", err
	}
	//log.Println("got video info", data)
	type VideoInfo struct {
		Streams []struct {
			CodecType  string `json:"codec_type"`
			Width      int
			Height     int
			Duration   string
			RFrameRate string `json:"r_frame_rate"`
		} `json:"streams"`
	}
	vInfo := &VideoInfo{}
	err = json.Unmarshal([]byte(data), vInfo)
	if err != nil {
		return 0, 0, "", "", err
	}
	for _, s := range vInfo.Streams {
		if s.CodecType == "video" {
			return s.Width, s.Height, s.Duration, s.RFrameRate, err
		}
	}
	return 0, 0, "", "", err
}
var GetVideoInfo = new(VideoInfo)

type VideoInfo struct{}
type Video struct {
	//Path     string
	Length float64 // 时长(s)
	//Bitrate  float64 // 播放速率(kb/s)
	//Size     int64   // 文件大小(byte)
	Width  int64   // 视频分辨率宽度
	Height int64   // 视频分辨率高度
	Fps    float64 // 视频帧率(帧/s)
	//Vbitrate float64 // 视频比特率(kb/s)
	//Abitrate float64 // 音频比特率(kb/s)
	//Ahz      float64 // 音频采集率(Hz)
}

// Stat 通过调用 ffmpeg命令 使用正则获取视频信息,
// 部分视频无法正常获取时长或比特率等,则使用0表示;
// 如果多个属性无法获取,则可能是正则匹配不全,
// 请手动执行 ffmpeg -i file_path 参照输出信息来确认问题
//var cmd = exec.Command("ffmpeg", "-i", "video_path")

func (video VideoInfo) Stat(video_path string) (v *Video, iserr bool) {
	//cmd.Args[2] = video_path
	//dir, err := os.Getwd() //获取当前文件路径
	//if err != nil {
	//	fmt.Println(err.Error())
	//	return
	//}
	ffmpegPath := filepath.Join(api.GetAppInstallDir(), "\\bin\\ffmpeg\\ffmpeg.exe")
	//api.Log.Info("ffmpegPath:", ffmpegPath) //
	cmd := exec.Command(ffmpegPath, "-i", video_path)
	r, _ := cmd.CombinedOutput()
	//if err != nil {
	//	api.Log.Error(err.Error()) //
	//	fmt.Println("FFmpeg command execution failed: %s\n", err)
	//}
	// sample1
	//  Duration: 00:00:00.00, start: 0.000000, bitrate: N/A
	//    Stream #0:0: Video: rv40 (RV40 / 0x30345652), yuv420p, 640x480, 25 fps, 25 tbr, 1k tbn, 1k tbc
	//    Stream #0:1: Audio: cook (cook / 0x6B6F6F63), 44100 Hz, mono, fltp, 64 kb/s

	// sample2
	//  Duration: 00:10:23.13, start: 0.000000, bitrate: 1741 kb/s
	//    Stream #0:0: Video: h264 (High) (H264 / 0x34363248), yuv420p(progressive), 352x288 [SAR 1:1 DAR 11:9], 1604 kb/s, 30 fps, 30 tbr, 30 tbn, 60 tbc
	//    Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, s16p, 128 kb/s

	// sample3
	//  Duration: 00:17:57.43, start: 0.000000, bitrate: 383 kb/s
	//    Stream regexp.MustCompile(`.*Duration:\s(.*?),.*bitrate:\s(\S+)`)#0:0: Audio: cook (cook / 0x6B6F6F63), 44100 Hz, stereo, fltp, 64 kb/s
	//    Stream #0:1: Video: rv40 (RV40 / 0x30345652), yuv420p, 640x480, 308 kb/s, 23.98 fps, 23.98 tbr, 1k tbn, 1k tbc

	str_r := string([]byte(r))
	if video.parse_err(str_r) {
		return nil, true
	}

	length, _ := video.parse_duration(str_r)          //length, bitrate
	width, height, _, fps := video.parse_video(str_r) //width, height, v_bitrate, fps
	//a_hz, a_bitrate := video.parse_audio(str_r)

	v = &Video{
		//Path:     video_path,
		Length: length,
		//Bitrate:  bitrate,
		//Size:     get_size(video_path),
		Width:  width,
		Height: height,
		Fps:    fps,
		//Vbitrate: v_bitrate,
		//Abitrate: a_bitrate,
		//Ahz:      a_hz,
	}

	return
}

func (video VideoInfo) get_size(path string) int64 {
	file, _ := os.Stat(path)
	return file.Size()
}

var reg_err = regexp.MustCompile(`\[in#\d+ @ [0-9a-fA-F]+\] Error opening input: (.+)`)

// 解析err行
func (video VideoInfo) parse_err(str string) bool {
	s := reg_err.FindString(str)
	if len(s) != 0 {
		api.Log.Error(errors.New(s))
		return true
	}
	return false
}

var reg_duration = regexp.MustCompile(`.*Duration:\s(.*?),.*bitrate:\s(\S+)`)

// 解析Duration行
func (video VideoInfo) parse_duration(str string) (float64, float64) {
	s := reg_duration.FindStringSubmatch(str)
	if len(s) != 3 {
		return 0, 0
	}

	t := strings.Split(s[1], ":")
	length := atof64(t[0])*3600 + atof64(t[1])*60 + atof64(t[2])
	return length, atof64(s[2])
}

var reg_video = regexp.MustCompile(`Stream.*Video.*\s(\d+)x(\d+)(?:.*?(\S+)\skb/s)?.*?(\S+)\sfps`)

// 解析Video行
func (video VideoInfo) parse_video(str string) (int64, int64, float64, float64) {
	s := reg_video.FindStringSubmatch(str)

	if len(s) != 5 {
		return 0, 0, 0, 0
	}
	return atoi64(s[1]), atoi64(s[2]), atof64(s[3]), atof64(s[4])
}

var reg_audio = regexp.MustCompile(`Stream.*Audio.*?(\d+)\sHz.*\s(\S+)\skb/s`)

// 解析Audio行
func (video VideoInfo) parse_audio(str string) (float64, float64) {
	s := reg_audio.FindStringSubmatch(str)

	if len(s) != 3 {
		return 0, 0
	}
	return atof64(s[1]), atof64(s[2])
}

func atoi64(s string) int64 {
	i, _ := strconv.ParseInt(s, 10, 64)
	return i
}

func atof64(s string) float64 {
	i, _ := strconv.ParseFloat(s, 64)
	return i
}

防止电脑进入睡眠状态 #

func disableComputerSleep() (err error) {
	kernel32, err := syscall.LoadLibrary("kernel32.dll")
	if err != nil {
		return
	}
	defer syscall.FreeLibrary(kernel32)
	_SetThreadExecutionState, err := syscall.GetProcAddress(kernel32, "SetThreadExecutionState")
	if err != nil {
		return
	}

	for {
		_, _, callErr := syscall.Syscall(_SetThreadExecutionState, 1, 0x80000000|0x00000002|0x00000001, 0, 0)
		if callErr != 0 {
			fmt.Println("SetThreadExecutionState error", callErr)
		}
		time.Sleep(30 * 1000 * time.Millisecond)
	}
}

监听进程退出信号 #

func exitSingal() chan os.Signal {
	exitSingal := make(chan os.Signal, 1)
	signal.Notify(exitSingal, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGINT)
	return exitSingal
}
select {
	case sin := <-exitSingal():
		fmt.Printf("get system singal %s ,exit ", sin.String())
}

获取电脑睡眠状态 #

var (
	   powerStatusCode              uint32 = 0
	   eventCh                             = make(chan uint32)
	   ctx, Chancel                        = context.WithCancel(context.Background())
	libPowrProf                            = windows.NewLazySystemDLL("powrprof.dll")
	powerRegisterSuspendResumeNotification=libPowrProf.NewProc("PowerRegisterSuspendResumeNotification")
	powerUnregisterSuspendResumeNotification=libPowrProf.NewProc("PowerUnregisterSuspendResumeNotification")
)

const (
	PBT_APMSUSPEND         uint32 = 4
	PBT_APMRESUMESUSPEND   uint32 = 7
	PBT_APMRESUMEAUTOMATIC uint32 = 18
)
//入口函数
func ListenSystemSleepEvent() {
	NewEventListener(ctx, eventCh)
	for {
		select {
		case powerStatusCode = <-eventCh:
		default:
		}
	}
}

func NewEventListener(haltCtx context.Context, eventCh chan uint32) {
	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		const (
			_DEVICE_NOTIFY_CALLBACK = 2
		)
		type _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS struct {
			callback uintptr
			context  uintptr
		}

		var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr {
			eventCh <- changeType
			return 0
		}

		params := _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS{
			callback: windows.NewCallback(fn),
		}
		handle := uintptr(0)

		Log.Info("注册电源 暂停/恢复")
		powerRegisterSuspendResumeNotification.Call(
			_DEVICE_NOTIFY_CALLBACK,
			uintptr(unsafe.Pointer(&params)),
			uintptr(unsafe.Pointer(&handle)),
		)

		<-haltCtx.Done()
		Log.Info("取消注册电源 暂停/恢复")
		powerUnregisterSuspendResumeNotification.Call(
			uintptr(unsafe.Pointer(&handle)),
		)
	}()
}

自动填充空格 以格式化输出字符串 #

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
)

func main() {
	// 定义一个JSON数据
	jsonData := []byte(`{"a":1,"b":2}`)

	// 格式化JSON数据
	var formattedData bytes.Buffer
	err := json.Indent(&formattedData, jsonData, "", "  ")
	if err != nil {
		fmt.Println("Error formatting JSON:", err)
		return
	}

	// 输出格式化后的JSON数据
	fmt.Println(formattedData.String())
}

逐行读取文件 #

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

func main() {
	filePath := "your_file.log"

	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	// 创建一个 Scanner 来逐行读取文件内容
	scanner := bufio.NewScanner(file)

	// 逐行读取并处理文件内容
	for scanner.Scan() {
		line := scanner.Text()
		fmt.Println(line)

		// 在这里可以对每一行的内容进行处理
		// 例如,你可以将每一行的内容存储到切片中,或者进行其他操作
	}

	// 检查是否有错误发生
	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

判断windows系统版本 #

import "github.com/elastic/go-sysinfo"
func TestGetVer(t *testing.T) {
	host, err := sysinfo.Host()
	if err != nil {
		fmt.Println("Error getting host info:", err)
		return
	}

	info := host.Info()
	fmt.Println("Operating System:", info.OS.Name)
	fmt.Println("Family:", info.OS.Family)
	fmt.Println("Version:", info.OS.Version)
	fmt.Println("Platform:", info.OS.Platform)
	fmt.Println("Kernel Version:", info.KernelVersion)
	fmt.Println("Arch:", info.Architecture)
}
Operating System:Windows 7 Home Basic
Family: windows
Uersion: 6.1
Platform: windows
Kernel version:6.1.2601.17514(win7sp1_rtm.101119-1850)
Arch:x86_64
0perating System: windows
Version: Windows 6.1<Build 761>

逐字节读取文件 #

func Test_copy(t *testing.T) {
	path1 := "C:\\hlnet\\1-1720405740\\小米行车记录仪MJHSJJLYBY-168862538.E01\\NO NAME\\$未分配簇"
	path2, _ := os.Getwd()
	path2 = filepath.Join(path2, "$未分配簇3")
	time1 := time.Now()
	file, err := os.Open(path1)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer file.Close()

	reader := bufio.NewReader(file)

	bufferSize := 10240
	buffer := make([]byte, bufferSize)

	for {
		n, err := reader.Read(buffer)
		if err != nil {
			fmt.Println(err.Error())
			if err == io.EOF {
				fmt.Println("EOF")
			}
			break // 文件读取结束或发生错误
		}
		// 处理读取的数据
		zeroBuffer := make([]byte, 1024)
		if !bytes.Equal(buffer, zeroBuffer[:n]) {

			fmt.Println("zero buffer")
		}

	}
	fmt.Println(time.Now().Sub(time1).Seconds())
}