实现的功能:监控.rss文件变化(删除、重命名、内容变化) 并且处理为对应的.css文件
本人工作是web前端。less和sass的css预处理概念是非常好的,自己尝试了一下
测试效果图:
自己列的一个简单需求列表
功能要求:
√ 1.监控文件列表控件 列出需要监控的文件列表
√ 要求有右键删除功能
√ 休眠状态?文件在列表中 但暂时不进行监控
√ 2.隐藏到托盘功能 一定要注意NotifyIcon的icon属性要选一张图不然没效果!!!
× 3.添加监控文件功能 批量功能要不要? 一个一个加吧
√ 4.把rss文件编译为css文件
√ *[email protected]引入文件功能 引入变量文件
√ 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.IO;//FileWatch 文件读写
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(); } } }