• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Golang Fyne项目含源码

武飞扬头像
发飙的蜗牛_
帮助2

项目介绍

效果图

学新通

功能介绍

主要实现了根据文本文件里面的内容,自动更名所选文件夹里面的文件名称

步骤介绍

1.创建txt文本文件,输入内容程序界面中"目录文件"选择目前创建的文本文件
例:
学新通

2.选择需要批量更改名字的文件夹
学新通
3.选择路径后,程序点击"开始更名",便会自动更名
学新通
4.结果
学新通

代码区域

项目结构

学新通

下载fyne包以及Fyne工具包

命令:
1.go get fyne.io/fyne/v2
2.go get fyne.io/fyne/cmd/fyne

追加静态资源,程序设置图标

1.将静态资源编译为 go 文件 (在自己的项目目录打开终端执行):fyne bundle fav.png >> bundled.go
2. 打开 bundled.go 文件会看到一个变量 resourceFavPng
3.设置窗口图标,任务栏图标
//主要代码
a := app.New()
a.SetIcon(resourceFavPng) //本地运行的注释,否则报错,打包的时候在把此行代码打开

完整代码

package main

import (
	"YHSoft/Demo/GUIDemo/FyneDemo/02_RenameFileName/models" //更换成自己的项目路径
	"errors"
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/storage"
	"fyne.io/fyne/v2/widget"
	"github.com/flopp/go-findfont"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"unicode"
)

func main() {
	//新建一个app
	a := app.New()
	//设置窗口栏,任务栏图标
	a.SetIcon(resourceIconPng)
	//新建一个窗口
	w := a.NewWindow("自动化更名程序V1.0")
	//主界面框架布局
	MainShow(w)
	//尺寸
	w.Resize(fyne.Size{Width: 500, Height: 100})
	//w居中显示
	w.CenterOnScreen()
	//循环运行
	w.ShowAndRun()

	err := os.Unsetenv("FYNE_FONT")
	if err != nil {
		return
	}
}

var tileInfo string
var done = make(chan bool)
var stop = make(chan int, 1)
var num int64

// MainShow 主界面函数
func MainShow(w fyne.Window) {
	//var ctrl *beep.Ctrl
	title := widget.NewLabel("自动化更名程序")
	hello := widget.NewLabel("目录文件:")
	entry1 := widget.NewEntry() //文本输入框
	//entry1.SetText("E:\\rename_temp2\\123.txt")

	dia1 := widget.NewButton("打开", func() { //回调函数:打开选择文件对话框
		fd := dialog.NewFileOpen(func(reader fyne.URIReadCloser, err error) {
			if err != nil {
				dialog.ShowError(err, w)
				return
			}
			if reader == nil {
				log.Println("Cancelled")
				return
			}

			entry1.SetText(reader.URI().Path()) //把读取到的路径显示到输入框中
		}, w)

		fd.SetFilter(storage.NewExtensionFileFilter([]string{".txt"})) //打开的文件格式类型
		fd.Show()                                                      //控制是否弹出选择文件目录对话框
	})

	text := widget.NewMultiLineEntry() //多行输入组件
	//text.Disable()                     //禁用输入框,不能更改数据

	labelLast := widget.NewLabel("发飙的蜗牛    ALL Right Reserved")
	//labelLast := widget.NewLabel(" ")
	label4 := widget.NewLabel("文件路径:")
	entry2 := widget.NewEntry()

	//entry2.SetText("E:\\rename_temp2\\宝岗路停车场项目幕墙施工图PDF")

	dia2 := widget.NewButton("打开", func() {
		dialog.ShowFolderOpen(func(list fyne.ListableURI, err error) {
			if err != nil {
				dialog.ShowError(err, w)
				return
			}
			if list == nil {
				log.Println("Cancelled")
				return
			}
			//设置输入框内容
			entry2.SetText(list.Path())
		}, w)
	})

	//开始更名按钮
	bt3 := widget.NewButton("开始 更名", func() {
		go func() {
			if (entry1.Text != "") && (entry2.Text != "") {
				text.SetText("")
				text.Refresh()
				if num != 0 {
					stop <- 1
					return
				} else {
					err := generateTxt(entry1.Text, entry2.Text, text)
					if err != nil {
						dialog.ShowError(err, w)
					}
					text.Refresh()
				}
			} else {
				dialog.ShowError(errors.New("读取TXT文件错误"), w)
			}
		}()

	})

	//停止更名按钮
	bt4 := widget.NewButton("停止 更名", func() {
		go func() {
			done <- false
		}()
	})

	head := container.NewCenter(title)

	v1 := container.NewBorder(layout.NewSpacer(), layout.NewSpacer(), hello, dia1, entry1)
	v4 := container.NewBorder(layout.NewSpacer(), layout.NewSpacer(), label4, dia2, entry2)

	v5 := container.NewHBox(bt3, bt4)
	v5Center := container.NewCenter(v5)

	ctnt := container.NewVBox(head, v1, v4, v5Center, text, labelLast) //控制显示位置顺序
	w.SetContent(ctnt)
}

