2016-07-23 8 views
0

bbcフィードを読み込んで、ニュースオブジェクトを含むjsonファイルを作成する必要があるコンソールアプリケーションを作成しています。毎時間1時間に実行されます。私の問題は、それは親オブジェクトを複製しているが、なぜ私は理解していないということです。奇妙なことは、時間通りに実行すると機能するということですが、時間の5分前に実行すると、この複製された親要素が作成されます。Jsonファイルに重複するエントリ。 C#

public static void Main(string[] args) 
    { 
     // get the starting time of app. 
     DateTime startingTime = DateTime.Now; 
     int minute = 1; 
     int hoursRun = 0; 
     bool folderCreated = false; 
     int n = startingTime.AddHours(hoursRun).Hour; 
     //this will be the folder path for feeds. 
     string feedsFolderPath = Environment.GetFolderPath(
        System.Environment.SpecialFolder.Desktop) + "\\feeds"; 

     // uri for feeds. 
     string bbcURI = "http://feeds.bbci.co.uk/news/uk/rss.xml"; 

     while (true) 
     { 
      // check the hour and if it is more than 1 minutes past the hour wait for the next hour. 
      if (DateTime.Now.Hour == startingTime.AddHours(hoursRun).Hour && DateTime.Now.Minute < minute) 
      { 
       //get feeds 
       News bbcNewsFeed = ProcessFeedHelper.GetFeeds(bbcURI); 

       // if this is the first run go ahead and create a json file. 
       if (hoursRun == 0) 
       { 
        if (!folderCreated) 
        { 
         ProcessFeedHelper.CreateFolder(feedsFolderPath); 
         folderCreated = true; 
        } 
        ProcessFeedHelper.CreateJsonFile(bbcNewsFeed, feedsFolderPath); 

       } 
       else 
       { 
        //if it is the second time then we need to check for duplicates. 
        ProcessFeedHelper.RemoveDuplicatesFeeds(bbcNewsFeed, feedsFolderPath); 
        ProcessFeedHelper.CreateJsonFile(bbcNewsFeed, feedsFolderPath); 
       } 

       // if it is the 23rd hour then we need to reset the counter and detele all files in folder. 
       if (hoursRun == 23) 
       { 
        hoursRun = 0; 

        ProcessFeedHelper.DeleteFilesInDirectory(feedsFolderPath); 
       } 
       else 
       { 

        //others increment the hoursrun. 
        hoursRun++; 
       } 


       bbcNewsFeed = null; 

      } 
     } 
    } 
} 

helperClassの

