一个用于读取、编辑、加密、解密和写入 XmlStore 文件的实用程序
一个用于读取、编辑、加密、解密、写入 XmlStore 文件的实用程序。
引言
大型数据集最好存储在数据库中。对于小型、简单、单表数据集,传统数据库可能过于复杂,而将其存储在各种更简单的格式中,从制表符分隔的文件到 XML 文件,可能更方便。然而,每种格式都有其自身的复杂性,此处不作赘述。
XmlStore 旨在成为一种“无需思考”的格式。(稍后详述。)
XmlStoreClient 是一个具有简单用户界面的 WinForms 客户端。它在 DataGridView
中显示任何 XmlStore 文件的内容。您可以导航到任何记录(行)或字段(列),对其进行编辑,并保存您的更改。您还可以加密和解密
- 单个单元格,
- 整行,
- 整列,或者
- 整个数据集(表)。
上图中的“Title”列已加密,下图显示的是解密后的效果。
警告
如果您加密了需要密码的内容,您将需要相同的密码来解密数据。您必须记住它,因为密码**未存储**在任何地方。
背景
情况
一位朋友需要一个简单的实用程序来存储她经常访问的网站的用户名和密码。和许多人一样,她很难记住她创建的所有用户名和密码。她查看了能够满足她需求的解决方案,例如 KeePass。但她担心从不熟悉的来源获得解决方案。所以,她想要
- 一个易于使用的界面(即“别让我费脑子”)和
- 一种便携但安全的存储方法,可以存储在她的 U 盘上,并在她工作、在家、旅途中等地方使用的多台 PC 上使用。
复杂性
与为某人“定制”的任何应用程序一样,需求会发生变化。在这种情况下,她首先只想要一个简单的用户名和密码列表。然后,她想添加实体(例如银行)的名称,然后她想添加其 URL,依此类推。这实际上变成了第三个要求——能够轻松添加另一个字段,而无需软件更新。
由于这是一项“免费”任务,我不想在她每次更改“必需字段”列表时都必须维护/更新该实用程序。
不过,我应该提到,她确实向我最喜欢的慈善机构之一捐款:Year Up。确实,如果此实用程序或其中的任何代码对您有帮助,请考虑向 Year Up 或世界各地任何类似的无私奉献、帮助有需要的人的组织捐款。
解决方案
基于 DataGridView
的界面对我的朋友来说效果很好,因为她熟悉电子表格。第二个目标(便携性)通过使用 **XML** 来实现,安全部分是通过允许她使用另一个密码 **加密 XML 中的任何“值”** 来实现的,但这个密码
- 除了她的大脑之外,哪里都没有存储,并且
- 她可以随时随地更改,并且更改次数越多越好。
下图显示了她满意的某个改版屏幕截图。
使用代码
免责声明
我承担这个项目是为了帮助我的朋友,并且在这个过程中,我还学到了一些关于 Visual Studio 2005、C#、XML、DataGridView
、加密等方面的知识。请注意:**没有任何内容经过适当或充分的测试**。更重要的是,您或其他人很可能做得更好。因此,如果您使用此代码并且无法解密某些内容,我和其他人也无能为力。不过,从积极的一面来看,由于您拥有源代码,*您可以使其更健壮以满足您的需求*。
构建实用程序
如果您有 Visual Studio 2005,那么您应该能够“开箱即用”地使用项目源代码——只需构建并运行即可。代码本身并非火箭科学。它具有合理的文档。如果您没有 Visual Studio 2005,您将不得不请一位更有经验的朋友。(别问我,我不知道!也别问微软,因为那里没人会回应!!!)
代码模块
代码对新手(比如我自己)的附带好处是:该项目包含文档合理且自明的代码模块。幸运的话,它们也许能帮助您学习如何使用各种技术中的一些功能。
VVX_About.cs
VVX.About
是一个简单的类,提供一个“廉价”的、零维护的“帮助 | 关于”消息框。如果您不知道如何访问程序集中的信息,它可以向您展示一种从其中提取一些信息的方法。
VVX_MsgBox.cs
VVX.MsgBox
是一个类,用于简化对各种消息框的访问。它帮助我学会了更有效地使用消息框。例如,MsgBox.Confirm(...)
方法允许我执行类似这样的操作
if (VVX.MsgBox.Confirm("Save changes?"))
this.DoFileSave();
而不是这样
if(DialogResult.Yes == MessageBox.Show("Save changes?", "Confirm",
MessageBoxButtons.YesNo, MessageBoxIcon.Question))
this.DoFileSave();
VVX_FileDialog.cs
VVX.FileDialog
是一个类,用于更有效地访问 OpenFileDialog
和 SaveFileDialog
。例如,FileDialog.GetFilenameToOpen(...)
方法允许我执行类似这样的操作
string filename = VVX.FileDialog.GetFilenameToOpen(VVX.FileDialog.FileType.XML);
if (filename.Length > 0)
{
this.DoGridPopulate(this.ctlTableDGV);
}
该方法仅负责设置过滤器等。
VVX_File.cs
VVX.File
是一个类,用于简化对几个文件相关方法的访问,例如删除。同样,这也不是火箭科学,但我发现很难记住必须使用 System.IO.FileInfo
类来删除文件!我现在可以通过这个做到。
VVX.File.Delete(sTempFile);
VVX_CryptoLib.cs
VVX.CryptoLib
是一个 C# 类,它是 VB 版 CodeProject 文章“.NET 文件的字符串加密库”作者 HanreG 的一个子集,并受其启发。我只是用 C# 重写了代码,并且只使用了两个方法
public string EncryptString(string value , string password) {...}
public string DecryptString(string value , string password) {...}
有关这些主题的更多信息,请参阅该文章。
VVX_XmlStore.cs
VVX.XmlStore
是一个 C# 类,它帮助我们“访问”和“管理”XmlStore 文件。目前,它侧重于将数据与 UI (DataGridView
) 连接起来。
XmlStore
考虑以下“表”
上面“表”的 XmlStore 文件
- 本质上是一个简单的“平面”XML 文件。
- 它存储**一个**表(例如上面的密码表)的“表格”数据。
它看起来像这样
<?xml version="1.0" encoding="utf-8"?>
<xmlstore version="1.0">
<schema datanodename="record">
<field name="entity" title="Entity" />
<field name="username" title="Username" />
<field name="password" title="Password" />
<field name="url" title="URL" />
<field name="contact" title="Contact" />
<field name="phone" title="Phone" />
</schema>
<record entity="bank" username="victorbox" password="Sony1234"
url="www.xyz.com" contact="john doe" phone="123-456-7890" />
<record entity="city" username="victorboz" password="2MuchTax"
url="www.city.gov" contact="Jane Doe" phone="890-456-1234" />
<record entity="CodeProject" username="victorbos" password="goodguys"
url="www.CodeProject.com" contact="-" phone="-" />
</xmlstore>
如您所见,它实际上是一个纯 XML 文件,其中
- 有一个名为
xmlstore
的根节点(但可以命名为任何名称,因为它在代码中没有直接引用)。
以及根节点内的两种“第一代”子节点,即
- 一个单独的
<schema ... />
节点,和 - 表中的**每行**(或
<record ... />
)都有一个数据节点。
数据节点可以有任何基本名称;在上例中,它命名为**record**。
实用程序在没有 Schema 节点的情况下也能工作
schema 节点虽然好用,但并非必需。如果找不到,VVX.XmlStore
将简单地枚举第一个数据(例如 <record ... />
)节点中的属性,并使用属性的名称作为列标题。
关于 Schema 节点
schema 节点的作用有限。首先,它为数据(即 **record**)节点中相应属性的值提供 DataGridView
中显示的**标题**(即列标题)。
其次,它的 datanodename
属性标识了数据节点(在此示例中为 <record ... />
)的基本名称,即“record”。
重要
对您来说可能很明显,但以防万一不清楚……
- schema 节点必须是
<schema ... />
;请勿更改其基本名称。 - 它的属性必须按所示命名:
<schema datanodename="..." >
;请勿更改其名称。 - 它的子节点必须是
<field name="..." title="..." />
;请勿更改其基本名称或属性名称。 - 如果您将数据节点的基本名称从
<record ... />
更改为,例如,<lulu ... />
,那么您还必须将datanodename
属性的值从"record"
更改为"lulu"
。 - 如果您更改了数据节点中某个属性的名称,您也应该在相应的
<field ... />
节点中更改其名称。例如,如果您将<record entity="bank" ... />
更改为<record vendor="bank" ... />
,那么您应该将<field name="entity" title="Entity" />
更改为<field name="vendor" title="Entity" />
。注意:更改**标题**完全是装饰性的。
为什么要使用 XmlStore?
阅读完上一部分后,您可能会觉得这太麻烦了。在我看来,对于这个实用程序而言,这些“规则”可能比某些替代方案的要求稍微宽松一些。
实际上,您可以通过使用 System.Data.DataTable
及其 ReadXml
和 ReadXmlSchema
方法来实现所有这些,然后编写必要的代码来初始化 DataGridView
。这种方法的限制在于,至少对于这个实用程序而言,我的朋友必须维护两个文件,一个用于 XML,一个用于架构;对于非技术人员来说,不得不这样做会使解决方案的复杂性增加一倍以上。此外,我可能没有学到那么多东西!
需要改进之处
仍有很大的改进空间:一种更简单的方法来“测试”和“修复”XmlStore 文件;一种更简单的方法来创建新文件;一种更简单的方法来更改 Crypto 密码;一种更简单的方法来重新排列列。我的朋友并不真正需要/想要这些……但它们反映了这个实用程序的明显局限性。
如果您需要更“强大”和“丰富”的东西……
如果这个实用程序对您来说太弱了,以下之一可能更适合您
不幸的是,它们对我的朋友来说有点太复杂了。(还记得要求之一是“别让我费脑子”吗!)
最后,对您的感谢
我从像您这样匿名地、自由地与世界分享经验的人那里学到了很多。也许您贡献了一点,但我学到了很多。如果这个实用程序能帮助一个人,您就使我的一天变得有意义,并给了我回馈社区的机会。所以,谢谢您!
其他近期贡献
- “一个简单的实用程序,用于快速创建图像文件(*.GIF, *.PNG 等)的反射版本”。2007 年 3 月 6 日
- “一个简单的实用程序,用于快速创建不透明或透明的图像文件(*.GIF, *.PNG 等)”。2007 年 3 月 5 日