//设置字体
func init() {
	fontPaths := findfont.List()
	for _, fontPath := range fontPaths {
		//fmt.Println(fontPath)
		//楷体:simkai.ttf
		//黑体:simhei.ttf
		//微软雅黑:msyh.ttc
		if strings.Contains(fontPath, "simkai.ttf") {
			err := os.Setenv("FYNE_FONT", fontPath)
			if err != nil {
				return
			}
			break
		}
	}
}

//读取数据校验数据
func generateTxt(inPath, outPath string, text *widget.Entry) error {
	//标题
	tileInfo  = "开始处理,正在读取文件...\n"
	text.SetText(tileInfo)

	nameList,err := models.GetStrList(inPath)
	if err != nil{
		tileInfo  = "读取文件出错...\n"
		text.SetText(tileInfo)
	}


	//获取文件路径的文件
	files, _ := ioutil.ReadDir(outPath)

	var fileNameList []string

	for _, file := range files {
		// 带扩展名的文件名
		fullFilename := file.Name()

		//添加文件数据到切片中
		fileNameList = append(fileNameList, fullFilename)
	}

	if len(nameList) == 0 || len(fileNameList) == 0{
		tileInfo  = "已停止处理...\n"
		text.SetText(tileInfo) //设置多行显示控件中的内容
		return errors.New("找不到路径或路径下不存在此文件")
	}

	if len(nameList) != len(fileNameList) {
		tileInfo  = "已停止处理...\n"
		text.SetText(tileInfo) //设置多行显示控件中的内容
		return errors.New("目录行数与文件行数不相等,请检查!")
	}

	renameFile(nameList, fileNameList, outPath, text)

	return nil
}

