go linux监测文件变化

news2024/9/22 15:36:40

go linux监测文件变化

文件改变内容有两种方式,效果一样,但执行方式有区别:

  1. 直接打开文件改,现在很多编辑器都是这样操作的
  2. 先删除原来的,再新创建写入一个替代原来的。比如vi/vim.这种方式会打断linux inotify原有的监测(就好比你有一部手机,一个人走过来给你砸了,再递给你一部同型号配置,内容备份了你原来的手机,但是新下载了个app。这时候你使用上用不出差别,但是它已经不是你原来的手机了).遇到这种情况时我们需要判断是否文件还存在,存在说明就是上述情况,然后需要重新监听文件状态

go linux监测文件变化,靠系统调用inotify.

演示代码

package main

import (
	"errors"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"unsafe"
)

type FileLink struct {
	c        chan int64
	filename string
}
type FileWatcher struct {
	linkmap     map[int32]FileLink
	link        map[string]int32
	resource_mu sync.Mutex
	fd          int
}

const WATCH_FLAG = syscall.IN_MODIFY | syscall.IN_CLOSE_WRITE

// 重新监听文件状态
func rewatch(fw *FileWatcher, wd *syscall.InotifyEvent) bool {
	finfo := fw.linkmap[wd.Wd]
	if _, err := os.Stat(finfo.filename); err != nil {
		fmt.Fprintln(os.Stderr, "not found "+finfo.filename+" "+err.Error())
		return false
	}
	fw.resource_mu.Lock()
	defer fw.resource_mu.Unlock()
	delete(fw.linkmap, wd.Wd)
	fmt.Println("rewatch " + finfo.filename)
	wid, err := syscall.InotifyAddWatch(fw.fd, finfo.filename, WATCH_FLAG)
	if wid < 0 {
		fmt.Fprintln(os.Stderr, "rewatch failed "+err.Error())
		return false
	}
	wd.Wd = int32(wid)
	fw.linkmap[wd.Wd] = finfo
	fmt.Println("rewatch " + finfo.filename + " finished")

	return true
}

func Status2String(status uint32) string {
	var ans []string
	if status&syscall.IN_MODIFY > 0 {
		ans = append(ans, "modify")
	}
	if status&syscall.IN_CLOSE_WRITE > 0 {
		ans = append(ans, "close_write")
	}
	return strings.Join(ans, " ")
}
func (s *FileWatcher) AddWatch(filename_list ...string) ([]<-chan int64, error) {
	s.resource_mu.Lock()
	defer s.resource_mu.Unlock()
	var (
		errlist  []error
		chanlist []<-chan int64
	)
	for _, name := range filename_list {
		wd, err := syscall.InotifyAddWatch(s.fd, name, WATCH_FLAG)
		if err != nil {
			errlist = append(errlist, err)
		} else {
			s.linkmap[int32(wd)] = FileLink{c: make(chan int64, 1), filename: name}
			s.link[name] = int32(wd)
			chanlist = append(chanlist, s.linkmap[int32(wd)].c)
		}
	}
	if len(errlist) > 0 {
		return chanlist, errors.Join(errlist...)
	}
	return chanlist, nil
}
func (s *FileWatcher) Delete(filename_list ...string) {
	s.resource_mu.Lock()
	defer s.resource_mu.Unlock()
	for _, name := range filename_list {
		if wd, ok := s.link[name]; ok {
			syscall.InotifyRmWatch(s.fd, uint32(wd))
			close(s.linkmap[wd].c)
			delete(s.link, name)
			delete(s.linkmap, wd)
		}
	}
}
func (s *FileWatcher) Close() error {
	return syscall.Close(s.fd)
}
func NewFileWatcher() (*FileWatcher, error) {
	var filewatcher FileWatcher
	filewatcher.linkmap = make(map[int32]FileLink)
	filewatcher.link = make(map[string]int32)
	var err error
	filewatcher.fd, err = syscall.InotifyInit()
	if err != nil {
		return nil, err
	}
	go func() {
		var (
			buff  []byte = make([]byte, 1<<16)
			size  int
			err   error
			event *syscall.InotifyEvent
		)
		for {
			size, err = syscall.Read(filewatcher.fd, buff)
			if err == nil {
				if size < syscall.SizeofInotifyEvent {
					continue
				}
				//读取到的是inotifyevent 事件数组
				for i := 0; i <= size-syscall.SizeofInotifyEvent; i += syscall.SizeofInotifyEvent {
					event = (*syscall.InotifyEvent)(unsafe.Pointer(&buff[i]))
					if event.Mask&syscall.IN_IGNORED > 0 {
						if rewatch(&filewatcher, event) {
							event.Mask -= syscall.IN_IGNORED
							if event.Mask&syscall.IN_MODIFY == 0 {
								event.Mask |= syscall.IN_MODIFY
							}
						} else {
							continue
						}
					}
					filewatcher.linkmap[event.Wd].c <- int64(event.Mask)
					// fmt.Println(filewatcher.linkmap[event.Wd].filename + " status " + Status2String(event.Mask))
				}
			} else {
				break
			}
		}
	}()
	return &filewatcher, nil
}
func main() {
	fw, err := NewFileWatcher()
	if err == nil {
		var chlist []<-chan int64
		chlist, err = fw.AddWatch("test.txt")
		if err == nil {
			ch := make(chan os.Signal, 1)
			signal.Notify(ch, os.Interrupt)
			go func() {
				<-ch
				fw.Close()
				os.Exit(0)
			}()
			for {
				status := <-chlist[0]
				fmt.Println("test.txt status " + Status2String(uint32(status)))
			}
		} else {
			fw.Close()
		}
	}
	if err != nil {
		log.Fatalln(err.Error())
	}
}

