文件清单和统计
用于盘点目录和统计文件的程序。
引言
经过数百万年的人类进化,世界人口估计为 70 亿,但第一台计算机诞生仅几十年,如今的普通 PC 包含超过 150 万个文件。习惯了从小拥有几件物品和玩具的成长经历,知道我的 PC 包含如此多的文件,这让人感到困惑;我是否会使用或了解它们?
为了应对这种神秘感,我将展示一个程序,用于统计目录中的文件、盘点统计结果,并将记录存储在 SQLite 表中,以及我将如何
- 设计和编写文件清单和统计程序
- 设计友好的用户界面
- 修复错误并改进之前的应用程序
- 在 C# 应用程序中实际使用 SQLite
- 动态创建数据库和表
- 将持久数据保存到 SQLite 数据库
- 讨论一些未来的增强功能和设计的多样性
背景
在我编写了 File Inventory - A Hybrid Version Control System(文件清单 - 混合版本控制系统)[^] 后,我继续思考对用户有用的磁盘驱动器或文件夹的摘要信息。跟踪每个文件并非现实目标,开发这样的程序可能需要很长时间。
计数文件和目录的数量并盘点计数摘要更容易实现。文件计数可以让用户知道一段时间内增加了多少文件。用户可以从根驱动器或子目录中获取计数。我建议用户先尝试一个小的子目录,直到用户熟悉该程序,然后再尝试整个驱动器。
如果尝试在整个驱动器上运行,可能需要 10 到 30 分钟甚至几个小时才能完成。
我修改了我之前文章中的程序来进行文件和目录计数。
重点在于更友好的用户界面、文件维护界面和编程执行速度。
这不是一个漂亮的、完整的运行实用程序。它需要更多的工作才能真正有用。该程序是一项编程实践,可以作为演示项目来推销未来的项目。
遵循本文的先决条件
由于这是 File Inventory - A Hybrid Version Control System(文件清单 - 混合版本控制系统)[^] 的一个变体,因此该文章的先决条件部分也适用。阅读过那篇文章会很有帮助。
先前版本中的错误
如果您阅读了 File Inventory - A Hybrid Version Control System(文件清单 - 混合版本控制系统)[^] 并下载了源代码,您可能会注意到,当您在包含 500 多个文件的目录上运行时,程序会表现异常。程序似乎会挂起并且一段时间内没有响应;这是由于批处理程序忙于插入记录引起的。在调用批处理函数之前添加两三行线程调用就会立即返回控件。我在本文中添加了线程代码。
它还有一个错误,即尝试在运行批处理文件后删除 SQL 脚本文件。因此,在此版本中,我对每个批处理命令使用不同的脚本文件,并且不删除它。作为练习,限制在小型目录。
下面的屏幕截图显示了临时 SQL 脚本文件和一个用于删除的维护选项卡
编程一个更友好的用户界面
第一个改进是将 TextBox
更改为 ComboBox
,并在 ComboBox
前面添加一个图标大小的按钮。这个细微的改变让用户可以选择不输入目录名,而是单击这个小按钮来弹出目录搜索对话框。ComboBox
还保存用户选择的历史记录。此功能类似于 Word 保存以前打开的十个文档列表,不同之处在于此程序没有这样的限制。
第二个改进是用 DataGrid
替换 ListBox
来列出清单目录。这样,它就可以显示每个清单目录以及文件总数。
第三个是在 Tab3-maintenance(选项卡 3 - 维护)中添加一些功能。此选项卡显示程序创建的所有文件,并允许用户清除程序生成的临时 SQL 脚本文件以及删除 Inventory.db SQLite 数据库,以便重新开始。
关注点
设计很简单,它由最少的三张表组成。将目录名映射到表名,统计摘要表,以及存储目录详细信息的各个表。以下是创建表和插入记录的脚本。
--******** create inventory.db *********
--sqlite3 inventory.db setup.sql
create table path_table_map(
no INTEGER PRIMARY KEY,
dirpath varchar(500),
tblname varchar(500));
create table statistic_page (
no INTEGER PRIMARY KEY,
ckey varchar(20),
dirpath varchar(500),
sumdir INTEGER,
sumfile INTEGER);
create table c_temp(
no INTEGER PRIMARY KEY,
ckey varchar(20),
dirpath varchar(500),
sumfile integer);
insert into path_table_map (dirpath, tblname) values ('c:\temp', 'c_temp');
insert into statistic_page (ckey, dirpath, sumdir, sumfile)
values ('_2012 01/22 06:53:32', 'c:\temp', 5, 27);
insert into c_temp (ckey, dirpath, sumfile)
values ('_2012 01/22 08:13:43', 'c:\temp', 14);
insert into c_temp (ckey, dirpath, sumfile)
values ('_2012 01/22 08:13:43', 'c:\temp\6032', 2);
我采用了 Using SQLite in your C# Application(在您的 C# 应用程序中使用 SQLite)[^]。LoadData
函数访问 SQLite 数据库并从 mains 表检索数据,然后填充 DataSet
。
private void LoadData()
{
SetConnection();
sql_con.Open();
sql_cmd = sql_con.CreateCommand();
string CommandText = "select id, desc from mains";
DB = new SQLiteDataAdapter(CommandText,sql_con);
DS.Reset();
DB.Fill(DS);
DT= DS.Tables[0];
Grid.DataSource = DT;
sql_con.Close();
}
我对其进行了轻微修改,以传递 SQL 注释,这样我就不必多次复制代码。
//passing a sql command
private void sqlQueryToTable(string CommandText)
{
setConnection(a_dbname);
asql_con.Open();
asql_cmd = asql_con.CreateCommand();
aDB = new SQLiteDataAdapter(CommandText, asql_con);
asql_con.Close();
aDS.Reset();
aDB.Fill(aDS);
aDT = aDS.Tables[0];
}
// calling module
private void getCatalog()
{
string sql = "select ckey as 'catalog', sumdir as 'total_dir', " +
"sumfile as 'total_file' from statistic_page where dirpath = '" +
aDir + "' order by ckey desc;";
sqlQueryToTable(sql);
// assign result table to a datagrid
if (aDT.Rows.Count > 0)
a_table2 = aDT;
}
代码调试
我添加了一个 CheckBox
来查看批处理程序的运行。下面的屏幕截图显示了一个有价值的调试错误。SQLite3 在 inventory.db 上运行 _2012_0122_0644_35_2.sql 脚本
上述错误是由以下代码引起的
// summary saved to statistic_page table
txtQuery = "insert into statistic_page values ('" + a_catalog + "', '" +
aDir + "', " + a_total_dir + ", " + a_total_file + ");";
上面的代码生成以下 SQL 脚本,该脚本随后保存到文件 _2012_0122_0644_35_2.sql 中
insert into statistic_page values ('_2012 01/22 08:13:43', 'c:\temp', 5, 27);
但正确的语法应如下所示
insert into statistic_page (ckey, dirpath, sumdir, sumfile)
values ('_2012 01/22 08:13:43', 'c:\temp', 5, 27);
通过提供一个 CheckBox
,我们可以在前台查看批处理程序的运行,这可以简化调试。将 SQL 语句保存到临时文件可以让程序员发现任何错误,而无需在运行时进行调试。
结论
本文记录了我如何继续改进该程序并为其添加更多功能。我已经在 c:\users(一个大目录,包含 22,000 个文件)上进行了测试,运行需要一两分钟。我的下一个任务将侧重于如何管理大型目录以及如何显示和标记两个日志之间的差异。
附录
如果您下载了代码,最好先删除并重新创建 batchjob.bat 文件(在删除之前将 bat 文件内容保存到 txt 文件)。否则,每次程序调用运行批处理作业时,都会收到一个烦人的安全确认提示。Windows 会对非来自您自己系统的批处理文件发出安全警报,并警告用户潜在的危险。
一位读者要求修复一个错误并添加线程支持。当我测试我的 C 驱动器时,它有五十万个文件。将目录计数器(15,000 行)保存到 SQLite 需要 10 分钟。在运行过程中,用户可以在屏幕上移动。
我感谢读者的评论和反馈;这些对于改进程序非常有价值。
参考文献
历史
- 2012 年 1 月 22 日 - 第一个版本。
- 2012 年 2 月 4 日 - 第二个版本 - 添加了线程支持并修复了错误。