从文件中连续下载最新更改

时间:2011-01-17 21:09:40

标签: c# download

我不知道如何开始这个。我对下载文件几乎没有任何了解,除了我曾经遵循的下载简单文本文件的教程。

请允许我解释一下我应该下载哪种文件。我有一个记录本地演示的游戏。通过添加所谓的帧,该文件不断增长。 我们要实现的目标是完全下载此文件,并在下载后仅获取此文件的最新添加内容,而不是再次获取整个文件。这使我们可以在远程系统创建时播放演示。

我们已经使用wget成功完成了这项工作,但我们希望围绕下载机制编写一个用户友好的客户端。那么,wget做的是检查文件是否已更改,然后仅获取最后添加的字节。该文件增长约40KBps。这样我们就可以轻松地将流设置为远程系统。

不能一直重新下载整个文件。我们设法检查在线文件是否已更改,但是当它检测到更改时,它只是下载了整个文件。这些文件最终可能增长到15Mb,因为这个尺寸,我们无法真正提供快速下载并跳到游戏中的当前帧。

来源,教程,甚至只是下载代码及其解释如何工作将有助于我们的项目。

提前致谢。

4 个答案:

答案 0 :(得分:3)

简单实施

  • 执行HEAD请求
  • 获取内容长度
  • 使用字节范围来请求文件的新部分(通过比较本地长度和内容长度 - 就像下载管理器恢复功能一样)
  • 将其附加到您的本地文件

完成。

答案 1 :(得分:0)

首先,不要将其视为文件。听起来你正在处理的是随着时间推移的修改数据包流。如果本地计算机上的基本文件丢失或过期,那么您需要进行一些额外的下载来建立基础,但是一旦到位,大多数时候将使用的代码就是接收更新帧并应用它们通过附加或覆盖原始数据到基地。

将此视为版本控制系统可能会有所帮助,或者至少熟悉版本控制术语并使用类似的概念来处理您的解决方案。例如:每个修订都有一个唯一的签名(通常是实际数据的哈希或摘要),并且有一个与签名相关的订单。如果您可以要求客户端始终按顺序获取更新帧(如果客户端还没有帧150-199,则不允许客户端具有帧200),那么客户端对服务器的请求可能只是“我有xyz。我最新需要什么?“

如果您的数据更改很快发生,特别是如果它们是多个客户端同时在共享文档上执行的结果,那么单独使用时间签名可能不够独特,不可靠。时间签名+内容的数字哈希可能是一个好主意,我相信这是大多数版本控制系统以某种方式使用的。

考虑使用版本控制系统作为核心实现并围绕它构建服务器和客户端而不是编写自己的服务器和客户端也可能是值得的。如果您对应用程序有任何要求,允许用户“返回”以前的版本或获取当前文档并进行其他人看不到的私人更改(版本控制术语中的专用分支),这将特别有用。

答案 2 :(得分:0)

好的,我已经阅读了一些在这里提出的额外问题: 我们通过HTTP访问该文件。它被推送到网络服务器上。推送机制是我们稍后可以处理的。现在我们正在使用丑陋的批处理文件启动程序并在本地检查更改,但这对用户来说是不可见的,所以以后会担心。

对于其他两个问题,这大致是它的工作原理。 连接到游戏服务器的游戏在本地记录演示 - >此演示上传到网站空间 - >这个演示应该下载到本地用户,然后可以播放演示。

答案 3 :(得分:0)

假设您正在使用HTTP请求来检索文件,以下内容应该对您有所帮助。我利用上次修改的内容和内容长度值,并轮询文件以进行更改。您可能希望根据触摸文件而不进行更新来更改该内容,或者出于任何原因可能更改的ehader这不是寻找更改的好方法。但是,这应该会让你朝着正确的方向前进。

如果你真的有动力,你可以将轮询代码放在我在程序中使用的线程中,创建一个“FileUpdatedEventArgs”类并通过事件传回更改。 - 或许你只是坚持自己投票。 ; - )

public class SegmentedDownloader
{
    #region Class Variables

    /// <summary>
    /// Date the file was last updated
    /// Used to compare the header file for changes since
    /// </summary>
    protected DateTime LastModifiedSince = default(DateTime);

    /// <summary>
    /// Length of the file when it was last downlaoded
    /// (this will be used to provide a content offset on next download)
    /// </summary>
    protected Int64 ContentLength = default(Int64);

    /// <summary>
    /// The file we're polling
    /// </summary>
    protected Uri FileLocation;

    #endregion

    #region Construct

    /// <summary>
    /// Create a new downloader pointing to the specific file location
    /// </summary>
    /// <param name="URL">URL of the file</param>
    public SegmentedDownloader(String URL)
        : this(new Uri(URL))
    {
    }

    public SegmentedDownloader(Uri URL)
    {
        this.FileLocation = URL;
    }

    #endregion

    /// <summary>
    /// Grab the latests details from the page
    /// </summary>
    /// <returns>Stream with the changes</returns>
    public Stream GetLatest()
    {
        Stream result = null;

        try
        {
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(this.FileLocation);
            if (this.ContentLength > 0)
                webRequest.AddRange(this.ContentLength);
            webRequest.IfModifiedSince = this.LastModifiedSince;

            HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();

            Int64 contentLength = webResponse.ContentLength;
            DateTime lastModifiedSince = Convert.ToDateTime(webResponse.Headers["Last-Modified"]);
            if (contentLength > 0 || lastModifiedSince.CompareTo(this.LastModifiedSince) > 0)
            {
                result = webResponse.GetResponseStream();
                this.ContentLength += contentLength;
                this.LastModifiedSince = lastModifiedSince;
            }
        }
        //catch (System.Net.WebException wex)
        //{ // 302 = unchanged
        //    Console.WriteLine("Unchanged");
        //}
        catch (Exception)
        {
            result = null;
        }
        return result;
    }
}

可以这样使用:

class Program
{
    static TimeSpan updateInterval = TimeSpan.FromSeconds(5);
    static Thread tWorker;
    static ManualResetEvent tReset;

    static void Main(string[] args)
    {
        tReset = new ManualResetEvent(false);
        tWorker = new Thread(new ThreadStart(PollForUpdates));
        tWorker.Start();

        Console.Title = "Press ENTER to stop";
        Console.ReadLine();

        tReset.Set();
        tWorker.Join();
    }

    static void PollForUpdates()
    {
        SegmentedDownloader segDL = new SegmentedDownloader("http://localhost/dataFile.txt");
        do
        {
            Stream fileData = segDL.GetLatest();
            if (fileData != null)
            {
                using (StreamReader fileReader = new StreamReader(fileData))
                {
                    if (fileReader.Peek() > 0)
                    {
                        do
                        {
                            Console.WriteLine(fileReader.ReadLine());
                        }
                        while (!fileReader.EndOfStream);
                    }
                }
            }
        }
        while (!tReset.WaitOne(updateInterval));
    }
}