效果展示

监测vscode 更改
在这里插入图片描述

监测vim更改识别
在这里插入图片描述

需要注意的点

这里我演示只演示了修改和关闭并写入(保存),如果需要监测其它状态,syscall.IN_开头的就是mask。每个值的作用定量名已经很明确了,不明白自行google含义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1487734.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决maven远程仓库找不到问题

首先可以修改maven镜像&#xff0c;改成国内镜像 在上步行不通的情况下 可以进行下面的设置 首先jar包下载下来&#xff0c;打开maven的设置 将下面代码改成自己的实际&#xff0c;插入到3中 mvn install:install-file -Dfile{$jar包地址} -DgroupId{$jar包的groupid} -Dar…

web3时事粥报

比特币正成为更具有吸引力的通胀对冲工具 在通胀的宏观经济浪潮中&#xff0c;比特币正逐渐崭露头角&#xff0c;成为那些渴望多元化投资组合的投资者眼中的璀璨明星。Kooner 预测&#xff0c;2024年&#xff0c;各种宏观经济挑战可能进一步提升比特币、黄金和白银等资产的避险…

基于机器学习的曲面拟合方法

随着科技的不断发展&#xff0c;机器学习成为了最近最热门的技术之一&#xff0c;也被广泛应用于各个领域。其中&#xff0c;基于机器学习的曲面拟合方法也备受研究者们的关注。曲面拟合是三维模型处理中的重要技术&#xff0c;其目的是用一组数据点拟合出平滑的曲面&#xff0…

文生视频基础1:sora技术报告学习

sora技术报告学习 背景学后理解训练流程技术拆解编码解码扩散模型训练用数据 28号直播交流会后的一些想法自身的一点点想法 参考 原文地址&#xff1a;Video generation models as world simulators 背景 此项目的背景是基于Datawhale的关于sora技术文档的拆解和相关技术讲解…

安卓tcp ip通讯

废话不多说直接上代码 //权限 引入<uses-permission android:name"android.permission.ACCESS_NETWORK_STATE" /><!--允许应用程序改变网络状态--><uses-permission android:name"android.permission.CHANGE_NETWORK_STATE"/><!--允…

NumpyPython 笔记1 3.4

array.ndim 几维 array.shape 几行&#xff0c;几列 array.size 存在多少个元素 np.array 转化为矩阵 dtype 确定类型&#xff0c;并且确定精度64&#xff1f;32&#xff1f;16&#xff1f;数字越小&#xff0c;越不精确 二维 np.zeros 生成零矩阵&#xff0c;并且规…

java常用应用程序编程接口(API)——Instant,DateTimeFormatter,Period,Duration概述

前言&#xff1a; 整理下学习心得。打好基础&#xff0c;daydayup&#xff01; Instant Instant是时间线上的某个时刻/时间戳&#xff0c;通过获取Instant的对象可以拿到此刻的时间&#xff0c;该时间由两部分组成&#xff1a;1&#xff0c;从1970年1月1日00:00:00开始走到此刻…

驱动开发面试复习

创建字符设备 1 创建设备号 alloc_chrdev_region 2.创建cdev cdev_init 3.添加一个 cdev,完成字符设备注册到内核 cdev_add 4.创建类 class_create 5.创建设备 device_create 1.内核空间与用户空间数据 copy_from_user 和copy_to_user 俩个函数来完成。 copy_from_user 函数…

