WinForms FTP下载中While循环里Stream.Read()的作用及异常咨询
我在WinForms中实现了一个FTP文件下载按钮,功能正常,但无法理解DownLoadFileFromFtp方法里While循环中bytesRead = ftpResponseStream.Read(buffer, 0, buffer.Length);这段代码的作用。若移除该代码,下载会进入无限循环,且本地文件体积异常膨胀,恳请专业人士解释这段代码的功能。
相关实现代码
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private static void DownloadFileFromFtp (string serverURI, string pathToLocalFile) { FileStream localFileStream = File.Open(pathToLocalFile, FileMode.OpenOrCreate); FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(serverURI); ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile; ftpRequest.Credentials = new NetworkCredential("demo", "password"); WebResponse ftpResponse = ftpRequest.GetResponse(); Stream ftpResponseStream = ftpResponse.GetResponseStream(); byte[] buffer = new byte[2048]; Console.WriteLine($"\nBuffer length is: {buffer.Length}"); int bytesRead = ftpResponseStream.Read(buffer, 0, buffer.Length); while(bytesRead > 0) { localFileStream.Write(buffer, 0, buffer.Length); bytesRead = ftpResponseStream.Read(buffer, 0, buffer.Length); } localFileStream.Close(); ftpResponseStream.Close(); } private void Form1_Load(object sender, EventArgs e) { if(NetworkInterface.GetIsNetworkAvailable()) { toolStripStatusLabel1.Text = "Connected"; } else { toolStripStatusLabel1.Text = "Disconnected"; } } private void DownloadFile_Click(object sender, EventArgs e) { DownloadFileFromFtp("ftp://test.rebex.net/pub/example/readme.txt", @"C:\Users\nstelmak\Downloads\testFile.txt"); } }
代码作用解析
这段ftpResponseStream.Read(buffer, 0, buffer.Length)代码承担两个核心功能:
读取下一批数据填充缓冲区
FTP流的数据是分批传输的,每次Read会从FTP服务器的响应流里读取最多2048字节(缓冲区大小)的数据到buffer数组里。如果没有这行代码,缓冲区里始终是第一次Read读取的旧数据,后续每次localFileStream.Write都会重复写入这批旧数据,导致本地文件体积不断膨胀。控制循环终止条件
Stream.Read方法的返回值是实际读取到的字节数:当FTP流里的所有数据都读完时,Read会返回0。这行代码会更新bytesRead的值,当返回0时,循环条件bytesRead > 0不再成立,循环终止。如果移除这行代码,bytesRead会一直保持第一次Read返回的非0值,循环永远不会退出,陷入无限循环。
额外提示
你的代码里还有个小问题:localFileStream.Write(buffer, 0, buffer.Length)应该改成localFileStream.Write(buffer, 0, bytesRead)。因为最后一次读取FTP流时,可能读不满2048字节的缓冲区,用bytesRead作为写入长度才能保证只写入实际读取到的有效数据,避免写入多余的无效字节。
内容的提问来源于stack exchange,提问作者Torrvic

