实现的功能:监控.rss文件变化(删除、重命名、内容变化) 并且处理为对应的.css文件
本人工作是web前端。less和sass的css预处理概念是非常好的,自己尝试了一下
测试效果图:
自己列的一个简单需求列表
功能要求:
√ 1.监控文件列表控件 列出需要监控的文件列表
√ 要求有右键删除功能
√ 休眠状态?文件在列表中 但暂时不进行监控
√ 2.隐藏到托盘功能 一定要注意NotifyIcon的icon属性要选一张图不然没效果!!!
× 3.添加监控文件功能 批量功能要不要? 一个一个加吧
√ 4.把rss文件编译为css文件
√ *5.@引入文件功能 引入变量文件
√ 6.注释功能
√ 7.全部重新生成
格式定义:
√ 1.引入的文件中不得包含@文件(有也没作用) 因为不同于其他高级程序 css无需多级包含 把需要的复制过来 成为单独文件更方便
√ 2.一个变量 形如 $xxx : ... ;
√ $与变量名间不得有空格
√ 分号和冒号左右可以有空格
√ 支持一行多个变量
√ 3.只支持#开始的单行注释#
√ 4.使用方式 ($xxx) 或者 $xxx[^a-zA-Z0-9\-_]
√ 5.分号是关键字即使是url的字符串也不能使用
新类
变量定义:
√ string inipath;// 配置文件的目录
√ List<string> filelist = new List<string>();//要监控的文件列表
√ List<FileSystemWatcher> watchs = new List<FileSystemWatcher>();//根据filelist获取对应的目录
增
√ void addOne(string filepath) //处理添加的每一个需要监控文件
删
√ void deleteOne(string filepath)
改
√ void alterOne(string filepath) //主要针对文件的重命名
文件监控函数
√ OnFileRenamed(){rss2css(e.FullPath.ToString());} 还得调用alterOne函数
√ OnFileChanged(){rss2css(e.FullPath.ToString());}
√ OnFileDeleted() 调用deleteOne函数
√ void readini(string filepath) //读配置文件
√ void writeini(string filepath)//程序关闭时写配置文件
//根据rss文件路径编译文件生成css文件 依赖string preprocess(string text)
√ void rss2css(string rssPath)
//编译内容
√ string preprocess(string text)
界面:
√ 增加按钮:根据textBox调用addOne
√ 列表控件:显示filelist文件列表 允许右键删除事件(调用deleteOne)
托盘事件:
√ 退出函数
主要引用:
using System.Text.RegularExpressions;//正则
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;//json 要求framework4.5 要下载对应dll
这个watch.cs是一个类基本重要的函数都在这里
winform中会调用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;//FileWatch 文件读写
using System.Text.RegularExpressions;//正则
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;//json
namespace css_var2
{
class Watchers
{
#region 成员变量
//要编译的文件
public List<string> files;
//要监控的文件夹
private List<FileSystemWatcher> folderWatchers;
#endregion
//构造函数
public Watchers()
{
files = new List<string>();
folderWatchers = new List<FileSystemWatcher>();
}
#region 成员方法
//读配置文件
public void readini(string filepath)
{
//配置文件保存之前需要监视的文件列表
if (!File.Exists(filepath))
{
File.Create(filepath).Dispose();
}
else
{
FileStream fs = new FileStream(filepath, FileMode.Open);
StreamReader m_streamReader = new StreamReader(fs);
m_streamReader.BaseStream.Seek(0, SeekOrigin.Begin);// 从数据流中读取每一行,直到文件的最后一行
string temp = "";
temp = m_streamReader.ReadLine();
while (temp != null)
{
addOne(temp);
temp = m_streamReader.ReadLine();
}
m_streamReader.Close();
fs.Close();
//fs.Dispose();
}
}
//程序关闭时写配置文件
public void writeini(string filepath)
{
//清空
FileStream fs1 = new FileStream(filepath, FileMode.Create, FileAccess.Write);
fs1.SetLength(0);
fs1.Close();
//fs1.Dispose();
//重写
StreamWriter sw = new StreamWriter(filepath, true, Encoding.UTF8);
for (int i = 0; i < files.Count; i++)
{
if (File.Exists(files[i]))
sw.WriteLine(files[i]);
}
sw.Flush();
sw.Close();
}
//暂停监视功能
public void startpause(bool bPause)
{
int n = folderWatchers.Count;
for (int i = 0; i < n; i++)
{
folderWatchers[i].EnableRaisingEvents = bPause;
}
}
//添加一个要编译的文件
public void addOne(string filepath)
{
bool bFound = false;
string temp = Path.GetExtension(filepath);
int n=0;
bFound = File.Exists(filepath);
//要监控的文件必须存在 而且是自定义格式的rss拓展名
if (bFound && temp.ToLower() == ".rss")
{
//检查文件是否已经加入过
bFound = false;
n = files.Count;
for (int i = 0; i < n; i++)
{
if (filepath == files[i])
{
bFound = true;
break;
}
}
if (bFound == false)
{
//每加入一个新文件:文件列表添加文件名
files.Add(filepath);
//新加入的文件 的父目录是否已经进行了监视
n = folderWatchers.Count;
temp = Path.GetDirectoryName(filepath);
for (int i = 0; i < n; i++)
{
if (temp == folderWatchers[i].Path)
{
bFound = true;
break;
}
}
if (bFound == false)
{
FileSystemWatcher w = new FileSystemWatcher();
w.Path = temp;
w.Filter = "*.rss";
w.EnableRaisingEvents = true;
w.IncludeSubdirectories = false;
w.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
w.Changed += OnFileChanged;
w.Renamed += OnFileRenamed;
w.Deleted += OnFileDelete;
folderWatchers.Add(w);
}
}
}
}
//删除一个要编译文件
public void deleteOne(string filepath)
{
int n = folderWatchers.Count,
l = files.Count;
/*
string temp = Path.GetDirectoryName(filepath);
for (int i = 0; i < n; i++)
{
if (folderWatchers[i].Path == temp)
{
folderWatchers.RemoveAt(i);
break;
}
}
*/
for (int i = 0; i < l; i++)
{
if (files[i] == filepath)
{
files.RemoveAt(i);
break;
}
}
}
//修改一个要编译文件的路径
public void alterOne(string oldpath,string filepath)
{
int n = files.Count,
l = folderWatchers.Count;
string tempNew = Path.GetDirectoryName(filepath),
tempOld = Path.GetDirectoryName(oldpath);
for (int i = 0; i < n; i++)
{
if (files[i] == oldpath)
{
files[i] = filepath;
break;
}
}
for (int i = 0; i < l; i++)
{
if (folderWatchers[i].Path == tempOld)
{
folderWatchers[i].Path = tempNew;
break;
}
}
}
//文件或目录重命名事件
private void OnFileRenamed(object sender, RenamedEventArgs e)
{
//重新编译
rss2css(e.FullPath.ToString());
//修改监控对象的路径
alterOne(e.OldFullPath.ToString(), e.FullPath.ToString());
}
//文件更改事件
private void OnFileChanged(object sender, FileSystemEventArgs e)
{
//文件发生变化 重新编译生成文件
rss2css(e.FullPath.ToString());
}
//文件删除事件
private void OnFileDelete(object sender, FileSystemEventArgs e)
{
//删除监控对象
deleteOne(e.FullPath.ToString());
}
//文件生成 - 调用preprocess函数将指定位置的rss文件编译 在同目录下生成css文件
public void rss2css(string rssPath)
{
string temp = "",
res = "",
cssPath = Path.GetDirectoryName(rssPath) + "\\" + Path.GetFileNameWithoutExtension(rssPath) + ".css";
bool bInFiles = false;
for (int i = 0; i < files.Count; i++)
{
if (files[i] == rssPath)
{
bInFiles = true;
break;
}
}
if (bInFiles)
{
//读取
try
{
temp = File.ReadAllText(rssPath);
}
catch (Exception ee0)
{
}
if (File.Exists(cssPath) == false)
{
File.Create(cssPath).Dispose();
}
//写入
try
{
//清空
FileStream fs1 = new FileStream(cssPath, FileMode.Create, FileAccess.Write);
fs1.SetLength(0);
fs1.Close();
//重写
StreamWriter sw = new StreamWriter(cssPath, true, Encoding.UTF8);
res = preprocess(temp);
sw.Write(res);
sw.Flush();
sw.Close();
}
catch (Exception ee)
{
}
}
}
//预处理
public string preprocess(string text)
{
string resStr = "";//要返回的字符串
#region 定义要用到的变量
bool bInclude = true,
bMain = false;
List<string> includeFiles = new List<string>();
//待处理的rss字符串
string k = "",//($k)中的k字符串
v = "",//保存json[k].toString()
varStr = "",//变量部分
cssStr = "";//css部分
//匹配包含的文件
Regex include = new Regex(@"^\s*@(.+?)\r\n", RegexOptions.None);
//匹配注释
Regex comment = new Regex(@"^\s*#.+\r\n", RegexOptions.Singleline);
//匹配一行:一个变量 形如 $xx:xxx;
Regex getLine = new Regex(@".+\r\n", RegexOptions.Multiline);
//将一个变量处理为 变量名:值 的数组
Regex matchOne = new Regex(@"\s*\$([a-zA-Z0-9\-_]+)\s*[:]([^;]+)[;]");
//匹配($xxx)
Regex v2string = new Regex(@"\(\$(.+?)\)", RegexOptions.Multiline);
//临时保存匹配结果
Match match = null, t = null;
//用于 分割变量部分和css部分的下标
int index = 0;
//变量json
JObject json = new JObject();
#endregion
#region 1.分离变量和正文部分 解决了textbox中和文件中分离不一致的问题
match = getLine.Match(text);//匹配含有一个变量的一行
while (match.Groups[0].Value != "")
{
//正文还没开始 --> 匹配注释 --> 匹配到注释则跳过,没匹配到就匹配变量
//先完成包含文件部分的匹配 将所有包含文件部分匹配完后 完成下一行的内容
//正文开始时 --> 做变量替换
#region 注释
if (bMain == false)
{
t = comment.Match(match.Groups[0].Value);
if (t.Groups[0].Value != "")
{
index = match.Index + t.Groups[0].Value.Length;
//匹配下一行
match = match.NextMatch();
if (match.Groups[0].Value == "")
{
bMain = true;
}
continue;
}
}
#endregion
#region 先匹配包含文件部分
bInclude = true;
t = include.Match(match.Groups[0].Value);
if (t.Groups[0].Value != "")
{
includeFiles.Add(t.Groups[1].Value);
}
else
{
bInclude = false;
}
if (bInclude)
{
//匹配下一行
match = match.NextMatch();
if (match.Groups[0].Value == "")
{
bMain = true;
}
continue;
}
#endregion
#region var
t = matchOne.Match(match.Groups[0].Value);//一个变量按格式匹配 结果是长度为3的数组 原字符串 变量名 值
if (t.Groups[0].Value == "")
{
//变量匹配完成 获取css部分字符串
cssStr = text.Substring(index); break;
}
else
{
//用于 分割变量部分与css部分
index = match.Index + t.Groups[0].Value.Length + 2;// \r\n 2个字符
while (t.Groups[0].Value != "")
{
//变量部分
varStr += t.Groups[0].Value + "\r\n";
t = t.NextMatch();
}
//匹配下一行
match = match.NextMatch();
if (match.Groups[0].Value == "")
{
bMain = true;
}
}
#endregion
}
#endregion
//2.变量2json
#region 2.1 读取@文件列表的文件 与varStr合并
for (int i = 0; i < includeFiles.Count; i++)
{
if (File.Exists(includeFiles[i]))
{
v = File.ReadAllText(includeFiles[i]);
varStr = v +"\r\n"+ varStr;
}
}
#endregion
#region 2.2 var2json
match = getLine.Match(varStr);
while (match.Groups[0].Value != "")
{
//注释
t = comment.Match(match.Groups[0].Value);
if (t.Groups[0].Value != "")
{
//匹配下一行
match = match.NextMatch();
continue;
}
#region var2json
t = matchOne.Match(match.Groups[0].Value);
if (t.Groups[0].Value == "")
{
//变量匹配完成
break;
}
else
{
//变量2json
json[t.Groups[1].Value] = t.Groups[2].Value;
//匹配下一行
match = match.NextMatch();
}
#endregion
}
#endregion
#region 3.处理变量值中的变量 $c_white:($white);
foreach (var item in json)
{
v = item.Value.ToString();
t = v2string.Match(v);
if (t.Groups[0].Value != "")
{
k = t.Groups[1].Value;
if (json.Property(k) != null)
{
v = v.Replace("($" + k + ")", json[k].ToString());
}
else
{
v = v.Replace("($" + k + ")", "");
}
json[item.Key] = v;
}
}
#endregion
#region 4.cssstr变量替换
resStr = cssStr;
match = v2string.Match(cssStr);
while (match.Groups.Count > 1)
{
if (match.Groups[0].Value != "")
{
k = match.Groups[1].Value;
if (json.Property(k) != null)
{
v = json[k].ToString();
}
else
{
v = "";
}
resStr = resStr.Replace("($" + k + ")", v);
}
match = match.NextMatch();
}
#endregion
return resStr;
}
#endregion
}
}
winform的form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace css_var2
{
public partial class Form1 : Form
{
private string iniPath = System.Environment.CurrentDirectory + @"\info.ini";
private Watchers w1 = null;
private bool CloseWin = false;
public Form1()
{
InitializeComponent();
this.ShowInTaskbar = false;
this.notifyIcon1.Visible = true;
//托盘菜单和事件
MenuItem show = new MenuItem("显示");
MenuItem quit = new MenuItem("退出");
show.Click += new EventHandler(toNormal_Click);
quit.Click += new EventHandler(quit_Click);
this.notifyIcon1.ContextMenu = new System.Windows.Forms.ContextMenu();
this.notifyIcon1.ContextMenu.MenuItems.Add(show);
this.notifyIcon1.ContextMenu.MenuItems.Add(quit);
//listBox contextmenu
MenuItem del = new MenuItem("删除");
del.Click += new EventHandler(delOne_Click);
listBox1.ContextMenu = new System.Windows.Forms.ContextMenu();
listBox1.ContextMenu.MenuItems.Add(del);
//监控初始化
w1 = new Watchers();
w1.readini(iniPath);
showFiles(ref w1.files);
textBox2.Text = @"#test include
@C:\Users\sophsis\Desktop\test1.rss
#comment1
$c_white:color:($white);
#comment2
$c_black:color:($black);
#comment2
* {
padding:0;
margin:0;
($c_black);
}";
}
//将文件列表显示到 listbox中
private void showFiles(ref List<string> lists)
{
int n = lists.Count;
listBox1.Items.Clear();
for (int i = 0; i < n; i++)
{
listBox1.Items.Add(lists[i]);
}
}
//添加一个文件
private void button1_Click(object sender, EventArgs e)
{
w1.addOne(textBox1.Text);
textBox1.Clear();
showFiles(ref w1.files);
}
//启动监视 暂停监视功能
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
//暂停监视
if (cb.Checked)
{
w1.startpause(false);
}
//启动监视
else
{
w1.startpause(true);
}
}
//测试预处理函数
private void button2_Click(object sender, EventArgs e)
{
textBox3.Text = w1.preprocess(textBox2.Text);
}
//保存配置文件
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//托盘里关闭 才是真的关闭程序
//
if (this.CloseWin)
{
w1.writeini(iniPath);
}
else
{
e.Cancel = true;
this.Hide();
}
}
//删除一个监控
private void delOne_Click(object sender, EventArgs e)
{
w1.deleteOne(listBox1.Items[listBox1.SelectedIndex].ToString());
listBox1.Items.RemoveAt(listBox1.SelectedIndex);
}
//显示窗口事件
private void toNormal_Click(object sender, EventArgs e)
{
this.Show();
}
//退出程序
private void quit_Click(object sender, EventArgs e)
{
CloseWin = true;
this.Close();
}
private void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
this.Show();
}
}
}