WebOpenFileDialog






4.75/5 (3投票s)
本文介绍了一个适用于 Web 的 OpenFileDialog
目录
1. 摘要
这篇简短的文章介绍了一个类,它使用户能够从 Web URL 上找到的文件列表中选择文件。它还允许遍历网站的目录结构。
2. 背景
在最近的一个项目中,我发现我需要 OpenFileDialog [^] 的功能,但用于 Web 目录。在搜索网上时,我发现了一些可以执行此功能的工具,但没有一个是我能直接放入应用程序的,尤其是使用 .Net Framework Version 3.5 开发的应用程序。
由于最终的工具可能会在我最初的项目之外有用,因此我在此介绍它。
关于排版说明
在以下讨论中,由开发者指定的属性显示为
- 黑色粗体
- 红色粗体是必需的
- 红色在某些情况下是必需的
软件内部使用的变量显示为 斜体 文本。
3. WebOpenFileDialog
WebOpenFileDialog 是一个派生自 .NET Form [^] 类并提供从网站上选择文件功能的工具。它包含自己的 GUI,一旦成功初始化,允许用户从 TreeView [^] 中选择一个节点,并通过“确定”按钮指示所选节点是所需文件。
3.1. 属性
以下属性可以指定。
属性 | 获取/设置 | 默认值 | 描述 |
Anonymous_FTP | Set | false | 如果为 true,则尝试建立匿名 FTP 连接;否则,必须提供 User_Name 和 Password。 |
File_Name | Get | 无 | 如果返回时值为 DialogResult.OK,则包含用户选择的文件的完全限定文件名;否则,如果返回时值为 DialogResult.Cancel,则包含一个空字符串。 |
FTP_URL | Set | 无 | FTP 网站的 URL,从该网站检索初始目录源(即,要检索的最高目录列表)。类似于 OpenFileDialog 中的“InitialDirectory”。提供的 URL 必须符合 FTP 架构(即,它必须以 'ftp://' 或 'ftps://' 开头)。 |
Pass_Word | Set | 无 | FTP_URL 中指定的站点的 FTP 密码。如果 Anonymous_FTP 为 true,此属性可以为空字符串或站点的匿名 FTP 密码。如果 Anonymous_FTP 为 false,则必须提供站点的 FTP 密码。 |
Perform_Ping | Set | true | 如果为 true,则尝试使用 Ping 与网站建立连接;否则,不执行 Ping。 |
Show_Hidden | Set | false | 如果为 true,则显示以句点开头的目录条目;否则,将忽略以句点开头的目录条目。 |
User_Name | Set | 无 | FTP_URL 中指定的站点的 FTP 用户名。如果 Anonymous_FTP 为 true,此属性可以为空字符串或站点的匿名 FTP 用户名。如果 Anonymous_FTP 为 false,则必须提供站点的 FTP 用户名。 |
Window_Title | Set | 无 | 对话框标题栏中显示的标题。如果未提供,将使用“Web Open File Dialog”作为标题。 |
3.2. 调用
using System;
using System.Text;
using System.Windows.Forms;
using WOFD = WebOpenFileDialog.WebOpenFileDialog;
:
:
WOFD wofd = new WOFD
{
Anonymous_FTP = <(true|false)>,
FTP_URL = <URL of the FTP web site topmost node>,
User_Name = <username for the FTP web site>,
Pass_Word = <password for the FTP web site>,
Perform_Ping = <(true|false)>,
Show_Hidden = <(true|false)>,
Window_Title = <title for the WebOpenFileDialog form>
};
if ( wofd.ShowDialog ( ) == DialogResult.OK )
{
filename_TextBox.Text = wofd.File_Name;
}
4. 实现
4.1. directories_and_files_to_treeview
实际检索和展开 FTP 目录列表的方法称为 directories_and_files_to_treeview。其签名是
bool directories_and_files_to_treeview (
string ftp_url,
NetworkCredential credential,
ref TreeView tree_view,
ref string error_message )
在处理 ftp_url 之前,该方法会确定 ftp_url 是否是现有 TreeView 的根节点。如果是,则会创建一个新的 TreeNode [^];否则,会搜索名为 ftp_url 的节点。这两种情况都会为 directories_and_files_to_treeview 的当前调用建立根节点。
ftp_url = ftp_url.Replace ( @"\", "/" );
if ( tree_view.Nodes.Count == 0 )
{
tree_node = new TreeNode ( ftp_url )
{
Tag = "DIR"
};
tree_view.Nodes.Add ( tree_node );
root_node = tree_view.Nodes [ 0 ];
}
else
{
root_node = find_tree_node ( tree_view.Nodes [ 0 ],
ftp_url ) ;
if ( root_node == null )
{
error_message = String.Format (
"Unable to locate {0}\n" +
"in existing directory tree",
ftp_url );
successful = false;
return ( successful );
}
}
请注意,每次调用 directories_and_files_to_treeview 时,只处理当前目录(在 ftp_url 中指定)。需要多次调用才能遍历 ftp_url 下方的目录树。此限制是强制的,以避免大量网络流量,因为假设只需要访问有限数量的子目录。
通过使用 FtpWebRequest [^] 类,该类由 WebRequest.Create [^] 返回并强制转换为 FtpWebRequest,来完成对网站目录的检索。为了获取网站上的文件目录,将请求 Method 设置为 WebRequestMethods.Ftp.ListDirectoryDetails [^]。此协议检索 FTP 服务器上文件的详细列表。初始化代码可能如下所示:
FtpWebRequest request;
ftp_uri = new Uri ( ftp_url );
// retrieve directory details
request =
( FtpWebRequest ) WebRequest.Create ( ftp_uri );
request.Credentials = credential;
// use FTP LIST to retrieve
// all directory entries
request.Method = WebRequestMethods.
Ftp.ListDirectoryDetails;
using ( WebResponse response = request.
GetResponse ( ) )
{
using ( StreamReader stream_reader =
new StreamReader (
response.
GetResponseStream ( ) ) )
{
// process each line in the
// directory list
while ( stream_reader.Peek ( ) > 0 )
{
string line = stream_reader.ReadLine ( );
:
:
目录列表由行组成,第一字符区分条目类型。 Unix 文件类型 [^] 描述了 Unix 操作系统中文件的类型。目录列表的示例是
drwx--x--x 24 amvetspost amvetspost 4096 May 1 09:31 ..
drwx------ 2 amvetspost amvetspost 4096 Jul 14 2016 .HttpRequest
drwx------ 4 amvetspost amvetspost 4096 Jul 14 2016 .MirrorSearch
-rw-r--r-- 1 amvetspost amvetspost 100 May 22 2016 .bash_logout
-rw-r--r-- 1 amvetspost amvetspost 230 May 22 2016 .bash_profile
-rw-r--r-- 1 amvetspost amvetspost 176 Jul 27 2015 .bash_profile.rpmnew
-rw-r--r-- 1 amvetspost amvetspost 124 Sep 22 2015 .bashrc
drwxrwx--x 5 amvetspost amvetspost 4096 Jul 14 2016 .cagefs
drwxr-xr-x 2 amvetspost amvetspost 4096 Apr 26 15:17 .cl.selector
-rw------- 1 amvetspost amvetspost 0 Jul 10 2016 .contactemail
drwxr-xr-x 3 amvetspost amvetspost 4096 Jul 14 2016 .cpan
drwx------ 5 amvetspost amvetspost 4096 Apr 29 08:36 .cpanel
drwx------ 3 amvetspost amvetspost 4096 Jul 14 2016 .cpcpan
drwx------ 4 amvetspost amvetspost 4096 Aug 17 2016 .cphorde
drwx------ 4 amvetspost amvetspost 4096 Jul 14 2016 .cpobjcache
-rw-r--r-- 1 amvetspost amvetspost 145 Jul 10 2016 .gemrc
drwxr-x--- 2 amvetspost 99 4096 Jul 10 2016 .htpasswds
-rw------- 1 amvetspost amvetspost 650 Apr 29 08:36 .lastlogin
-rw-r--r-- 1 amvetspost amvetspost 33 May 22 2016 .md5sum
drwxr-xr-x 2 0 0 4096 Jun 19 12:03 .mysql_backup
drwx------ 2 amvetspost amvetspost 4096 Apr 26 15:58 .subaccounts
drwx------ 2 amvetspost amvetspost 4096 Jul 15 2016 .trash
-rw-r--r-- 1 amvetspost amvetspost 658 Mar 25 2016 .zshrc
drwxr-xr-x 2 amvetspost amvetspost 4096 Jun 13 08:51 AmVetsData
lrwxrwxrwx 1 amvetspost amvetspost 39 Jul 10 2016 access-logs -> /usr/local/apache/domlogs/amvetspost292
drwxr-xr-x 2 amvetspost amvetspost 4096 Aug 17 2016 cache
drwxr-x--- 2 amvetspost 12 4096 Jul 10 2016 etc
drwx------ 2 amvetspost amvetspost 4096 Jun 14 05:20 logs
drwxr-x--- 8 amvetspost amvetspost 4096 Jul 14 2016 mail
每行第一个字符决定是否处理。出于我们的目的,只保留普通文件(第一个字符为连字符 (-))和目录(第一个字符为小写字母 'd')。所有其他将忽略。
如果目录条目名(目录列表中的最后一列)以句点开头,则该条目被视为“隐藏”条目。除非将 Show_Hidden 属性设置为 true,否则将忽略隐藏条目。如果目录列表行的第一个字符是 'd' 且目录条目名以句点结尾,则忽略该条目。后者消除了目录 '.'(当前目录)和 '..'(父目录)。
有了这些第一个字符的定义,代码就变成了
char first_ch = ( char ) 0;
int index = 0;
string name = String.Empty;
string type = String.Empty;
first_ch = line [ 0 ];
if ( first_ch == 'd' )
{
if ( line.EndsWith ( "." ) )
{
continue; // ignore . and ..
}
type = "DIR";
}
else if ( first_ch == '-' )
{
type = "FILE";
}
else
{
continue; // ignore all others
}
index = line.LastIndexOf ( ' ' );
if ( index < 0 )
{
continue;
}
name = line.Substring ( index ).Trim ( );
if ( name.StartsWith ( "." ) )
{
if ( !Show_Hidden )
{
continue;
}
}
tree_node = new TreeNode ( name )
{
Tag = type
};
if ( type.Equals ( "DIR" ) )
{
tree_node.Nodes.Add (
new TreeNode ( "EMPTY" )
{
Tag = "EMPTY"
} );
}
root_node.Nodes.Add ( tree_node );
}
目录列表中的每个非忽略的目录条目名都分配给一个 TreeNode,其类型为“DIR”或“FILE”,并存储在 Tag 中。如果要添加一个新的目录节点(DIR),它会被赋予一个类型为“EMPTY”的子节点,然后再添加到 TreeView 中。这个空节点会导致 TreeView 控件在节点前放置一个加号 (+),从而暗示存在一个子树。请注意,TreeNode 的展开仅在该 TreeNode 被作为根处理时(即,在调用 directories_and_files_to_treeview 时作为 ftp_url 传递)发生。
4.2. find_tree_node
TreeNode 搜索方法可能很有趣。其内容是
TreeNode find_tree_node ( TreeNode root,
string name_to_find )
{
Stack < TreeNode > stack = new Stack < TreeNode > ( );
bool no_strip = false;
stack.Push ( root );
name_to_find = name_to_find.Replace ( @"\", "/" );
no_strip = name_to_find.EndsWith ( "/" );
while ( stack.Count > 0 )
{
StringBuilder name = new StringBuilder ( );
TreeNode node = ( TreeNode ) stack.Pop ( );
name.AppendFormat ( "{0}/{1}",
node.FullPath,
node.Name );
name.Replace ( @"\", "/" );
if ( !no_strip )
{
while ( name.ToString ( ).EndsWith ( "/" ) )
{
name.Length--;
}
}
if ( name.ToString ( ).Equals ( name_to_find ) )
{
return ( node );
}
foreach ( TreeNode child in node.Nodes )
{
if ( child != null )
{
stack.Push( child );
}
}
}
return ( null );
}
给定一个用于搜索的根节点以及要搜索的节点名称,find_tree_node 会在 root 的子树中查找具有 name_to_find 名称的节点。如果搜索成功,则返回包含该名称的 TreeNode;否则,返回 null。
我曾考虑使用递归搜索,但迭代方法似乎更简单。因此,简单胜过了优雅!
5. 使用 WebOpenFileDialog
根据构建,WebOpenFileDialog 是一个包含 WebOpenFileDialog 类的项目,该类派生自 Form 类。它具有 WebOpenFileDialog 命名空间。要在 Microsoft Visual Studio [^] 中使用此类,只需将 WebOpenFileDialog 项目复制到包含的解决方案中。
6. 演示
演示项目已包含在下载文件中。执行后,它会显示
选择文件后(如 第一个图 所示)并点击“确定”按钮,所选文件名的完全限定路径将出现在 Filename TextBox 中。
7. 参考
- FtpWebRequest [^]
- Microsoft Visual Studio [^]
- OpenFileDialog 类 [^]
- TreeNode [^]
- TreeView. [^]
- Unix 文件类型 [^]
- WebRequest.Create [^]
- WebRequestMethods.Ftp.ListDirectoryDetails [^]
8. 开发环境
WebOpenFileDialog 是在以下环境中开发的
Microsoft Windows 7 Professional Service Pack 1 |
Microsoft Visual Studio 2008 Professional |
Microsoft .Net Framework Version 3.5 SP1 |
Microsoft Visual C# 2008 |
9. 历史
06/27/2017 | 原文 |