【问题标题】:Why is this FTP Download not outputting the downloaded data to my output file?为什么这个 FTP 下载没有将下载的数据输出到我的输出文件?
【发布时间】:2013-11-16 16:43:44
【问题描述】:

我正在编写自己的 FTPDownload 类,但在更改了一些我试图解决的问题后遇到了一个问题。

我将在下面粘贴的代码有效地开始下载并运行一段时间,在“主”循环的每次迭代中提取完整的数据数组。我可以肯定地说,对于小文件(例如 html 中的会议议程),可以快速且看似完整地复制 - 但是有些东西仍然很不合适。

正如我们所说,我正在下载一个 1.05 gig 文件,我的下载状态控件显示完成了 325 Megs - 我可以证明已经通过流收集了这么多数据但是,这就是事情发生的地方奇怪...到目前为止,我的输出文件中只写入了 548 KB。

以下方法正在收集、计数和写入数据 - 在我最近的更改之前,它的性能相当不错,除了一些性能问题我打算通过将它变成另一个的扩展来解决系列课程。

class DownloadThread : StreamReader
{
    protected override void Cycle()
    {
        if (this.IsComplete)
        {
            this.FireEvent("OnComplete", new Event(this, "DownloadThread has confirmed completion of the targetted download."));
            this.Stop();
            return;
        }
        else if ((this._InputSource = this.GetResponseStream(this.RemotePath)) == null)
        {
            this.FireEvent("OnException",new Event(this,"DownloadThread could not execute. A Response Stream could not be retrieved from the Input Source '" + this.RemotePath + "'."));
            this.Stop();
            return;
        }
        else
        {
            try
            {
                this._StartTime = DateTime.Now;

                Byte[] Bytes = new Byte[4096];

                while ((this.BytesLastRead = this.Read(Bytes, 0, 4096)) > 0)
                {
                    this.LocalStream.Write(Bytes, 0, DataMetrics.Length(Bytes));
                    this.LocalStream.Flush();

                    this.BytesSinceLast += this.BytesLastRead;
                    this.TotalRead += this.BytesLastRead;

                    this.TriggerProgress();

                    continue;
                }
                return;
            }
            catch (Exception e)
            {
                this.FireEvent("OnException", new Event(this, "An exception was encountered while reading data for the download." + Environment.NewLine + e.Message + Environment.NewLine + e.StackTrace));
                return;
            }
        }
    }

    protected override Stream GetResponseStream(string RemotePath)
    {
        this.Request = (FtpWebRequest)FtpWebRequest.Create(this.RemotePath);

        if (this.Credentials != null)
            this.Request.Credentials = this.Credentials;

        this.Response = (FtpWebResponse)this.Request.GetResponse();

        Stream ResponseStream = this.Response.GetResponseStream();

        return ResponseStream;
    }
}

值得注意的是——在任何人得出结论之前——这个“循环”方法会自动在其自己的线程中的循环内运行;并将每 'ThreadDelay' 毫秒重复一次(假设它返回)。

该类中的'LocalStream'变量如下:

    protected Stream _LocalStream = null;

    protected Stream LocalStream
    {
        get
        {
            if (this.LocalFile == null)
                return null;
            else if (this._LocalStream == null)
            {
                if (!this.LocalDirectory.Exists)
                    this.LocalDirectory.Create();

                this._LocalStream = this.LocalFile.OpenWrite();

                return this.LocalStream;
            }
            else
                return this._LocalStream;
        }
    }

我认为这可能会导致一些冲突 - 并确保一些线程安全在我的待办事项列表中,但我目前在这个领域没有遇到任何问题 - 我只是假设有人可能想要采取一眼。

