ASP.NET 中的文件系统浏览:新方法与旧方法的对比






4.21/5 (19投票s)
2005年7月3日
3分钟阅读

144660

3470
从 ASP 迁移到 ASP.NET 的大多数程序员仍然使用循环创建的方法来显示特定文件夹的内容。在本演示中,我将向您展示如何使用文件系统对象、DataGrid 和 DataTable 来完成此任务。
引言
“文件系统浏览?那是什么鬼?”
“旧方法?新方法?还有其他方法吗???”
我想我们大多数人仍然处于 .NET 之前的思维模式,我经常用这个术语来形容那些基于过去做事方式而没有利用新技术优势来简化任务的解决方案。这种思维模式的一个绝佳例子就是,当您被要求创建一个 Web 窗体来列出文件夹内容并允许用户下载该文件夹中选定的文件时,您的脑海中会浮现出什么?我敢打赌,80% 以上的程序员会给出这样的答案。
“是的,我可以构建一个函数来读取文件夹,并像我在 ASP 3.0 中那样编写它,使用 HTML 标签构建布局,然后遍历指定文件夹内的所有目录和文件。然后,我将使用
Response.Write
方法将表格结构写入 HTML 页面。”
有罪??
我想我们大多数人仍然这样想……
如果我告诉您,您可以通过仅使用一些 System.IO
对象、一个 DataTable
和一个 DataGrid
来完成此任务,您会怎么想?听起来很奇怪,对吧?但这是真的!在继续讲解解决方案之前,我想向您展示一个由 ASP.NET 程序员编写的、使用旧方法完成此任务的代码示例。
这是经典代码的 C# 示例
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;
using System.IO;
using System.Configuration;
namespace KeithRull.FolderBrowserCS
{
/// <summary>
/// Summary description for FolderBrowser.
/// </summary>
public class theOldWayBrowser : System.Web.UI.Page
{
protected System.Web.UI.WebControls.PlaceHolder plhFiles;
private void Page_Load(object sender, System.EventArgs e)
{
//create the our table
LiteralControl lcTableHead = new
LiteralControl(@"<TABLE id=FileSystem" +
@"style='FONT-SIZE: xx-small;" +
@"BORDER-TOP-STYLE: none;" +
@"FONT-FAMILY: Arial;" +
@"BORDER-RIGHT-STYLE: none;" +
@"BORDER-LEFT-STYLE: none;" +
@"BORDER-COLLAPSE: collapse;" +
@"BORDER-BOTTOM-STYLE: none'" +
@"cellSpacing=0" +
@"rules=all border=1>");
plhFiles.Controls.Add(lcTableHead);
LiteralControl lcContents;
//creathe the column headers
LiteralControl lcTableHeader = new
LiteralControl(@"<TR>" +
@"<TD style='WIDTH: 80px'>Type</TD>" +
@"<TD style='WIDTH: 350px'>Name</TD>" +
@"<TD style='WIDTH: 150px'>CreationTime</TD>" +
@"<TD style='WIDTH: 150px'>LastWriteTime</TD>" +
@"</TR>");
plhFiles.Controls.Add(lcTableHeader);
try
{
//read our query string, if its null,
//assign the default folder
//to our variable else assign the query string value.
string strDir = Request.QueryString["d"] == null ?
FileBrowerProperty.IntialPath : Request.QueryString["d"];
//read the directory
DirectoryInfo DirInfo = new DirectoryInfo(strDir);
//read the subdirectories inside the parent directory
DirectoryInfo[] subDirs = DirInfo.GetDirectories();
//read the files in the parent directory
FileInfo[] Files = DirInfo.GetFiles();
//check if there are directories and
//files inside our parent directory
if((Files.Length != 0) && (subDirs.Length!=0))
{
//loop thru each of the directory
//inside the parent directory
foreach(DirectoryInfo di in subDirs)
{
//add the directory info to our table
LiteralControl lcFolders =
new LiteralControl(@"<TR>" +
@"<TD style='WIDTH: 80px'>" +
@"Directory</TD>" +
@"<TD style='WIDTH: 350px'>" +
@"<a href='theOldWayBrowser.aspx?d=" +
@di.FullName + "'>" + di.Name +
"</a></TD><TD style='WIDTH: 150px'>" +
di.CreationTime +
"</TD><TD style='WIDTH: 150px'>" +
di.LastWriteTime + "</TD></TR>");
plhFiles.Controls.Add(lcFolders);
}
//loop thru each of the file
//inside the parent directory
foreach(FileInfo fi in Files)
{
//add the file info to our table
LiteralControl lcContentsHead =
new LiteralControl("<tr><td>File</td><td>");
plhFiles.Controls.Add(lcContentsHead);
LinkButton lb = new LinkButton();
//set the label and command name
//to the filename of the file
lb.Text = @fi.Name;
lb.CommandName = @fi.Name;
//set the command argument to the fullpath
lb.CommandArgument = @fi.FullName;
//add our handler
lb.Click += new EventHandler(Download);
plhFiles.Controls.Add(lb);
LiteralControl lcContentsTail =
new LiteralControl("</td><td>" +
fi.CreationTime +
"</td><td valign='bottom'>"+
fi.LastWriteTime+"</td></tr>");
plhFiles.Controls.Add(lcContentsTail);
}
}
else
{
// there is file or folder inside the directory
lcContents =
new LiteralControl("<tr>" +
"<td colspan = 4>" +
"No file/folder found inside this " +
"directory.</td></tr>");
plhFiles.Controls.Add(lcContents);
}
}
catch(Exception ex)
{
//error trap
lcContents =
new LiteralControl("<tr>" +
"<td colspan = 4> Error encountered" +
" while trying to parse directory. " +
ex.Message + "</td></tr>");
plhFiles.Controls.Add(lcContents);
}
LiteralControl lcTableTail =
new LiteralControl("</table>");
plhFiles.Controls.Add(lcTableTail);
}
private void Download(object sender, System.EventArgs e)
{
//get the file path
string filepath = ((LinkButton) sender).CommandArgument;
//geth the filename
string filename = ((LinkButton) sender).CommandName;
//read the file to our stream
Stream s = File.OpenRead(filepath);
//create the bytes to be streamed
Byte[] buffer = new Byte[s.Length];
//build the buffer
try
{
s.Read(buffer, 0, (Int32) s.Length);
}
//close our stream
finally { s.Close(); }
//clear the response headers
Response.ClearHeaders();
//clear the content type
Response.ClearContent();
Response.ContentType = "application/octet-stream";
//add our header
Response.AddHeader("Content-Disposition",
"attachment; filename=" + filename);
//write the buffer to the http stream
Response.BinaryWrite(buffer);
//end response
Response.End();
}
}
}
这看起来不像旧的 ASP 实现吗?在读取数据时还在与界面打交道?
正如我刚才所说,我们可以通过使用 DataTable
和 DataGrid
来完成相同的任务。首先,让我们稍微检查一下 DataGrid.DataSource
属性。DataGrid.DataSource
属性接受任何实现 IList
接口的对象。考虑到这一点,让我们看一下 DirectoryInfo.GetDirectories()
、DirectoryInfo.GetFiles()
和 Directory.FileSystemInfo()
返回的值。>。
DirectoryInfo.GetDirectories()
方法用于获取目录中所有子目录的集合。而 DirectoryInfo.GetFiles()
获取指定目录中所有文件的集合。另一方面,DirectoryInfo.GetFileSystemInfos()
获取文件夹中所有文件和目录的集合。由于这三个方法都返回文件、目录或两者兼有的集合,我们可以安全地假设,我们可以使用这些对象返回的结果集作为我们 DataGrid
的数据源。
下面的列表显示了如何使用 DirectoryInfo.FileSystemInfo()
列出文件夹的内容
private void Page_Load(object sender, System.EventArgs e)
{
string folderToBrowse = @"c:\";
DirectoryInfo DirInfo =
new DirectoryInfo(folderToBrowse);
FileSystemGrid.DataSource =
DirInfo.GetFileSystemInfos();
FileSystemGrid.DataBind();
}
请注意,您需要设置您的网格以接受 DirectoryInfo.GetFileSystemInfo
方法生成的值。示例文本如下
<asp:datagrid id="FileSystemGrid" runat="server"
BorderStyle="None" AutoGenerateColumns="False"
Font-Size="XX-Small" Font-Names="Arial"
AllowSorting="True">
<Columns>
<asp:TemplateColumn HeaderText="Name">
<HeaderStyle Width="350px"></HeaderStyle>
<ItemTemplate>
<asp:HyperLink id=systemLink runat="server" NavigateUrl=''
Text='<%# DataBinder.Eval(Container, "DataItem.FullName") %>'>
</asp:HyperLink>
</ItemTemplate>
</asp:TemplateColumn>
<asp:BoundColumn DataField="CreationTime"
HeaderText="CreationTime">
<HeaderStyle Width="150px"></HeaderStyle>
</asp:BoundColumn>
<asp:BoundColumn DataField="LastWriteTime"
HeaderText="LastWriteTime">
<HeaderStyle Width="150px"></HeaderStyle>
</asp:BoundColumn>
</Columns>
</asp:datagrid>
第一个示例的结果如下所示
这很简单?对吧?
如果我们想添加一些用户交互怎么办?例如,单击选定的目录将允许用户浏览其下的文件和目录。要完成此任务,我们需要一个 LinkButton
、我们的 DataTable
和我们的 DataGrid
。但这次,我们将把文件夹表和文件表分开。这是必要的,因为我们希望有不同的交互。例如,单击文件夹将使我们能够浏览该文件夹下的子文件夹和文件,或者单击文件将使我们能够下载该文件。
这是解决此问题的 C# 示例
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
namespace KeithRull.FolderBrowserCS
{
/// <summary>
/// Summary description for theNewWayBrowser.
/// </summary>
public class theNewWayBrowser : System.Web.UI.Page
{
protected System.Web.UI.WebControls.DataGrid FileSystem;
private void Page_Load(object sender, System.EventArgs e)
{
//read our query string, if its null, assign the default folder
//to our variable else assign the query string value.
string folderToBrowse = Request.QueryString["d"] == null ?
FileBrowerProperty.IntialPath : Request.QueryString["d"];
//read the folder
DirectoryInfo DirInfo = new DirectoryInfo(folderToBrowse);
//create our datatable that would hold the list
//of folders in the specified directory
DataTable fileSystemFolderTable = new DataTable();
//create our datatable that would hold the list
//of files in the specified directory
DataTable fileSystemFileTable = new DataTable();
//create our datatable that would hold the list
//of files and folders when we combine the two
//previously declared datatable
DataTable fileSystemCombinedTable = new DataTable();
//create the columns for our file datatable
DataColumn dcFileType = new DataColumn("Type");
DataColumn dcFileFullName = new DataColumn("FullName");
DataColumn dcFileName = new DataColumn("Name");
DataColumn dcFileCreationTime = new DataColumn("CreationTime");
DataColumn dcFileLastWriteTime = new DataColumn("LastWriteTime");
//create the columns for our folder datatable
DataColumn dcFolderType = new DataColumn("Type");
DataColumn dcFolderFullName = new DataColumn("FullName");
DataColumn dcFolderName = new DataColumn("Name");
DataColumn dcFolderCreationTime = new DataColumn("CreationTime");
DataColumn dcFolderLastWriteTime = new DataColumn("LastWriteTime");
//add the columns to our datatable
fileSystemFolderTable.Columns.Add(dcFileType);
fileSystemFolderTable.Columns.Add(dcFileName);
fileSystemFolderTable.Columns.Add(dcFileFullName);
fileSystemFolderTable.Columns.Add(dcFileCreationTime);
fileSystemFolderTable.Columns.Add(dcFileLastWriteTime);
fileSystemFileTable.Columns.Add(dcFolderType);
fileSystemFileTable.Columns.Add(dcFolderName);
fileSystemFileTable.Columns.Add(dcFolderFullName);
fileSystemFileTable.Columns.Add(dcFolderCreationTime);
fileSystemFileTable.Columns.Add(dcFolderLastWriteTime);
//loop thru each directoryinfo object in the specified directory
foreach(DirectoryInfo di in DirInfo.GetDirectories())
{
//create a new row in ould folder table
DataRow fileSystemRow = fileSystemFolderTable.NewRow();
//assign the values to our table members
fileSystemRow["Type"] = "Directory";
fileSystemRow["Name"] = di.Name;
fileSystemRow["FullName"] = di.FullName;
fileSystemRow["CreationTime"] = di.CreationTime;
fileSystemRow["LastWriteTime"] = di.LastWriteTime;
fileSystemFolderTable.Rows.Add(fileSystemRow);
}
//loop thru each fileinfo object in the specified directory
foreach(FileInfo fi in DirInfo.GetFiles())
{
//create a new row in ould folder table
DataRow fileSystemRow = fileSystemFileTable.NewRow();
//assign the values to our table members
fileSystemRow["Type"] = "File";
fileSystemRow["Name"] = fi.Name;
fileSystemRow["FullName"] = fi.FullName;
fileSystemRow["CreationTime"] = fi.CreationTime;
fileSystemRow["LastWriteTime"] = fi.LastWriteTime;
fileSystemFileTable.Rows.Add(fileSystemRow);
}
//copy the folder table to our main datatable,
//this is necessary so that the parent table would have the
//schema of our child tables.
fileSystemCombinedTable = fileSystemFolderTable.Copy();
//loop thru each row of our file table
foreach(DataRow drw in fileSystemFileTable.Rows)
{
//import the rows from our child table to the parent table
fileSystemCombinedTable.ImportRow(drw);
}
//assign our file system parent table to our grid and bind it.
FileSystem.DataSource = fileSystemCombinedTable;
FileSystem.DataBind();
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required
// by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.FileSystem.ItemCommand +=
new DataGridCommandEventHandler(FileSystem_ItemCommand);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private void FileSystem_ItemCommand(object source,
DataGridCommandEventArgs e)
{
//get the filepath from the specified
//command arguments for our linkbutton
string filepath = e.CommandArgument.ToString();
//get the file system type of the selected ite
string fileSystemType =
FileSystem.Items[e.Item.ItemIndex].Cells[0].Text;
//if its a directory, redirect to our page and passing
//the new file path to our query string
if(fileSystemType == "Directory")
{
Response.Redirect("theNewWayBrowser.aspx?d="+
e.CommandArgument.ToString());
}
else
{
//get the filename
string filename = e.CommandName;
//read the file to our stream
Stream s = File.OpenRead(filepath);
//create the bytes to be streamed
Byte[] buffer = new Byte[s.Length];
//build the buffer
try {
s.Read(buffer, 0, (Int32) s.Length);
}
//close our stream
finally { s.Close(); }
//clear the response headers
Response.ClearHeaders();
//clear the content type
Response.ClearContent();
Response.ContentType = "application/octet-stream";
//add our header
Response.AddHeader("Content-Disposition",
"attachment; filename=" + filename);
//write the buffer to the http stream
Response.BinaryWrite(buffer);
//end response
Response.End();
}
}
}
}
下面显示了我们解决方案结果的截图
正如您所见,我们使用原生的 ASP.NET 对象,以与使用旧式 ASP 逻辑的第一个示例相同的结果完成了任务。