//开博题记: 接触编程两年多, 从没自己写过编程笔记, 偶尔会收藏些有用的文章, 但是都没整理过. 乱七八糟一大堆资料自己看起来也辛苦, 有必要把这些心得和资料整理记录下了, 留给自己以后查找, 也分享给各位学习者, 共同进步.
为了克服单级目录所存在的缺点, 可以为每一个用户建立一个单独的用户文件目录UFD(User File Directory). 这些文件目录具有相似的结构, 它由用户所有文件的文件控制块组成. 此外, 在系统中再建立一个主文件目录MFD(Master File Directory); 在主文件目录中,每个用户目录文件都占有一个目录项,其目录项中包括用户名和指向该用户目录文件的指针. 如下, 图中的主目录中示出了三个用户名,即Wang、Zhang和Gao.
看到图片后我首先想到的是利用DataTable存数据的方法来模拟程序. 上图很显然可以做成一个表存用户信息, 一个表存文件信息. 文件信息表内通过外键约束辨别属于哪个用户的表, 这样就可以实现权限管理, 当前用户可以读写新建删除自己的文件, 只读其他用户创建的文件. 由于是模拟操作, 文件表内就直接保存文件名和文件内容, 所以表如下
User(user, password)
File(user, fileName, fileContent, fileTime)
有了表后, 我想实现的功能是首先一个界面, 用户可以登录或新建用户, 程序默认有一个超级管理员admin, 超级管理员可以操作所有用户的文件, admin不可删除以防用户删完后就不能操作文件. 登录后可以进行新建删除修改文件等操作, 关闭程序后, 数据保存到本地.
第一个问题就是DataTable如何保存到本地, 保存到本地后如何读入程序. 找资料的时候发现, DataSet拥有ReadXml()和WriteXml()方法, 也就是说DateSet可以和Xml相互转换. 于是就写了一个DataSet的操作类, 读取Xml到DateSet内, 以及把DateSet内的DataTable保存到Xml内, 参考了DataSet实例之建立数据表和主外键约束里面初始化DateSet和Datatable写的方法.
///
/// 加载表集合的时候如果有数据文件就直接读取, 没有就初始化一个
///
public void Load()
{
//判断根目录下是否存在文件
if (File.Exists("MyFMS_DataS.xml"))
{
//存在的话就把文件读入到DataSet内
ds.ReadXml("MyFMS_DataS.xml");
}
else
{
//初始化Datatable
dtUser.Columns.Add("user", typeof(string));
dtUser.Columns.Add("password", typeof(string));
dtFile.Columns.Add("user", typeof(string));
dtFile.Columns.Add("FileName", typeof(string));
dtFile.Columns.Add("FileConrent", typeof(string));
dtFile.Columns.Add("FileTime", typeof(string));
//将两个内存表增加到Dataset对象ds的表集合中
ds.Tables.Add(dtFile);
ds.Tables.Add(dtUser);
//初始化个超级管理员
object[] add_dt = new object[2];
add_dt[0] = "admin";
add_dt[1] = "admin";
Add(add_dt, "User");
//初始化个超级管理员
object[] add_dt2 = new object[4];
add_dt2[0] = "admin";
add_dt2[1] = "程序说明";
add_dt2[2] = "本程序是用来模拟操作系统的二级文件管理系统\n\n概念:二级文件管理简单理解就是创建一个数组用来存储用户信息,每个数组元素在对应一个数组用来存储文件信息.管理员账户可以读写所有用户创建的文件,而特定的用户只能读写自己创建的文件,只读别人创建的文件.\n\n实现方式:本程序是利用两个Datatable, 一个用来存储用户资料(用户名, 密码), 另一张表用来存储文件信息(用户名, 文件名, 文件内容, 创建时间), 利用这两张表就可实现简单的二级文件模拟管理操作.\n\nby Cinwell";
add_dt2[3] = DateTime.Now.ToString();
Add(add_dt2, "File");
设置主键和外键约束
//UniqueConstraint uc = new UniqueConstraint("ucUser", ds.Tables["User"].Columns["user"], true);
//ds.Tables["User"].Constraints.Add(uc);
//ForeignKeyConstraint fc = new ForeignKeyConstraint("fcUser", ds.Tables["User"].Columns["User"], ds.Tables["File"].Columns["User"]);
//ds.Tables["File"].Constraints.Add(fc);
//保存DataSet
Save();
}
}
///
/// 保存文件
///
public void Save()
{
//保存DataSet
ds.WriteXml("MyFMS_DataS.xml");
}
有了数据后, 当用户打开程序, 首先是要登录. 简单一点实现就是, 当用户输入帐号密码之后, 程序把用户填的帐号和User表内匹配看有没有这行数据, 有的话把对应的密码返回出来, 然后返回的密码和用户填写的密码匹配, 如果一致则登录成功. 于是就还需要一个方法: 输入一个表名, 一个键值对, 返回一行数据. 这里可以用简单DataTable.Select()类似SQL查找表内数据的方法.由于限定用户名不重名, 所以返回的数据肯定是只有一行的, 直接读取password列的数据就得到该用户的密码了, 匹配一下就能判断帐号密码正确与否.
///
/// 查找表中指定行中的其他键的值
///
/// 表名
/// 指定行的键
/// 指定行的值
///
public DataRow[] FoundResult(string tName, string tKey, string tValue)
{
string strCondition = tKey + "='" + tValue + "'";
DataRow[] dr = ds.Tables[tName].Select(strCondition);
return dr;
}
用户还可以注册账户, 注册时限定用户输入只能是数字或字母, 在文本框上注册一个KeyPress事件
private void txtUser_KeyPress(object sender, KeyPressEventArgs e)
{
//IsNumber:指定字符串中位于指定位置的字符是否属于数字类别
//IsPunctuation:指定字符串中位于指定位置的字符是否属于标点符号类别
//IsControl:指定字符串中位于指定位置的字符是否属于控制字符类别
if (!Char.IsNumber(e.KeyChar) && !Char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}
登录成功后用户就可以操作文件, 把DataTable内文件信息遍历到Listview内
for (int i = 0; i < dt.Rows.Count; i++)
{
ListViewItem lvi = new ListViewItem(dt.Rows[i][0].ToString());
for (int j = 0; j < dt.Columns.Count; j++)
{
// lvi.ImageIndex = 0;
lvi.SubItems.Add(dt.Rows[i][j].ToString());
}
ltvUser.Items.Add(lvi);
}
最后就是窗体间传值的问题, 找到一篇文章(C#)WinForm窗体间传值 用了里面其中一个方法写的
//Form1
FormAlterPwd fr = new FormAlterPwd(tValue); //窗体间传值
//Form2
private string tValue;
public FormAlterPwd(string tValue)
{
InitializeComponent();
// TODO: Complete member initialization
this.tValue = tValue;
}
做完上面功能后发现还有一些细节可以完善, 比如新建用户可以选择是否为超级管理员, 还有打开多个文件的时候不能重复打开同一文件. 大致如此.
源码下载: 模拟二级文件系统(c#)