招聘人才小程序源码系统:多城市招聘平台+招聘会+职场咨询 带完整的搭建教程以及安装代码包

移动互联网的飞速发展&#xff0c;线上招聘已成为企业和求职者之间的重要桥梁。为了满足多城市、多行业、多岗位的招聘需求&#xff0c;以及提供一站式的求职服务&#xff0c;小编给大家分享一款“招聘人才小程序源码系统”。该系统不仅整合了多城市的招聘平台资源&#xff0c;…

ssm226基于jsp的快递管理系统的开发

** &#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;** 一 、设计说明 1.1 研究…

动态库制作

win下扩展名为.dll(dynamic linking library) linux下前缀为dll 扩展名为.so(shared object) linux 下使用动态库步骤 1&#xff0c;制作动态库&#xff0c; libmath.so 2&#xff0c;在主程序中包含动态库&#xff08;就是添加头文件的方法&#xff09; 3&#xff0c;编译…

IO 与 NIO

优质博文&#xff1a;IT-BLOG-CN 一、阻塞IO / 非阻塞NIO 阻塞IO&#xff1a;当一条线程执行read()或者write()方法时&#xff0c;这条线程会一直阻塞直到读取到了一些数据或者要写出去的数据已经全部写出&#xff0c;在这期间这条线程不能做任何其他的事情。 非阻塞NIO&…

[Java 探索之路~大数据篇] 新时代大数据流处理入门指南

本文主要介绍大数据基础&#xff0c;以及 flink 流计算 文章目录 【基础知识】1. 批处理与流处理1.批处理2.流处理 2. 为什么需要一个优秀的流处理框架1. 股票交易的业务场景2.生产者——消费者模型3. 流处理框架要解决的诸多问题&#xff08;1&#xff09;可扩展性&#xff08…

JS 对象数组排序方法测试

输出 一.Array.prototype.sort() 1.默认排序 sort() sort() 方法就地对数组的元素进行排序&#xff0c;并返回对相同数组的引用。默认排序是将元素转换为字符串&#xff0c;然后按照它们的 UTF-16 码元值升序排序。 由于它取决于具体实现&#xff0c;因此无法保证排序的时…

将六西格玛设计融入汽车制造:实践之路

在快节奏的现代生活中&#xff0c;汽车早已不再仅仅是一种交通工具&#xff0c;而是成为了展现个性、追求品质生活的重要象征。为了满足消费者日益增长的品质需求&#xff0c;汽车制造商们纷纷将目光投向了六西格玛设计这一先进的质量管理方法。那么&#xff0c;如何将六西格玛…

现在如何才能开通微信公众号留言功能?

为什么公众号没有留言功能&#xff1f;2018年2月12日之后直到现在&#xff0c;新注册公众号的运营者会发现一个问题&#xff1a;无论是个人还是企业的公众号&#xff0c;在后台都找不到留言功能了。这对公众号来说绝对是一个极差的体验&#xff0c;少了一个这么重要的功能&…

AWS的S3存储桶设置生命周期规则

业务场景&#xff1a;周期性备份数据到s3存储桶&#xff0c;设置定期删除&#xff0c;只保留一定周期内的存储数据&#xff0c;节省存储空间减少花费 1. 点击存储桶选择管理--->创建生命周期规则 2. 设置名称等参数 点击创建即可

VUE实现Office文档在线编辑,支持doc/docx、xls/xlsx、ppt/pptx、pdf等

1.微软提供的在线Office预览&#xff08;只能预览&#xff0c;不能编辑&#xff09; https://view.officeapps.live.com/op/view.aspx?src服务器上文档地址&#xff08;http开头&#xff09; 2.国内在线Office方案&#xff1a; 腾讯文档、石墨文档、飞书 优势&#xff1a;跨…

光路科技:工业以太网交换机引领工业互联网新篇章

随着全球范围内工业4.0的浪潮不断涌动&#xff0c;工业互联网作为其核心驱动力&#xff0c;正引领着工业生产向智能化、网络化的崭新阶段迈进。在这一转型的浪潮中&#xff0c;光路科技凭借其卓越的工业互联设备与创新解决方案&#xff0c;正为工业互联网领域的发展注入新的活力…

Unity 常用的4种灯光、制作镜子、灯光的调用修改数值、

创建灯光时&#xff0c;一般用4种&#xff1a;定向光、点光源、聚光、区域光、 定向光&#xff1a;太阳 点光源&#xff1a;灯泡 聚光灯&#xff1a;手电筒 区域光&#xff1a;烘焙-贴图 灯光选择已烘焙 需要先选择被烘焙的物体&#xff0c;然后再选择Contribute GI 等待进…