设计思路
首先读配置文件,获取配置文件的初始信息,然后用轮询的方式不断读取配置文件,如果某一次读取后配置文件发生了改变,或者变得无法读取,则返回变化后的文件(错误则nil),并且打印变更信息。
读取配置文件
ReadFile函数用于读取文件
reader:=bufio.NewReader(file);
ans:=make(map[string]string);
for {
line,err:=reader.ReadString('\n');
if err!=nil{
if err==io.EOF{
break;
}
newerr:=new (myerror);
newerr.s="文件读取错误";
e=newerr;
nret:=make(map[string]string);
return nret;
}
for i,c:=range line{
if c=='#'{
line=line[:i];
break;
}
}
var index int =-1;
for i,c:=range line{
if c=='='{
index=i;
break;
}
}
var left,right string;
if index==-1{
continue;
}else{
left=line[:index];
right=line[(index+1):];
}
left=strings.Replace(left," ","",-1)
left=strings.Replace(left,"\n","",-1)
left=strings.Replace(left,"\r","",-1)
right=strings.Replace(right," ","",-1)
right=strings.Replace(right,"\n","",-1)
right=strings.Replace(right,"\r","",-1)
ans[left]=right;
}
需要判断读取的是不是注释行,是的话就把注释部分裁剪掉。
然后判断等于号左边和右边各是什么,去掉空格,在加入到ans的map中。mao的下标是属性名,值是属性的值
ReadFile会返回一个map
定义Lintener接口与listen函数
type Listener interface{
listen(path string);
}
//承载函数需要一个结构体
type listenfunc struct{
}
//listen函数
func (lis listenfunc) listen(path string){
for {
nowmap:=ReadFile(path);
if e!=nil {fmt.Printf("%s\n",e.Error);return;}
if (len(nowmap)!=len(lastmap)){
lastmap=nowmap;
fmt.Printf("发生改变\n");
return;
}
for i,s:=range nowmap{
if s!=lastmap[i]{
lastmap=nowmap;
fmt.Printf("发生改变\n");
return;
}
}
}
}
在listen函数中对ini配置文件进行了轮询。
linten函数也可以用户自定义,默认采用的listen是如上代码中的。
if (listener==nil){//lintener未定义,采用默认listen函数
listener=new (listenfunc);
}
listener.listen(path);
如果listener已经被定义,则用户定义的优先。
自定义错误
首先我们要明白error的原型
type error interface{
Error() string
}
因此自定义错误的内容,就是重载Error函数
type myerror struct{
s string;
}
func (err myerror) Error() string{
return err.s;
}
使用如下:
newerr:=new (myerror);
newerr.s="erroe message";
fmt.Printf("%s",newerr.Error());
单元/集成测试
在Watch_test.go中测试了两个函数,Readfile读取配置文件,返回map,watch用于监听。
package watch;
import (
"testing"
)
func TestReadFile(t *testing.T){
Path:="D:\\gowork\\src\\watch\\config.ini";
file:=ReadFile(Path);
if file["host"]!="local"{
t.Errorf("ReadFile错误\n")
}
}
// D:\\gowork\\src\\watch\\config.ini
func TestWatch(t *testing.T){
Path:="D:\\gowork\\src\\watch\\config.ini";
now,err:=Watch(Path,nil);
if err!=nil {
t.Errorf("%s\n",err.Error());
return;
}
if now["port"]!="2333" {
t.Errorf("错误\n")
}
}
测试ReadFile函数,读取一个已知的文件,抽查其中的某一条信息,始终没有发现什么不同,加入空格和注释行后同理。
测试Watch函数,在监听后,手动将文件中的port值改为2333(配置文件的其它项也同理,但是需要修改代码)。监听结束后检查port值,正确。
在运行了go test watch后,检查结果:
功能测试
main函数如下:
package main
import (
"watch"
)
//D:\\gowork\\src\\watch\\config.ini
func main(){
watch.Watch("D:\\gowork\\src\\watch\\config.ini",nil);
}
文件的路径请自选
测试文件如下:
调用函数监听一个文件(文件路径自选)
这是已经展示出了文件原有的样子。
现在打开文件,进行修改(别用vscode打开,用记事本)
在中间加入注释行,在属性名和值前后加入空格:
程序并未结束,说明并没有更改。
那我们真的改变一个值:
port改为1001
结果:
正确。
再来个测试,运行:
运行后更改读取权限,为不可读取:
结果:
结果正确