根据 'DownloadThread.Read' 方法 - 因为我确定有人会好奇......这是从我自己的 'StreamReader' 类继承的;再次从我的“InputReader”类继承。附属字段包括在下面。

    protected Object _InputSource = null;

    public Object InputSource
    {
        get
        {
            return this._InputSource;
        }
    }

    public Stream InputStream
    {
        get
        {
            if (this.InputSource == null)
                return null;
            else
            {
                try
                {
                    return (Stream)this.InputSource;
                }
                catch (Exception)
                {
                    return null;
                }
            }
        }
    }

    public override double Read(byte[] buffer, int offset, int count)
    {
        try
        {
            return this.InputStream.Read(buffer, offset, count);
        }
        catch (Exception e)
        {
            this.Stop();
            this.FireEvent("OnException", new Events.Event(this, "An exception was encountered while reading from the InputStream." + Environment.NewLine + e.Message + Environment.NewLine + e.StackTrace));
            return 0;
        }
    }

现在 - 重申一下 - 我的问题是,由于某种原因,我收到的数据没有被正确地推送到文件中。我即将完成 ~1 gig 下载,因为我正在完成输入,到目前为止没有抛出异常并且流没有“崩溃” - 但我的输出文件只有 17 兆。

再等待 30 秒以完成此下载后,我的 1.05 gig 文件已变成 18 meg 文件;但我看不出为什么上面的代码不能正确处理这个问题。

任何人的建议都会很棒。

【问题讨论】:

  • 39 次浏览,但没有一个赞成票...我的问题没有正确形成吗?提供的数据不够吗?我不明白。
  • 你可以看到一个来自微软的例子,它更易读、更简单msdn.microsoft.com/en-us/library/ms229711%28v=vs.110%29.aspx
  • 我很欣赏这个参考,但这是我最初的代码的来源——这段代码和我的唯一真正的区别是上面提到的执行一个“ReadToEnd”,而我的读取是块,所以我可以更好跟踪下载了多少。重申一下 - 下载一直运行到文件末尾,并且正在提取所有数据,但我的本地文件没有被写入正在读取的完整数据。
  • 您使用的是什么技术?
  • 您似乎总是写入文件的开头,即在您调用 Stream.Write 时偏移量为 0。您能否提供代码的简化版本来说明您尝试修复的行为?

标签: c# ftp stream iostream ftpwebrequest


【解决方案1】:

我认为问题可能出在这行代码中:

this.LocalStream.Write(Bytes, 0, DataMetrics.Length(Bytes));

我假设您的DataMetrics.Length() 方法返回错误的字节数,因此我建议您尝试:

this.LocalStream.Write(Bytes, 0, this.BytesLastRead);

改为。

【讨论】:

  • 嘿@Yuriy;感谢您的尝试,但我已经尝试交换这些变量无济于事。我也可以说(至少在前几十次调试过程中)DataMetrics.Length 方法返回了一个准确的数字。如果我只是将静态“4096”放入我的 Write 中,似乎我几乎会得到相同的结果(我可能会尝试看看会发生什么)。
  • @DigitalJedi805,在深入研究FileStream.Flush() 内部之后,我发现它称之为过载Flush(flushToDisk: false),归结为以下代码:this.FlushInternalBuffer(); if(flushToDisk && this.CanWrite){ this.FlushOSBuffer(); } 所以从外观上看,你应该改变您的 LocalStream 属性类型为 FileStream 并调用 Flush(true) 或简单地将您的 while 循环包含在 using 语句 using(this.LocalStream){ while ... } 中,并让 CLR 处理流的处置、关闭和刷新。
【解决方案2】:

值得注意的是——在任何人下结论之前——这是 'cycle' 方法在自己的循环内自动运行 线;并且将每 'ThreadDelay' 毫秒重复一次(假设它 返回)。

我的第一个猜测是操作系统正在丢弃网卡上的数据,因为它没有主动出队,这就是为什么你得到 17mb 而不是 1gb。

【讨论】:

    猜你喜欢
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 1970-01-01
    • 2017-04-30
    • 2019-07-17
    • 1970-01-01
    • 2014-01-08
    相关资源
    最近更新 更多