download
下载 https://go.dev/dl/go1.21.3.windows-amd64.msi
双击安装。
测试验证
>go version
go version go1.21.3 windows/amd64
goland 只能免费使用 30 天,有免费的 go 开发工具吗
是的,Go语言有一些免费的开发工具可供使用。以下是一些常用的免费Go开发工具:
-
Visual Studio Code(VS Code):这是一款免费的轻量级代码编辑器,支持多种编程语言,包括Go语言。它具有丰富的插件生态系统,可以通过安装Go插件来提供对Go语言的支持。
-
LiteIDE:这是一款专为Go语言开发设计的开源集成开发环境(IDE)。它提供了一系列功能,如代码补全、调试器、项目管理等,可以帮助你更高效地开发Go应用程序。
-
Sublime Text:这是一款流行的文本编辑器,也可以用于Go语言开发。虽然它的免费版本有限制,但你可以购买许可证解锁更多功能。
-
Atom:这是一款免费的开源文本编辑器,支持多种编程语言,包括Go语言。它具有丰富的插件和主题,可以根据个人喜好进行定制。
这些免费的Go开发工具都提供了基本的代码编辑和调试功能,可以满足大多数Go开发者的需求。你可以根据个人偏好选择适合自己的工具进行Go语言开发。
如何通过 go 实现一个监听指定文件夹文件变化,并获取变化内容的程序?类似于 filebeta
1. 安装依赖包
go get github.com/fsnotify/fsnotify
报错1
$ go get github.com/fsnotify/fsnotify
go: go.mod file not found in current directory or any parent directory.
'go get' is no longer supported outside a module.
To build and install a command, use 'go install' with a version,
like 'go install example.com/cmd@latest'
For more information, see https://golang.org/doc/go-get-install-deprecation
or run 'go help get' or 'go help install'.
原因:
如果你在使用 Go 1.11 或更高版本,并且没有使用 Go Modules,那么你可能会遇到 “go get” 不再支持的问题。在这种情况下,你可以尝试以下解决方法:
-
进入你的项目目录:在终端中,使用
cd /your/project/directory
命令进入你的项目目录。 -
初始化 Go Modules:运行
go mod init
命令来初始化 Go Modules。这将创建一个 go.mod 文件。 -
使用 Go Modules 来获取包:使用
go get
命令获取你所需的包,例如go get github.com/fsnotify/fsnotify
。 -
更新你的代码:在你的代码中,使用
import
语句导入所需的包。
这样,你就可以在 Go Modules 环境中解决 “go get” 不再支持的问题。希望这可以帮到你!如有任何疑问,请随时提问。
报错 2
$ go mod init
go: cannot determine module path for source directory D:\gocode\logcollect (outside GOPATH, module path must be specified)
Example usage:
'go mod init example.com/m' to initialize a v0 or v1 module
'go mod init example.com/m/v2' to initialize a v2 module
Run 'go help mod init' for more information.
这个错误信息是由于在 Go Modules 环境中,无法确定模块的路径。这通常发生在你的代码目录不在 GOPATH 中时。
为了解决这个问题,你可以按照错误信息中提供的示例使用 go mod init
命令来初始化一个模块。你可以根据你的实际情况选择不同的模块路径。
例如,如果你的代码目录是 D:\gocode\logcollect
,你可以运行以下命令来初始化一个 v0 或 v1 模块:
go mod init example.com/m
或者,如果你想初始化一个 v2 模块,你可以运行以下命令:
go mod init example.com/m/v2
这样,你就可以为你的代码创建一个模块,并解决这个错误。希望这可以帮到你!如有任何疑问,请随时提问。
v0 或 v1 模块,和 v2 模块有什么区别?作用是什么
在 Go Modules 中,模块版本通常遵循语义化版本控制(Semantic Versioning)规范。
v0 或 v1 模块是指在初始化模块时使用的版本,而 v2 模块是指在初始化模块时使用的 v2 版本。
v0 或 v1 模块:
- 这些模块是在 Go Modules 刚开始引入时创建的。
- 它们使用的是 v0 或 v1 的版本控制规范。
- 当你使用
go mod init example.com/m
初始化模块时,默认创建的是 v0 或 v1 模块。 - 这些模块的版本号通常遵循
vX.Y.Z
的格式,其中 X、Y 和 Z 分别表示主版本号、次版本号和修订号。
v2 模块:
- v2 模块是在 v0 或 v1 模块的基础上进行的重大修改或重构。
- 它们使用的是 v2 版本控制规范。
- 当你使用
go mod init example.com/m/v2
初始化模块时,创建的是 v2 模块。 - v2 模块的版本号通常遵循
v2.Y.Z
的格式,其中 Y 和 Z 分别表示次版本号和修订号。
区别:
- v0 或 v1 模块和 v2 模块在版本控制规范和版本号的格式上有所不同。
- v2 模块通常用于在 v0 或 v1 模块的基础上进行重大修改或重构,以避免破坏现有的依赖关系。
模块的作用:
- 模块是 Go Modules 的核心概念,用于管理代码的依赖关系和版本控制。
- 它们允许你明确指定你的代码所依赖的其他模块,并确保这些依赖关系的版本是可控的。
- 模块还可以帮助你更好地管理和共享你的代码,使其更易于维护和部署。
希望这可以解答你的问题!如果还有其他疑问,请随时提问。
我们根据提示,输入:
go mod init example.com/m
日志如下:
$ go mod init example.com/m
go: creating new go.mod: module example.com/m
go: to add module requirements and sums:
go mod tidy
2. 继续执行安装
然后继续安装 fsnotify 依赖
go get github.com/fsnotify/fsnotify
这个命令的含义
go get github.com/fsnotify/fsnotify
是一个用于获取第三方包或库的 Go 命令。
具体来说,这个命令的作用是从远程代码仓库(例如 GitHub)中下载并安装 github.com/fsnotify/fsnotify
这个包。
该包是一个用于监听文件系统事件的 Go 包,可以用于监视文件或文件夹的变化。
执行 go get
命令后,Go 工具链会自动下载指定包的源代码,并将其安装到你的 GOPATH 或 Go Modules 中,使你可以在自己的项目中导入和使用该包。
例如,在你的 Go 代码中,你可以使用以下方式导入 github.com/fsnotify/fsnotify
包:
import "github.com/fsnotify/fsnotify"
然后,你就可以使用该包提供的功能来监听文件系统事件,如文件的创建、修改、删除等。
总结一下, go get
命令的作用是方便地获取和安装第三方包或库,使你可以在自己的项目中使用这些包来扩展功能。
安装报错
$ go get github.com/fsnotify/fsnotify
go: module github.com/fsnotify/fsnotify: Get "https://proxy.golang.org/github.com/fsnotify/fsnotify/@v/list": dial tcp 142.251.43.17:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
错误原因:
具体原因:默认go的代理网站是 GOPROXY=https://proxy.golang.org,direct
,是一个外网地址,国内访问不到,因此我们需要修改代理网站。
解决:使用命令
go env -w GOPROXY=https://goproxy.cn,direct
更改代理网站,然后再重新执行go get命令即可成功download了。
成功的安装日志如下:
$ go get github.com/fsnotify/fsnotify
go: downloading github.com/fsnotify/fsnotify v1.7.0
go: downloading golang.org/x/sys v0.4.0
go: added github.com/fsnotify/fsnotify v1.7.0
go: added golang.org/x/sys v0.4.0
编写代码
要通过Go实现一个监听指定文件夹文件变化并获取变化内容的程序,你可以使用 fsnotify
包来实现。下面是一个示例代码:
package main
import (
"log"
"os"
"path/filepath"
"github.com/fsnotify/fsnotify"
)
func main() {
// 创建一个新的文件系统监视器
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// 指定要监听的文件夹路径
dirPath := "D:\\logsdata"
// 使用 filepath 包中的 Walk 函数,遍历文件夹中的所有文件,并将它们添加到监视器中
err = filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
err = watcher.Add(path)
if err != nil {
log.Println(err)
}
}
return nil
})
if err != nil {
log.Fatal(err)
}
// 启动一个无限循环来监听文件事件
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
log.Println("事件:", event)
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("错误:", err)
}
}
}
简单解释
在这个示例代码中,我们使用 fsnotify
包来创建一个文件监视器。通过调用 NewWatcher
函数创建一个新的监视器实例,并使用 Add
函数添加要监听的文件夹。
然后,我们启动一个goroutine来处理文件变化事件。在事件处理函数中,我们检查事件类型是否为文件写入操作 fsnotify.Write
,如果是,我们可以读取变化的文件内容并进行处理。
最后,我们使用一个无缓冲通道 done
来阻塞主goroutine,以确保程序一直运行。
请注意,你需要将 "path/to/folder"
替换为你要监听的实际文件夹路径。希望这对你有所帮助!
运行代码
编译
go build
得到结果
$ ls
go.mod go.sum m.exe* main.go
运行
这个程序需要提前创建一个文件,比如 1.txt。
然后我们启动程序:
./m.exe
测试
我们修改文件内容,日志信息如下:
$ ./m.exe
2023/11/01 22:43:07 事件: WRITE "D:\\logsdata\\1.txt"
2023/11/01 22:43:07 事件: WRITE "D:\\logsdata\\1.txt"
2023/11/01 22:43:11 事件: WRITE "D:\\logsdata\\1.txt"
2023/11/01 22:43:11 事件: WRITE "D:\\logsdata\\1.txt"
2023/11/01 22:43:30 事件: WRITE "D:\\logsdata\\1.txt"
2023/11/01 22:43:30 事件: WRITE "D:\\logsdata\\1.txt"
v2
需求说明
如何修改上面的代码,让其支持监听文件夹下所有文件的新建和删除?
修改后的代码如下:
package main
import (
"log"
"os"
"github.com/fsnotify/fsnotify"
)
func main() {
// 创建一个新的文件系统监视器
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
// 指定要监听的文件夹路径
dirPath := "D:\\logsdata"
log.Println("开始处理文件夹:", dirPath)
// 递归遍历文件夹及其子文件夹,并将它们添加到监视器中
err = watchDir(dirPath, watcher)
if err != nil {
log.Fatal(err)
}
// 启动一个无限循环来监听文件事件
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
log.Println("事件:", event)
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("错误:", err)
}
}
}
// 递归遍历文件夹及其子文件夹,并将它们添加到监视器中
func watchDir(dirPath string, watcher *fsnotify.Watcher) error {
err := watcher.Add(dirPath)
if err != nil {
return err
}
// 打开文件夹
dir, err := os.Open(dirPath)
if err != nil {
return err
}
defer dir.Close()
// 读取文件夹中的所有文件和子文件夹
fileInfos, err := dir.Readdir(-1)
if err != nil {
return err
}
// 遍历文件夹中的文件和子文件夹
for _, fileInfo := range fileInfos {
// 如果是子文件夹,则递归调用 watchDir 函数
if fileInfo.IsDir() {
subDirPath := dirPath + "/" + fileInfo.Name()
err = watchDir(subDirPath, watcher)
if err != nil {
log.Println(err)
}
} else {
// 如果是文件,则将其添加到监视器中
filePath := dirPath + "/" + fileInfo.Name()
err = watcher.Add(filePath)
if err != nil {
log.Println(err)
}
}
}
return nil
}
测试效果
我们在文件夹下进行删除、新建、内容修改。
得到的监听日志如下:
$ ./m.exe
2023/11/01 22:51:12 开始处理文件夹: D:\logsdata
2023/11/01 22:51:17 事件: CREATE "D:\\logsdata\\新建文本文档.txt"
2023/11/01 22:51:18 事件: RENAME "D:\\logsdata\\新建文本文档.txt"
2023/11/01 22:51:18 事件: CREATE "D:\\logsdata\\5.txt"
2023/11/01 22:51:23 事件: REMOVE "D:\\logsdata\\4.txt"
2023/11/01 22:51:23 事件: REMOVE "D:\\logsdata\\4.txt"
2023/11/01 22:51:27 事件: REMOVE "D:\\logsdata\\3.txt"
2023/11/01 22:51:27 事件: REMOVE "D:\\logsdata\\3.txt"
2023/11/01 22:51:33 事件: WRITE "D:\\logsdata\\5.txt"
2023/11/01 22:51:33 事件: WRITE "D:\\logsdata\\5.txt"
V3-如何获取当前的具体操作类型
chat1-详细介绍一下文件变更后,接收到的 event 有哪些属性?
在使用 fsnotify 包监听文件变更时,你会收到不同类型的事件,每个事件都有一些属性提供有关变更的详细信息。
以下是 fsnotify 包中常见事件的属性:
- Create(创建文件或文件夹):
- Name: 被创建的文件或文件夹的名称。
- Op: 指示操作类型为创建。
- Write(写入文件):
- Name: 被写入的文件的名称。
- Op: 指示操作类型为写入。
- Remove(删除文件或文件夹):
- Name: 被删除的文件或文件夹的名称。
- Op: 指示操作类型为删除。
- Rename(重命名文件或文件夹):
- OldName: 被重命名的文件或文件夹的旧名称。
- NewName: 被重命名的文件或文件夹的新名称。
- Op: 指示操作类型为重命名。
- Chmod(修改文件权限):
- Name: 被修改权限的文件或文件夹的名称。
- Op: 指示操作类型为权限修改。
这些事件属性可以帮助你确定发生了哪种类型的文件变更,并提供有关变更的更多细节。
你可以根据需要使用这些属性来处理文件变更事件。
chat2-如何获取 Op
在 fsnotify 包中,当监听到文件事件后,你可以通过访问 event.Op 属性来获取对应的操作类型(Op)。
event.Op 是一个 fsnotify.Op 类型的常量,表示文件事件的操作类型。
以下是一些常见的操作类型以及它们的含义:
- fsnotify.Create : 文件或文件夹被创建。
- fsnotify.Write : 文件被写入。
- fsnotify.Remove : 文件或文件夹被删除。
- fsnotify.Rename : 文件或文件夹被重命名。
- fsnotify.Chmod : 文件或文件夹的权限被修改。
代码调整
// 启动一个无限循环来监听文件事件
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
switch event.Op {
case fsnotify.Create:
fmt.Println("文件或文件夹被创建:", event.Name)
case fsnotify.Write:
fmt.Println("文件被写入:", event.Name)
case fsnotify.Remove:
fmt.Println("文件或文件夹被删除:", event.Name)
case fsnotify.Rename:
fmt.Println("文件或文件夹被重命名:", event.Name)
case fsnotify.Chmod:
fmt.Println("文件或文件夹权限被修改:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("错误:", err)
}
}
测试
此时我们修改文件内容,得到的日志如下:
$ ./m.exe
2023/11/01 23:03:52 开始处理文件夹: D:\logsdata
文件被写入: D:\logsdata\2.txt
文件被写入: D:\logsdata\2.txt
文件被写入: D:\logsdata\2.txt
文件被写入: D:\logsdata\2.txt
v4-获取变更文件的内容
说明
在知道文件内容变化之后,我们如何获取文件的内容呢?
chat1-go 如何根据文件路径,获取文件内容?指定文件编码格式为 UTF-8
在 Go 中,你可以使用 ioutil.ReadFile
函数来根据文件路径获取文件内容。
以下是一个示例代码,它演示了如何根据文件路径读取文件内容并将其解析为 UTF-8 编码的文本:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
filePath := "/path/to/file.txt"
content, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Println("无法读取文件:", err)
return
}
text := string(content)
fmt.Println("文件内容:", text)
}
在上面的代码中,你需要将 "/path/to/file.txt"
替换为你要读取的文件的实际路径。
代码将使用 ioutil.ReadFile
函数读取文件内容,并将其存储在 content
变量中。
然后,使用 string
函数将字节切片转换为字符串,并将其存储在 text
变量中。
最后,将文件内容打印出来。
请注意, ioutil.ReadFile
函数将文件内容作为字节切片返回。
如果你需要以其他格式解析文件内容,例如 JSON 或 XML,你需要使用相应的库进行解析。
调整代码
我们添加一个读取文件内容的方法:
//默认以 UTF-8 的编码读取文件内容
func getFileContent(filePath string) string {
content, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Println("无法读取文件:", err)
return "";
}
text := string(content)
return text;
}
然后在文件变更事件的时候,读取文件内容:
case fsnotify.Write:
fmt.Println("文件被写入:", event.Name)
// 获取文件内容
writeContent := getFileContent(event.Name);
fmt.Println("文件被写入后的内容:", writeContent)
测试效果
我们编辑一个文件,得到的变更效果如下:
$ ./m.exe
2023/11/01 23:11:57 开始处理文件夹: D:\logsdata
文件被写入: D:\logsdata\2.txt
文件被写入后的内容: 11111哈哈哈哈
文件被写入: D:\logsdata\2.txt
文件被写入后的内容: 11111哈哈哈哈
文件被写入: D:\logsdata\2.txt
文件被写入后的内容: 11111哈哈哈哈
文件被写入: D:\logsdata\2.txt
文件被写入后的内容: 11111哈哈哈哈
文件被写入: D:\logsdata\2.txt
文件被写入后的内容: 11111哈哈哈哈顶顶顶顶
文件被写入: D:\logsdata\2.txt
文件被写入后的内容: 11111哈哈哈哈顶顶顶顶
文件被写入: D:\logsdata\2.txt
文件被写入后的内容: 11111哈哈哈哈顶顶顶顶
文件被写入: D:\logsdata\2.txt
文件被写入后的内容: 11111哈哈哈哈顶顶顶顶
v5-如何过滤多次监听触发的问题?
说明
发现上面的监听方法,在文件保存时,会收到多次文件的 write 事件,为什么?
chat:
当文件保存时,你可能会收到多次文件的写入事件( `fsnotify.Write` )。
这是由于不同的编辑器或操作系统在保存文件时的行为不同,可能会导致多个写入事件的触发。
一种常见的情况是,当你在编辑器中保存文件时,编辑器可能会执行多个写入操作。
例如,当你保存文件时,编辑器可能会首先将文件的内容截断为空,然后再将新的内容写入文件。这样的行为可能会导致多个写入事件的触发。
此外,某些操作系统也可能会在保存文件时执行类似的行为,导致多个写入事件的触发。
为了处理这种情况,你可以在代码中添加一些逻辑来过滤重复的写入事件,只处理最后一次写入事件。
你可以使用一个定时器来延迟处理事件,以确保在一段时间内没有更多的写入事件发生后再处理。
希望这个解答对你有帮助!如果还有其他问题,请随时提问。
chat1-定时器解决方案
结合上面的代码,以下是一个简单的去重重复写入事件的过滤代码示例:
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"log"
"time"
)
func main() {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
dirPath := "/path/to/folder"
err = watcher.Add(dirPath)
if err != nil {
log.Fatal(err)
}
// 定义一个定时器,用于延迟处理事件
timer := time.NewTimer(500 * time.Millisecond)
defer timer.Stop()
// 定义一个用于存储最后一次写入事件的变量
var lastWriteEvent *fsnotify.Event
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
// 如果事件类型为写入,并且定时器还在运行中,则重置定时器
if event.Op == fsnotify.Write && !timer.Stop() {
<-timer.C
}
// 如果事件类型为写入,并且与最后一次写入事件不同,则处理事件
if event.Op == fsnotify.Write && lastWriteEvent != nil && event.Name != lastWriteEvent.Name {
processEvent(event)
}
// 更新最后一次写入事件
if event.Op == fsnotify.Write {
lastWriteEvent = &event
// 启动定时器,延迟处理事件
timer.Reset(500 * time.Millisecond)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("错误:", err)
}
}
}
func processEvent(event fsnotify.Event) {
fmt.Println("处理事件:", event)
// 在这里添加你希望执行的处理逻辑
}
在上面的代码中,我们添加了一个定时器和一个变量来存储最后一次写入事件。
当收到写入事件时,我们首先检查定时器是否还在运行中,如果是,则重置定时器以延迟处理事件。
然后,我们检查当前写入事件是否与最后一次写入事件不同,如果是,则处理事件。
最后,我们更新最后一次写入事件,并启动定时器以延迟处理事件。
这样,重复的写入事件将被过滤掉,只有最后一次写入事件会被处理。
chat2-根据时间间隔处理
当涉及到去重重复写入事件时,还有其他一些更加优雅和简单的方式。
以下是一个示例代码,它通过使用时间戳来判断写入事件的时间间隔,以过滤掉重复的写入事件:
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"log"
"time"
)
func main() {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
dirPath := "/path/to/folder"
err = watcher.Add(dirPath)
if err != nil {
log.Fatal(err)
}
// 定义一个用于存储最后一次写入事件的时间戳
var lastWriteTime time.Time
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
// 如果事件类型为写入,并且距离上次写入事件超过500毫秒,则处理事件
if event.Op == fsnotify.Write && time.Since(lastWriteTime) > 500*time.Millisecond {
processEvent(event)
lastWriteTime = time.Now()
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("错误:", err)
}
}
}
func processEvent(event fsnotify.Event) {
fmt.Println("处理事件:", event)
// 在这里添加你希望执行的处理逻辑
}
在这个示例代码中,我们使用一个变量 lastWriteTime
来存储最后一次写入事件的时间戳。
当收到写入事件时,我们首先检查距离上次写入事件的时间间隔是否超过了500毫秒,如果是,则处理事件并更新 lastWriteTime
。
这种方式更加简单,通过时间间隔来判断重复事件,避免了使用定时器的复杂性。
希望这个示例代码能满足你的需求!如果还有其他问题,请随时提问。
代码调整
我们结合上面的代码,决定使用 map 来保存每一个文件的最后修改时间。
map 的创建
go 如何创建一个 map 数据结构,key 是 string, value 是一个 long 时间戳。
在 Go 中,你可以使用内置的 map
数据结构来创建一个映射,其中 key 是字符串类型,value 是一个长整型(时间戳)。
以下是一个示例代码,演示了如何创建和使用这样的 map
数据结构:
package main
import (
"fmt"
"time"
)
func main() {
// 创建一个 map,key 是字符串,value 是长整型(时间戳)
timestamps := make(map[string]int64)
// 添加键值对到 map 中
timestamps["key1"] = time.Now().Unix()
timestamps["key2"] = time.Now().Unix()
// 读取 map 中的值
value1 := timestamps["key1"]
value2 := timestamps["key2"]
// 打印值
fmt.Println("key1 对应的时间戳:", value1)
fmt.Println("key2 对应的时间戳:", value2)
}
在上面的示例代码中,我们使用 make
函数创建了一个 map
数据结构,其中 key 是字符串类型,value 是长整型(时间戳)。
然后,我们通过使用键来给 map
赋值,并使用键来获取相应的值。
代码调整
我们通过一个 map 记录每一个文件和对应的修改时间。
然后计算差值,小于 50ms 则不做内容变化输出:
//create map save data
fileUpdateTimes := make(map[string]int64)
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
switch event.Op {
case fsnotify.Create:
fmt.Println("文件或文件夹被创建:", event.Name)
case fsnotify.Write:
fmt.Println("文件被写入:", event.Name)
// 存放修改的时间
lastTimeMs := fileUpdateTimes[event.Name];
currentTimeMs := getTimeMs();
if(lastTimeMs != 0) {
diffTimeMs := currentTimeMs - lastTimeMs;
fmt.Println("diffTimeMs:", diffTimeMs)
if(diffTimeMs <= 50) {
break;
}
}
// update lastTime
fmt.Println("update time:", currentTimeMs)
fileUpdateTimes[event.Name] = currentTimeMs;
// 获取文件内容
writeContent := getFileContent(event.Name);
fmt.Println("文件被写入后的内容:", writeContent)
case fsnotify.Remove:
fmt.Println("文件或文件夹被删除:", event.Name)
case fsnotify.Rename:
fmt.Println("文件或文件夹被重命名:", event.Name)
case fsnotify.Chmod:
fmt.Println("文件或文件夹权限被修改:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("错误:", err)
}
}
func getTimeMs() int64 {
return time.Now().UnixNano() / int64(time.Millisecond);
}
测试
我们再次测试文件的内容变更,日志如下:
$ ./m.exe
2023/11/01 23:42:29 开始处理文件夹: D:\logsdata
文件被写入: D:\logsdata\2.txt
update time: 1698853354304
文件被写入后的内容: 11111哈哈哈哈顶顶顶顶对对对对对dddddddddddddddddd
文件被写入: D:\logsdata\2.txt
diffTimeMs: 1
文件被写入: D:\logsdata\2.txt
diffTimeMs: 1
文件被写入: D:\logsdata\2.txt
diffTimeMs: 1
文件被写入: D:\logsdata\2.txt
diffTimeMs: 8146
update time: 1698853362450
文件被写入后的内容: 11111哈哈哈哈顶顶顶顶对对对对对dddddddddddddddddddddd
文件被写入: D:\logsdata\2.txt
diffTimeMs: 1
文件被写入: D:\logsdata\2.txt
diffTimeMs: 1
文件被写入: D:\logsdata\2.txt
diffTimeMs: 1
文件被写入: D:\logsdata\2.txt
diffTimeMs: 8180
update time: 1698853370630
文件被写入后的内容: 11111哈哈哈哈顶
可以看到触发了多次文件的写入动作,但是只有超过一定的时间,我们才输出对应的文件内容。
v6-文件编码问题
说明
默认我们的方法是 utf-8 的,如果我们是其他的编码怎么办?
比如我们创建一个 gb2313 的文件。
输入内容:
你好啊,我的老伙计。
这时候输出是:
文件被写入后的内容: ▒▒ð▒▒▒▒ҵ▒▒ϻ▒ơ▒
指定编码读取内容
chat-如何指定编码?
导入包
"github.com/axgle/mahonia"
方法调整
//默认以 UTF-8 的编码读取文件内容
func getFileContent(filePath string) string {
// 默认编码
content, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Println("无法读取文件:", err)
return "";
}
text := string(content)
// 指定其他编码, 转 GBK
if(filePath == "D:\\logsdata\\gbk.txt") {
text = mahonia.NewDecoder("gbk").ConvertString(text)
}
return text;
}
install
go get github.com/axgle/mahonia
这个时候在测试 GBK 文件,编码如下:
文件被写入: D:\logsdata\gbk.txt
update time: 1698855304939
文件被写入后的内容: 你好啊,我的老伙计。
ddd
参考资料
chat
https://www.codingdict.com/questions/63128
https://blog.csdn.net/weixin_33915554/article/details/91869462
https://juejin.cn/s/golang%20%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6%E4%B9%B1%E7%A0%81
https://blog.csdn.net/kkx12138/article/details/87927175
https://www.zongscan.com/demo333/28308.html