C#实现FTP连接的示例源码详解
简介:C#语言在多种IT项目中被广泛使用,特别是在Windows平台。为了帮助开发者实现FTP文件传输,本文提供了一个如何在C#中使用System.Net命名空间创建FTP连接的详细示例源码。源码演示了如何使用FtpWebRequest和FtpWebResponse类进行文件下载,并解释了如何通过修改方法和使用不同的流来执行文件上传和其他操作。此外,还涵盖了异常处理和对特定FTP服务器操作时可能遇到的额外挑战。
1. C#与FTP连接概述
在现代软件开发中,文件传输协议(FTP)是一个非常重要的功能,它允许开发者在应用程序之间或服务器与客户端之间传输文件。C#作为一种流行的编程语言,提供了与FTP进行交互的标准方法。通过C#与FTP的连接,开发者可以方便地实现文件下载、上传、删除以及列出目录内容等功能。
要使用C#实现与FTP服务器的交互,开发者通常依赖于.NET Framework中提供的类库。特别是FtpWebRequest和FtpWebResponse这两个类,它们为开发者提供了与FTP服务器通信所需的所有方法和属性。在本章中,我们将简要概述C#与FTP连接的基础知识,并为后续章节中介绍的更高级的功能奠定基础。
FTP连接的实现涉及一系列步骤,包括创建网络连接、配置传输参数、发送命令以及处理响应等。在下一章,我们将详细探讨如何使用FtpWebRequest和FtpWebResponse类来实现文件下载这一基本功能,并分析相关代码的实现细节。通过这些实例,读者将逐渐掌握在C#环境下实现FTP操作的技能。
2. 使用FtpWebRequest和FtpWebResponse实现文件下载
2.1 FtpWebRequest和FtpWebResponse基础
2.1.1 FtpWebRequest类的介绍与配置
在C#中, FtpWebRequest 类允许你通过FTP协议执行数据传输操作,如下载和上传文件。为了使用 FtpWebRequest ,首先需要创建它的实例,并配置必要的属性,比如服务器地址、用户名、密码、FTP命令类型等。
下面的代码段展示了如何创建和配置 FtpWebRequest 的实例:
using System.Net;
// 创建FtpWebRequest实例
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://example.com/file.txt");
request.Method = WebRequestMethods.Ftp.DownloadFile; // 设置请求方法为下载文件
// 配置认证信息
request.Credentials = new NetworkCredential("username", "password");
// 设置使用被动模式
request.UsePassive = true;
// 其他可配置属性
request.Timeout = 10000; // 设置请求超时时间
代码逻辑逐行解读:
- 首先,通过 WebRequest.Create 方法创建一个 FtpWebRequest 实例。
- 通过设置 Method 属性,指明这是一个下载文件的操作。
- 使用 Credentials 属性提供FTP服务器登录时所需的身份验证信息。
- UsePassive 属性用于控制是否使用被动模式。被动模式有助于解决一些网络环境下的连接问题。
- Timeout 属性设置了请求的超时时间,单位是毫秒,防止程序在连接服务器时无限期地等待。
2.1.2 FtpWebResponse的处理流程
一旦设置了 FtpWebRequest 实例,接下来就是发起请求并处理响应。 FtpWebResponse 是 FtpWebRequest 的响应对象,其中包含从FTP服务器返回的所有信息。
处理 FtpWebResponse 的典型步骤如下:
- 发送请求并获取响应。
- 读取响应流中的数据。
- 关闭响应流。
下面是一个简单的代码示例:
using System.IO;
// 发送请求并获取响应
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
using (Stream responseStream = response.GetResponseStream()) // 使用using确保响应流会被正确关闭
{
// 读取数据到内存中的字节数组
using (Stream responseStream = response.GetResponseStream())
{
byte[] buffer = new byte[response.ContentLength];
int bytesRead;
int totalBytesRead = 0;
while ((bytesRead = responseStream.Read(buffer, totalBytesRead, buffer.Length - totalBytesRead)) != 0)
{
totalBytesRead += bytesRead;
}
// 将字节数组中的数据写入到本地文件
File.WriteAllBytes("local-file.txt", buffer);
}
}
代码逻辑逐行解读:
- 使用 GetResponse() 方法发送请求并获取响应。
- 使用 GetResponseStream() 获取响应流,这是一个包含服务器返回数据的流。
- 读取响应流并将其保存到一个字节数组中。
- 使用 File.WriteAllBytes 方法将字节数组内容保存到本地文件。
2.2 文件下载的实现步骤
2.2.1 确定文件下载的URL和路径
为了下载文件,首先需要知道文件在FTP服务器上的确切位置(即URL路径)以及本地保存文件的路径。这两个路径都是必需的,以便 FtpWebRequest 可以定位到正确的文件资源,并且确定本地文件系统的保存位置。
2.2.2 使用Stream读取文件内容
在C#中, Stream 类是用于读取和写入数据的基础类。在文件下载操作中,通过 FtpWebRequest 获取到的响应对象 FtpWebResponse 有一个 GetResponseStream 方法,该方法返回一个 Stream 对象,这个对象包含从服务器下载的文件数据。
2.2.3 文件保存到本地存储的策略
下载文件后,需要将其保存到本地磁盘。C#中的 System.IO 命名空间提供了许多用于文件操作的类和方法。在下载操作中,常用的类是 File 类,它包含 WriteAllBytes 、 WriteAllText 、 WriteAllLines 等方法,这些方法能够将数据一次性写入到文件中。
2.3 实践代码分析
2.3.1 下载文件的完整示例代码
下面的示例代码展示了如何使用 FtpWebRequest 类下载FTP服务器上的文件,并保存到本地磁盘。
using System;
using System.IO;
using System.Net;
class FtpFileDownloader
{
public static void DownloadFile(string url, string localPath)
{
// 创建FtpWebRequest实例
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url);
request.Method = WebRequestMethods.Ftp.DownloadFile;
// 配置认证信息
request.Credentials = new NetworkCredential("username", "password");
// 获取响应
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
using (Stream responseStream = response.GetResponseStream())
using (Stream fileStream = new FileStream(localPath, FileMode.Create))
{
// 将响应流的内容复制到本地文件
responseStream.CopyTo(fileStream);
}
}
}
// 使用示例
FtpFileDownloader.DownloadFile("ftp://example.com/file.txt", "local-file.txt");
代码逻辑逐行解读:
- 创建 FtpWebRequest 实例,并设置请求方法为下载文件。
- 配置FTP服务器的用户名和密码。
- 发送请求并获取 FtpWebResponse 实例。
- 获取响应流和本地文件流。
- 使用 CopyTo 方法将数据从响应流复制到文件流,完成文件下载。
2.3.2 错误处理和异常管理
在进行文件下载时,可能会遇到各种异常情况,例如网络中断、认证失败或文件不存在等。因此,实现错误处理和异常管理机制是非常重要的。
try
{
FtpFileDownloader.DownloadFile("ftp://example.com/file.txt", "local-file.txt");
}
catch (Exception ex)
{
// 异常处理逻辑
Console.WriteLine("下载失败: " + ex.Message);
}
异常处理逻辑:
- 使用 try-catch 语句捕获所有可能发生的异常。
- 将异常信息输出到控制台,或者进行其他错误处理逻辑,比如重新下载、用户通知等。
3. 文件上传的实现方法
文件上传功能在许多应用程序中都是一个不可或缺的部分,尤其是在内容管理系统和文件共享服务中。使用.NET框架,开发者可以通过多种方式实现文件上传功能,但使用 FtpWebRequest 类是实现该功能较为直接的方法。在本章节中,我们将深入探讨使用 FtpWebRequest 实现文件上传的基础知识、具体实现步骤以及实际应用中需要留意的事项。
3.1 FTP上传机制的理论基础
在着手编写代码之前,理解FTP上传机制以及在传输过程中数据流的处理方式是非常重要的。这样,开发者就能够更好地设计出健壮的文件上传功能。
3.1.1 FTP协议中的上传模式
FTP(File Transfer Protocol,文件传输协议)是一种用于在网络上进行文件传输的标准协议。在FTP上传操作中,主要有两种模式:主动模式(Active Mode)和被动模式(Passive Mode)。
- 主动模式(Active Mode) :在这种模式下,客户端打开一个随机端口,并开始监听。之后,客户端向FTP服务器发送一个PORT命令,告知服务器这个端口用于数据传输。服务器会使用自己的20端口(FTP数据端口)与客户端指定的端口建立连接,从而开始数据传输。
- 被动模式(Passive Mode) :被动模式中,客户端告诉服务器自己会监听某个端口。服务器收到这个信息后,将通过一个随机端口来连接到客户端的这个端口,然后开始数据传输。
被动模式通常用于解决防火墙或其他网络设备阻止FTP主动模式数据连接的问题。在编程实现中,使用 FtpWebRequest 时,可以通过设置 FtpWebRequest 实例的 UsePassive 属性来指定使用哪种模式。
3.1.2 上传过程中数据流的处理
在文件上传的过程中,数据流需要从本地计算机传输到FTP服务器。这一过程涉及到几个关键的步骤:
- 建立连接 :通过
FtpWebRequest建立与FTP服务器的连接。 - 配置请求 :配置FTP请求的类型(如上传),设置要上传的文件的相关属性,例如类型、大小等。
- 写入数据流 :将文件内容写入到FTP服务器请求中。
- 发送请求 :发送上传请求到FTP服务器。
- 关闭流 :上传完成后,关闭数据流和连接。
现在让我们深入到具体实现阶段。
3.2 文件上传的具体实现
实现文件上传的具体代码需要我们熟练使用 FtpWebRequest 类。以下步骤将展示如何设置上传参数以及编写上传文件的方法。
3.2.1 FtpWebRequest设置上传参数
在上传文件之前,首先需要创建一个 FtpWebRequest 实例,并为其配置相关的上传参数。下面的代码展示了如何创建这样一个实例,并进行一些基本的配置。
public static void UploadFile(string localPath, string remoteFilePath, string server, string username, string password)
{
// 创建FTP请求实例
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(server + remoteFilePath);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
// 设置为被动模式
request.UsePassive = true;
// 获取本地文件的长度
FileInfo file = new FileInfo(localPath);
long length = file.Length;
// 设置请求头
request.ContentLength = length;
// 读取文件内容到请求流中
byte[] fileContents = File.ReadAllBytes(localPath);
request.GetRequestStream().Write(fileContents, 0, fileContents.Length);
}
3.2.2 编写上传文件的方法
接下来,我们编写一个方法,将本地文件上传到FTP服务器。这个方法需要接收文件的本地路径、远程路径、FTP服务器地址、用户名以及密码作为参数。
using System;
using System.IO;
using System.Net;
public class FtpUploader
{
public static void UploadFile(string localPath, string remoteFilePath, string server, string username, string password)
{
try
{
// 上述代码片段,配置FTP请求
// ...
// 获取FTP服务器的响应
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Console.WriteLine($"Upload File Complete, status {response.StatusDescription}");
response.Close();
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
}
}
// 调用方法上传文件
// FtpUploader.UploadFile(@"C:\path\to\local\file.txt", "/remote/path/file.txt", "ftp.server.com", "username", "password");
上述代码段展示了从创建 FtpWebRequest 对象到配置其参数,最后通过 GetResponse 方法发送请求并获取服务器响应的完整过程。注意,错误处理是这里非常关键的部分,它能帮助我们理解上传过程中可能出现的异常情况。
3.3 实际应用中的注意事项
在实际应用中,除了实现文件上传的功能,还需要考虑到文件类型、大小限制,以及权限问题等因素。这些因素可能会影响到文件上传的成功与否。
3.3.1 文件类型和大小的处理
在进行文件上传时,FTP服务器可能会对上传文件的类型和大小进行限制。因此,开发者在设计上传功能时,应提前了解服务器的相关限制,并在代码中对文件进行相应的校验。
public static bool IsValidFileForUpload(string filePath, long maxFileSize)
{
FileInfo fileInfo = new FileInfo(filePath);
if (fileInfo.Length > maxFileSize)
return false; // 文件超过了最大文件大小限制
// 根据文件扩展名判断文件类型是否允许上传
string extension = Path.GetExtension(filePath).ToLower();
string[] allowedExtensions = { ".txt", ".doc", ".pdf" };
if (!Array.Exists(allowedExtensions, ext => ext == extension))
return false; // 文件类型不在允许上传的列表中
return true; // 文件大小和类型都符合条件
}
3.3.2 权限问题及解决方案
在上传文件到FTP服务器时,用户可能会遇到权限问题。用户必须具有足够的权限才能在服务器上创建或修改文件。如果遇到权限问题,可能需要联系服务器管理员,或者为用户账户赋予更多的权限。
此外,开发者还需要注意异常处理,比如网络超时、服务器错误等问题。在实现文件上传功能时,务必做好异常捕获,并提供清晰的用户反馈,以便在出现错误时能够快速定位问题所在。
以上就是本章节关于文件上传实现方法的详细介绍。接下来我们将继续探讨如何列出FTP目录内容和删除文件,以及在异常处理和服务器兼容性问题方面需要注意的事项。
4. 列出FTP目录内容和删除文件
4.1 FTP目录内容的读取与展示
4.1.1 使用LIST命令获取目录信息
在实现FTP服务器目录内容读取的过程中, LIST 命令是至关重要的。这个命令用来获取目录列表信息,通过它我们可以了解FTP服务器上有哪些文件和子目录。在C#中,可以通过调用 FtpWebRequest 类的 GetResponse 方法来执行 LIST 命令,从而获取目录内容。
由于不同FTP服务器对 LIST 命令的支持可能存在差异,有些服务器可能支持 LIST 命令的参数来格式化输出,但大多数情况下, LIST 命令返回的是一个目录项列表,每一项都包含了文件或目录的详细信息,比如文件大小、修改时间、权限等。
下面是一个使用 LIST 命令来获取FTP服务器上目录信息的基本示例:
private void GetFtpDirectoryListing(string server, string username, string password)
{
string requestUri = "ftp://" + server + "/"; // FTP目录路径
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(requestUri);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.Credentials = new NetworkCredential(username, password);
try
{
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
Console.WriteLine("Status: {0}", response.StatusDescription);
Console.WriteLine("Directory listing:");
Stream responseStream = response.GetResponseStream();
// 这里可以添加解析responseStream并展示目录信息的逻辑
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
}
在上述代码中,我们首先创建了一个 FtpWebRequest 对象,并设置其请求方法为 ListDirectoryDetails 。这样当调用 GetResponse 方法时,FTP服务器会返回目录项的详细列表。之后,我们将响应流中的数据读取出来并展示目录信息,具体展示逻辑可以根据需求自行编写。
4.1.2 分析和处理目录内容数据
从服务器返回的目录内容通常是一个包含多行的字符串流,每一行代表一个目录项。我们需要根据这个字符串流中的信息来分析并解析出文件名、大小、权限等细节。
下面是一个简单的解析示例:
// 假设responseStream是包含目录列表内容的流
StreamReader reader = new StreamReader(responseStream);
string line;
while ((line = reader.ReadLine()) != null)
{
// 解析每一行数据,以"-"为分隔符,通常第9个字段是文件名,第5个字段是文件大小
string[] parts = line.Split(' ');
string fileName = parts[8];
string fileSize = parts[4];
Console.WriteLine("File Name: {0}, File Size: {1}", fileName, fileSize);
}
上述代码段中,我们通过读取每一行数据并使用 Split 方法来分割字符串,从而提取出我们感兴趣的文件名和文件大小。这样我们就可以将FTP目录中的内容以更加结构化的方式展示给用户。
4.2 删除FTP服务器上的文件
4.2.1 删除文件的命令和方法
在FTP协议中,删除服务器上的文件是一个简单的过程,主要用到的命令是 DELE 。它用于删除指定的文件。在C#中,我们可以使用 FtpWebRequest 类发送这个命令。
首先,创建一个 FtpWebRequest 实例,并设置其方法为 DeleteFile ,然后将文件名作为请求的URI传入。之后,通过调用 GetResponse 方法来执行删除操作。如果文件成功删除,服务器将返回状态码250,否则会返回错误信息。
下面是一个删除FTP服务器上文件的示例代码:
private void DeleteFileFromFtp(string server, string username, string password, string filePath)
{
string requestUri = "ftp://" + server + "/" + filePath;
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(requestUri);
request.Method = WebRequestMethods.Ftp.DeleteFile;
request.Credentials = new NetworkCredential(username, password);
try
{
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
Console.WriteLine("File {0} deleted successfully", filePath);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
}
在上述代码中,我们首先构建了一个指向要删除文件的请求URI。然后,创建了一个 FtpWebRequest 对象,并将其方法设置为 DeleteFile 。通过设置 Credentials 属性,我们提供了用于FTP服务器认证的用户名和密码。调用 GetResponse 时,如果文件被成功删除,将打印出成功的消息;如果有任何异常发生,则会捕获它并打印错误消息。
4.2.2 实现删除操作的代码示例
现在我们来实现一个简单的代码示例,演示如何删除FTP服务器上的特定文件:
// 要删除的FTP服务器地址、用户名、密码和文件路径
string server = "ftp.example.com";
string username = "user";
string password = "pass";
string filePath = "/path/to/file.txt";
// 调用删除方法
DeleteFileFromFtp(server, username, password, filePath);
假设上述代码中指定的文件 file.txt 存在于FTP服务器上且有权限删除,那么执行上述方法后,该文件将从服务器上被删除。如果不具备删除权限,或者指定的文件不存在, GetResponse 方法将会抛出异常,错误处理逻辑将输出错误信息。
4.3 实现过程中的异常处理
4.3.1 常见错误及预防措施
在处理FTP操作时,可能会遇到各种各样的错误。常见的错误类型包括:
- 连接错误 :服务器地址错误、网络问题或者服务器不响应。
- 认证错误 :用户名或密码错误。
- 权限错误 :没有足够的权限去执行所请求的操作。
- 文件系统错误 :文件或路径不存在,或者文件正在被使用。
为了预防这些错误,我们可以采取以下措施:
- 验证服务器地址 :确保连接的服务器地址是正确的。
- 测试网络连接 :在尝试连接FTP服务器之前测试网络连接是否正常。
- 错误处理逻辑 :在代码中实现健壮的异常处理逻辑,以捕获和处理可能的错误。
- 用户反馈 :提供清晰的用户反馈信息,帮助用户了解错误原因。
4.3.2 异常捕获和错误提示机制
异常捕获是确保程序稳定运行的关键环节。通过合理地处理异常,可以避免程序在遇到错误时直接崩溃。在C#中,使用 try-catch 块可以捕获和处理异常。
下面是一个改进的代码示例,展示了异常处理和用户反馈:
private void SafeDeleteFileFromFtp(string server, string username, string password, string filePath)
{
try
{
DeleteFileFromFtp(server, username, password, filePath);
}
catch (WebException ex)
{
// 在这里可以根据ex.Status来区分不同的异常
switch (ex.Status)
{
case WebExceptionStatus.ConnectFailure:
Console.WriteLine("连接错误,请检查服务器地址或网络连接。");
break;
case WebExceptionStatus.ProtocolError:
if (ex.Response is FtpWebResponse response)
{
if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
Console.WriteLine("文件不存在或路径错误。");
}
break;
case WebExceptionStatus.NameResolutionFailure:
Console.WriteLine("DNS解析失败,请检查服务器地址。");
break;
default:
Console.WriteLine("未知错误:" + ex.Message);
break;
}
}
}
在上面的代码示例中,我们通过 try-catch 块来捕获可能出现的异常,并通过 switch 语句来区分不同类型的错误。当发生 WebException 时,会根据错误类型给出相应的提示信息。这样可以更好地帮助用户定位问题,提升用户体验。
接下来,我们可以用这个新的方法替换原来的 DeleteFileFromFtp 方法,以确保在进行删除操作时有稳健的错误处理逻辑。
5. 异常处理和FTP服务器兼容性问题
在FTP客户端应用程序开发中,处理各种异常情况和确保程序在不同的FTP服务器上能够稳定运行是非常重要的。本章节将详细介绍在使用C#进行FTP操作时,如何处理异常以及如何解决与服务器兼容性相关的问题。
5.1 异常处理策略
5.1.1 FTP连接异常的分类
FTP操作中可能会遇到的异常可以大致分为几类:
- 网络异常 :网络连接问题导致无法连接到FTP服务器。
- 权限异常 :由于认证失败或权限不足导致的异常。
- 资源异常 :服务器上的文件或目录不存在,无法执行预定操作。
- 响应异常 :服务器返回的响应码无法识别或不预期。
5.1.2 设计健壮的异常处理机制
为了设计一个健壮的异常处理机制,我们可以采用以下策略:
- 明确异常类型 :为不同的异常类型设计相应的处理逻辑。
- 统一异常处理入口 :通过try-catch块来捕获和处理异常。
- 记录详细的错误日志 :对发生的异常进行详细记录,便于后续分析和问题定位。
- 提供用户友好的错误提示 :用户界面应当给出易于理解的错误提示信息。
5.2 FTP服务器的兼容性问题分析
5.2.1 不同FTP服务器的差异性
不同FTP服务器可能会有如下差异:
- 命令支持 :各个服务器可能对FTP命令的支持程度不一。
- 响应码 :服务器的响应码可能有所不同,需要特别处理。
- 用户认证方式 :不同的服务器可能支持不同类型的用户认证方式。
- 传输模式 :二进制模式和文本模式可能因服务器而异。
5.2.2 实现兼容性策略的建议
为了提高程序的兼容性,可以采取以下建议:
- 使用标准的FTP命令 :尽量使用标准FTP协议定义的命令,避免依赖服务器特定的功能。
- 动态检测服务器特性 :在连接建立后,通过发送特定的命令来检测服务器的特性,并据此调整操作。
- 可配置的选项 :提供配置选项,允许用户根据服务器的具体情况手动调整连接参数。
5.3 实践中的兼容性测试
5.3.1 跨FTP服务器测试方法
进行兼容性测试时,可以遵循以下步骤:
- 列出目标服务器列表 :确定需要测试的FTP服务器类型。
- 建立连接 :尝试与每一个服务器建立连接。
- 执行标准操作 :对每个服务器执行一系列标准化的操作,如登录、列出目录、上传和下载文件等。
- 记录结果 :详细记录每个操作的结果以及出现的任何异常。
- 分析问题 :对记录的结果进行分析,找出不兼容的具体点。
5.3.2 案例分析:兼容性问题的解决实例
假设我们遇到了一个问题:在某个FTP服务器上上传文件时总是失败,而其他服务器上则可以正常上传。经过调查,我们发现该服务器使用了一个非标准的FTP命令来处理上传操作。为了解决这一问题,我们可以:
- 检测服务器类型 :在连接建立后,向服务器发送特定的命令来检测其特性。
- 调整上传策略 :如果检测到服务器使用了非标准命令,我们可以准备相应的备选上传策略。
- 用户配置 :如果服务器特性未知,可以提供一个用户配置界面,让用户选择合适的服务器类型或手动输入命令。
- 代码实现 :修改上传功能的代码,使其能够根据服务器的不同采用不同的处理逻辑。
通过以上步骤,我们能够确保我们的FTP客户端应用程序不仅能够处理各种异常情况,而且能够与不同的FTP服务器保持良好的兼容性。
简介:C#语言在多种IT项目中被广泛使用,特别是在Windows平台。为了帮助开发者实现FTP文件传输,本文提供了一个如何在C#中使用System.Net命名空间创建FTP连接的详细示例源码。源码演示了如何使用FtpWebRequest和FtpWebResponse类进行文件下载,并解释了如何通过修改方法和使用不同的流来执行文件上传和其他操作。此外,还涵盖了异常处理和对特定FTP服务器操作时可能遇到的额外挑战。
更多推荐

所有评论(0)