public static News GetFeeds(String aURI) 
    { 
     News newsFeed; 

      //instantiate xmlreader and point to uri 
      using (System.Xml.XmlReader reader = System.Xml.XmlReader.Create(aURI)) 
      { 
       //load the feed into SyndicationFeed Object 
       SyndicationFeed feed = SyndicationFeed.Load(reader); 

       newsFeed = new News(); 

       List<NewsItem> newsItemList = new List<NewsItem>(); 


       foreach (var item in feed.Items) 
       { 
        // BBC Feed parent element titles change throughout the day but I have not managed to get them all. 
        // Could potentially break however, the logic is correct. 
        // Here we create the parent element object. 
        if (item.Title.Text == "BBC News Channel" || item.Title.Text == "BBC News at 10") 
        { 

         newsFeed.title = item.Title.Text; 
         newsFeed.link = item.Id; 
         newsFeed.description = item.Summary.Text; 

        } 
        else 
        { 
         NewsItem newsItem = new NewsItem(); 
         newsItem.title = item.Title.Text; 
         newsItem.link = item.Id; 
         newsItem.description = item.Summary.Text; 
         newsItem.publishDate = FormatDate(item.PublishDate.ToString()); 

         //Add it to parent object. 
         newsItemList.Add(newsItem); 
        } 
       } 

       newsFeed.items = newsItemList; 
       //close reader once we have finished reading feed and return feed object. 
       reader.Close(); 

      } 
      return newsFeed; 
    } 
    /// <summary> 
    /// Creates a folder at a specified path. 
    /// </summary> 
    /// <param name="aPath"></param> 
    public static void CreateFolder(string aPath) 
    { 
     System.IO.Directory.CreateDirectory(aPath); 
    } 
    /// <summary> 
    /// Creates a Json formatted file based on a news object passed through. 
    /// </summary> 
    /// <param name="aNews"></param> 
    /// <param name="aPath"></param> 
    public static void CreateJsonFile(News aNews, string aPath) 
    { 

      string filePath = aPath + "\\" + DateTime.Now.ToString("yyyy-MM-dd-HH") + ".json"; 


      //serialises objects in news Object and appends a file. 
      string jsonFile = JsonConvert.SerializeObject(aNews, Newtonsoft.Json.Formatting.Indented); 

      aNews = JsonConvert.DeserializeObject<News>(jsonFile); 

      jsonFile = JsonConvert.SerializeObject(aNews, Newtonsoft.Json.Formatting.Indented); 


      File.AppendAllText(@filePath, jsonFile); 

      Console.WriteLine(jsonFile); 


    } 

    /// <summary> 
    /// Removes Duplicate news articles in new feeds if they are already stored in files. 
    /// </summary> 
    /// <param name="aNews"></param> 
    /// <param name="aPath"></param> 
    public static void RemoveDuplicatesFeeds(News aNews, string aPath) 
    { 
     try 
     { 
      //get paths to all files. 
      string[] filesInDirectory = Directory.GetFiles(aPath); 

      List<News> newsInFiles = new List<News>(); 
      News newsInFile; 

      // loop through files in directory. 
      foreach (string aFile in filesInDirectory) 
      { 
       //Read files file and deserialise the news object putting it in a news collection. 
       StreamReader reader = new StreamReader(aFile); 
       string fileContent = reader.ReadToEnd(); 
       newsInFile = Newtonsoft.Json.JsonConvert.DeserializeObject<News>(fileContent); 

       newsInFiles.Add(newsInFile); 
       reader.Close(); 
      } 
      //only go in here if there is the recent feed has news items. 
      if (aNews.items.Count > 0) 
      { 
       foreach (News aNewsInFile in newsInFiles) 
       { 
        // put news list into new news list so the next loop doesn't crash. 
        List<NewsItem> tempNewsList = new List<NewsItem>(aNews.items); 
        foreach (NewsItem aNewsItemFromCurrentFeed in tempNewsList) 
        { 
         //check that the current news item is not already in files saved. 
         var newsItemAlreadyExists = from nItems in aNewsInFile.items 
                where nItems.title == aNewsItemFromCurrentFeed.title 
                where nItems.publishDate == aNewsItemFromCurrentFeed.publishDate 
                where nItems.link == aNewsItemFromCurrentFeed.link 
                where nItems.description == aNewsItemFromCurrentFeed.description 
                select nItems; 
         // if item already stored in file then we must remove it as we don't want it. 
         if (newsItemAlreadyExists.First() != null) 
         { 
          if (aNews.items.Contains(aNewsItemFromCurrentFeed)) 
          { 
           aNews.items.Remove(aNewsItemFromCurrentFeed); 
          } 
         } 
        } 
       } 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Unexpected Error"); 
     } 
    } 
    /// <summary> 
    /// Deletes all the files in a directory(path specified in parameter). 
    /// </summary> 
    /// <param name="directoryPath"></param> 
    public static void DeleteFilesInDirectory(string directoryPath) 
    { 
     try 
     { 
      //create files collection and directory object. 
      List<FileInfo> importFiles = new List<FileInfo>(); 
      DirectoryInfo tempDirectory = new DirectoryInfo(directoryPath); 

      //get all files in directory. 
      importFiles.AddRange(tempDirectory.GetFiles()); 

      //if the number of files in the directory are greater than zero then delete them. 
      if (importFiles.Count > 0) 
      { 
       for (int i = 0; i < importFiles.Count; i++) 
        importFiles[i].Delete(); 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Unexpected Error"); 
     } 
    } 
    /// <summary> 
    /// Formats a string to ddd, mm yyyy hh:ss gmt 
    /// </summary> 
    /// <param name="aDate"></param> 
    /// <returns></returns> 
    private static String FormatDate(String aDate) 
    { 
     try 
     { 
      //split string 
      char[] delimiters = { ' ', ',', ':', '/' }; 
      string[] tokens = aDate.Split(delimiters); 
      int year = int.Parse(tokens[2]); 
      int month = int.Parse(tokens[1]); 
      int day = int.Parse(tokens[0]); 
      int hh = int.Parse(tokens[3]); 
      int mm = int.Parse(tokens[4]); 
      int ss = int.Parse(tokens[5]); 

      //create date time object. and add gmt to end of string. 
      DateTime date = new DateTime(year, month, day, hh, mm, ss); 
      return date.ToUniversalTime().ToString("r"); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Unexpected Error"); 
     } 
     return ""; 
    } 
} 

親クラス

class News 
{ 
    public string title { get; set; } 
    public string link{ get; set; } 
    public string description{ get; set; }   
    public IList<NewsItem> items{ get; set; } 


} 

子クラス

class NewsItem 
{ 
    public string title { get; set; } 
    public string description { get; set; } 
    public string link { get; set; } 
    public string publishDate { get; set; } 

} 

ファイルの例

(端部を持っていると仮定していません)

if (DateTime.Now.Hour == startingTime.AddHours(hoursRun).Hour && DateTime.Now.Minute < minute) 

は、私は上記の私のコメントで指摘したように、それが探しているので、あなたは、8時59分でプログラムを起動すると仮定します。私は問題ここで競合状態かもしれないと思う

{ 
    "title": "BBC News Channel", 
    "link": "http://www.bbc.co.uk/news/10318089", 
    "description": "Britain's most-watched news channel, delivering breaking  news and analysis all day, every day.", 
    "items": [ 
    { 
     "title": "Dover ferry port chaos leads to 14-hour traffic jams", 
     "description": "Delays at the Port of Dover have caused up to 14-hour tailbacks on the A20 /M20 with Kent Police warning disruption could last for another two days.", 
     "link": "http://www.bbc.co.uk/news/uk-england-kent-36873632", 
     "publishDate": "Sat, 23 Jul 2016 19:38:36 GMT" 
    }, ] 
} { 
    "title": "BBC News Channel", 
    "link": "http://www.bbc.co.uk/news/10318089", 
    "description": "Britain's most-watched news channel, delivering breaking news and analysis all day, every day.", 
    "items": [] 
} 
+1

あなたは5分前にそれを実行した場合時間は、私はそれが約23時間何もしないことを期待するだろう...私の理解は間違っていますか?あなたが8時55分にそれを開始すると、私はあなたの状態が(擬似コード) "時間== 8、分== 0"であり、別の23時間5分は起こらないと思うでしょう。 – smarx

答えて

1

時間は8分、0分になります。これは23時間ほどではないと思いますが...

この条件を確認するとDateTime.Now.Hour == startingTime.AddHours(hoursRun).Hourと返されますtrueは時間が現在8であるため、実行は次の状態を確認するために進みます。DateTime.Now.Minute < minute。時間が経過したので、条件がチェックされた時点で9時です。したがって、両方の条件が真であり、コードが実行されます。 (ファイルは2016-07-23-09.jsonと呼ばれる作成されます。)

hoursRunがインクリメントされ、それが今、ループの次の反復9.

だ、時間は午前九時00分05秒のようなものです。両方の条件が真である(時間は9、分は0)ので、コードは同じファイル(2016-07-23-09.json)に追加されて実行されます。

私の勘では、あなたが同じ時間の時間と分のコンポーネントをチェックしているを確認しますこれは、おそらく最小の修正プログラムは、これを行うことであろう、右の場合:

while (true) 
{ 
    var now = DateTime.Now; 
    if (now.Hour == startingTime.AddHours(hoursRun).Hour && now.Minute < minute) 
    { 

私も入れてお勧めしますwhileループのスリープステートメント...このタイトなビジーループで大量のCPUを使用している可能性があります。

EDIT

ああ、また、あなたはおそらく最初の場所で23時間待つという意味ではありませんでした。 :-)簡単な修正としてどこでも+1を使用することができます(ただし、プログラムを8:00に実行すると、最初のファイルを書き込むために9:00まで待つことになります)。

EDIT 2

あなたはこれがループを構築するための簡単な方法かもしれ「時間上で」実行されている気にしない場合:

DateTime lastRun = DateTime.MinValue; 

while (true) 
{ 
    // sleep for 10 minutes at a time until an hour has passed 
    while ((DateTime.UtcNow - lastRun) < TimeSpan.FromHours(1)) 
    { 
     Thread.Sleep(TimeSpan.FromMinutes(10)); 
    } 

    // do work in here 

    // remember the last time we did work 
    lastRun = DateTime.UtcNow; 
} 
+0

ありがとう、今朝のテストの後、これが該当します。自分自身で少し近視眼的な解決策。しかし、シリアライゼーションは大きな問題でした。私は、ファイル作成セクションをメインクラスにすることを決めました。ここでは、これは起こっていないようです。これは、メソッドスタックのローカルコピーを作成していて、まだヒープを参照していたために起こったと思います。そしてそれは両方を直列化した。私はこれがうまく機能しないかもしれないと理解していますが、それ以外は寝るのに役立ちます – spaga

関連する問題