在本文中,将探讨如何使用C#语言和TcpComm库来实现文件和文件夹的快速传输功能。将通过一个示例应用程序来展示如何通过类似于资源管理器的窗口来传输文件或文件夹。用户可以通过在资源管理器中选择文件或文件夹,然后将它们拖放到传输窗口的右侧面板,或者在传输窗口的右侧面板中选择它们并将它们拖放到资源管理器窗口中来传输文件。
在这里提供的是一种非常快速的FTP类功能,而没有大多数FTP客户端通常带来的麻烦。许多FTP客户端没有提供拖放功能,而是迫使用户处理一个过时的界面,该界面有一个单独的窗口显示本地和远程机器的文件系统内容。
使用本文作为指南,将能够快速地将文件和文件夹传输功能构建到网络应用程序中,使用这里找到的TcpComm库。尽管在这个示例项目中使用了TcpComm库,但并不局限于它。设计了RemoteFileSystem类(负责与远程机器通信并获取文件系统信息的类)作为一个完整且独立的实体,可以与任何网络通信库一起使用。因此,如果有更熟悉的其他网络库,或者想要编写自己的库,不必从这个项目中移除TcpComm,而是可以将RemoteFileSystem类直接放入项目中。
在2012年在CodeProject上编写并发布了TcpComm库。多年来,人们一直在询问如何传输文件夹。该库在客户端和服务器类中提供了GetFile()和SendFile()函数……也提供了一种方法来更改客户端和服务器用于接收传入文件的文件夹。所以当被问及时,大多数情况下会告诉人们他们需要自己构建应用程序中的文件夹传输功能。会说提供了工具,剩下的就取决于了。
最近,正在工作的应用程序要求做同样的事情——构建一个显示远程机器文件系统的UI,并提供一种在本地和远程机器之间传输文件的方法。希望界面相当直观,所以那种笨重的老式Cute FTP风格的界面,每个文件系统都有一个单独的窗口,是不行的。决定在单独的测试应用程序中构建这个功能,并在测试期间使用TcpComm库,以确保TcpComm中的文件传输代码尽可能紧凑,并且最终为多年来一直在询问的人们提供如何传输文件夹的示例。
这个应用程序的核心是RemoteFileSystem类。它有自己的客户端和服务器类,负责处理有关远程文件系统的请求。RemoteFileSystem.Server接受来自RemoteFileSystem.Client的字符串形式的请求。请求格式化为XML,使用构建的XML解析器(XmlObject)。RFS(RemoteFileSystem)本身不会通过网络发送任何数据,它通过委托将每个请求或响应传递给选择的网络通信库。在示例项目中,初始化RFS服务器所需的代码非常简短。
C#
//
Initialize RemoteFileSystem here:
rfsServer =
new
RemoteFileSystem.Server((
String
data) =>
{
//
Send data to the client here:
UI(() => LblStatus.Text =
"
Sending data to client."
);
lat.SendArray(TcpComm.Utilities.StrToByteArray(data),
100
, currentSessionId,
ref
errMsg);
}, (
String
newPath) =>
{
//
Handle requests to update the TcpComm server's received files folder here:
var
session = tcpServer.GetSession(currentSessionId);
if
(session !=
null
) { session.ReceivedFilesFolder = newPath; }
});
相比之下,客户端构造函数相当长,因为服务器的回复数据正在被解析,并用于填充TreeView和ListView控件:
C#
private
void
StartRFS()
{
rfsClient =
new
RemoteFileSystem.Client((
String
data) =>
{
//
Requests are sent to the server here:
String
errMsg =
"
"
;
if
(!tcpClient.SendText(data,
100
,
ref
errMsg))
{
MessageBox.Show(
"
Could not send data to the server!"
,
"
TCP Communications problem"
, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}, (RemoteFileSystem.Client.ServerReplyData serverData) =>
{
//
Handle server replies here:
if
(serverData.type.Equals(
"
getdrives"
))
{
//
This code needs to be run on the UI thread:
UI(() =>
{
tvPaths.Nodes.Clear();
tvPaths.Nodes.Add(
"
"
, remoteMachineName,
3
);
TreeNode firstNode = tvPaths.Nodes[0];
...
This project is heavily commented. My intent was to have interested parties read through the example project so they can get a handle on how to use the different pieces of this puzzle.
在测试这个项目时,如果决定在另一台网络机器上测试服务器,请确保通过右键单击它并以管理员身份运行它。如果不这样做,那么服务器应用程序将无法访问文件系统,并会在第一次连接到它时静默关闭。
当尝试连接到在另一台机器上运行的服务器时,请确保在连接字符串中指定端口,通过冒号将IP地址或主机名分隔开,例如:your_IP_address_or_hostname:22490
这个示例项目包含了XmlObject的副本——编写的一个XML解析器。它建立在XmlReader之上,所以不——没有试图做一些开创性的事情。只是想要包装最有可能使用的功能,并使其以认为所有人都最习惯的方式可用。例如,当查看XML时,看到了一系列嵌套的对象。所以当用解析器访问XML时,不想遍历节点,或者担心非法字符。只想简单地访问对象,并像任何其他面向对象的程序员一样轻松地获取它的子对象。
这个项目还包含了几个辅助类。一个是CopyFile辅助类。它完成了传输文件和显示进度的所有繁重工作。
另一个是DragDrop辅助类。它提供了获取最终用户拖动到的Windows资源管理器文件夹名称的能力,因为Windows本身并不提供这个功能。这个类中的大部分代码最初是在找到的。然而,已经将Joy先生的示例完全重写为一个简单的辅助类,而不是一个跨越项目的示例。也对其进行了改进,以便永远不会看到被拖动的文件,即使它被拖放到桌面上。