//操作更名文件
func renameFile(nameList []string, fileNameList []string, outPath string, text *widget.Entry) {
	var newName string

	//遍历更改
	for index, fullFilename := range fileNameList {
		select {
		case <-done: //读管道中内容,没有内容前,阻塞
			//扩展名
			fileExt := filepath.Ext(fullFilename)

			//fmt.Println("nameList[index]=",nameList[index])
			defaultName := nameList[index] //文本文件初始名称
			var defaultNameCode []string
			var defaultNameNewCode string

			rune := []rune(defaultName)
			for i := len(rune); i > 0; i-- {
				if !unicode.Is(unicode.Han, rune[i-1]) {
					defaultNameCode = append(defaultNameCode, string(rune[i-1]))
				} else {
					break
				}
			}

			//重新编排名称编号
			for i := len(defaultNameCode); i > 0; i-- {
				defaultNameNewCode  = defaultNameCode[i-1]
			}

			//fmt.Println("defaultName=", defaultName)

			//重组新名称
			newName = strconv.Itoa(index 1)   " "   strings.ReplaceAll(defaultName, defaultNameNewCode, "")   " "   defaultNameNewCode

			// 不带扩展名的文件名
			//filenameOnly := strings.TrimSuffix(fullFilename, fileExt)

			//将每个文件名后面加上1,扩展名不变
			err := os.Rename(outPath `\` fullFilename, outPath `\` newName fileExt)
			if err != nil {
				fmt.Println("err=", err)
			}

			tileInfo  = "处理数据文件:"   fullFilename   "\n"
			time.Sleep(time.Second * 1)
			text.SetText(tileInfo) //设置多行显示控件中的 内容

			tileInfo  = "停止更名...\n"
			text.SetText(tileInfo) //设置多行显示控件中的内容
			num = num   1
			<-stop //读管道中内容,没有内容前,阻塞
		default:
			//扩展名
			fileExt := filepath.Ext(fullFilename)

			//fmt.Println("nameList[index]=",nameList[index])
			defaultName := nameList[index] //文本文件初始名称
			var defaultNameCode []string
			var defaultNameNewCode string

			rune := []rune(defaultName)
			for i := len(rune); i > 0; i-- {
				if !unicode.Is(unicode.Han, rune[i-1]) {
					defaultNameCode = append(defaultNameCode, string(rune[i-1]))
				} else {
					break
				}
			}

			//重新编排名称编号
			for i := len(defaultNameCode); i > 0; i-- {
				defaultNameNewCode  = defaultNameCode[i-1]
			}

			//fmt.Println("defaultName=", defaultName)

			//重组新名称
			newName = strconv.Itoa(index 1)   " "   strings.ReplaceAll(defaultName, defaultNameNewCode, "")   " "   defaultNameNewCode

			// 不带扩展名的文件名
			//filenameOnly := strings.TrimSuffix(fullFilename, fileExt)

			//将每个文件名后面加上1,扩展名不变
			err := os.Rename(outPath `\` fullFilename, outPath `\` newName fileExt)
			if err != nil {
				fmt.Println("err=", err)
			}

			tileInfo  = "处理数据文件:"   fullFilename   "\n"
			//time.Sleep(time.Second * 1)
			text.SetText(tileInfo) //设置多行显示控件中的 内容
		}
	}
	tileInfo  = "处理完毕!"
	text.SetText(tileInfo) //设置多行显示控件中的内容
	num = 0
}

学新通
package models

import (
	"bufio"
	"fmt"
	"github.com/axgle/mahonia"
	"io"
	"os"
	"strings"
)


//读取txt文件,自动判断编码格式
func GetStrList(path string)([]string,error){
	f, err := os.Open(path) //打开目录路径txt文件
	if err != nil {
		return nil, err
	}
	defer f.Close() //最后关闭文件

	r := bufio.NewReader(f)

	buf := make([]byte, 1024)
	var res string

	_, err = r.Read(buf)
	if err != nil && err != io.EOF {
		return nil,err
	}

	res = GetStrCoding(buf)

	if res == "UTF8" {
		return GetTextContentUTF8(path),nil
	} else {
		return GetTextContentGbk(path),nil
	}
}

//读取gbk编码格式的文件
func GetTextContentGbk(txtPath string) []string {
	f, err := os.Open(txtPath) //打开目录路径txt文件
	if err != nil {
		fmt.Println("err=", err)
	}
	defer f.Close()

	decoder := mahonia.NewDecoder("gbk")
	r := bufio.NewReader(decoder.NewReader(f))

	chunks := []byte{}
	buf := make([]byte, 1024)

	for {
		n, err := r.Read(buf)
		if err != nil && err != io.EOF {
			panic(err)
		}
		if 0 == n {
			break
		}
		chunks = append(chunks, buf[:n]...)
	}

	nameStr := strings.ReplaceAll(string(chunks), "\r\n", ",")
	return strings.Split(nameStr, ",")
}

//读取utf8编码格式的文件
func GetTextContentUTF8(txtPath string) []string {
	f, err := os.Open(txtPath) //打开目录路径txt文件
	if err != nil {
		fmt.Println("err=", err)
	}
	defer f.Close()

	r := bufio.NewReader(f)
	chunks := []byte{}
	buf := make([]byte, 1024)
	for {
		n, err := r.Read(buf)
		if err != nil && err != io.EOF {
			panic(err)
		}
		if 0 == n {
			break
		}
		chunks = append(chunks, buf[:n]...)
	}

	nameStr := strings.ReplaceAll(string(chunks), "\r\n", ",")
	return strings.Split(nameStr, ",")
}

const (
	GBK     string = "GBK"
	UTF8    string = "UTF8"
	UNKNOWN string = "UNKNOWN"
)

//判断文本文件格式
func GetStrCoding(data []byte) string {
	if isUtf8(data) == true {
		return UTF8
	} else if isGBK(data) == true {
		return GBK
	} else {
		return UNKNOWN
	}
}


func isGBK(data []byte) bool {
	length := len(data)
	var i = 0
	for i < length {
		if data[i] <= 0x7f {
			//编码0~127,只有一个字节的编码,兼容ASCII码
			i  
			continue
		} else {
			//大于127的使用双字节编码,落在gbk编码范围内的字符
			if data[i] >= 0x81 &&
				data[i] <= 0xfe &&
				data[i 1] >= 0x40 &&
				data[i 1] <= 0xfe &&
				data[i 1] != 0xf7 {
				i  = 2
				continue
			} else {
				return false
			}
		}
	}
	return true
}

func preNUm(data byte) int {
	var mask byte = 0x80
	var num int = 0
	//8bit中首个0bit前有多少个1bits
	for i := 0; i < 8; i   {
		if (data & mask) == mask {
			num  
			mask = mask >> 1
		} else {
			break
		}
	}
	return num
}

func isUtf8(data []byte) bool {
	i := 0
	for i < len(data) {
		if (data[i] & 0x80) == 0x00 {
			// 0XXX_XXXX
			i  
			continue
		} else if num := preNUm(data[i]); num > 2 {
			// 110X_XXXX 10XX_XXXX
			// 1110_XXXX 10XX_XXXX 10XX_XXXX
			// 1111_0XXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
			// 1111_10XX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
			// 1111_110X 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX 10XX_XXXX
			// preNUm() 返回首个字节的8个bits中首个0bit前面1bit的个数,该数量也是该字符所使用的字节数
			i  
			for j := 0; j < num-1; j   {
				//判断后面的 num - 1 个字节是不是都是10开头
				if (data[i] & 0xc0) != 0x80 {
					return false
				}
				i  
			}
		} else {
			//其他情况说明不是utf-8
			return false
		}
	}
	return true
}

学新通

结尾

代码可能不是最完美的,但是能实现想要的功能,也感谢各路大神的项目案列,也让自己有了相关代码的参考!
取之于民,用之于民!最后也欢迎各位的指教,共同交流进步!

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhhjbiee
系列文章
更多 icon
同类精品
更多 icon
继续加载