2012-10-23 44 views
1

我最近決定使用protobuf-net來序列化我的應用程序用來查看純文本數據解析是否有任何性能增益的大型純文本數據文件。protobuf-net不支持指定方法

數據類:

[ProtoContract] 
public class ClimateFile : BaseModel 
{ 
    #region Properties 
    [ProtoMember(1)] 
    public double Latitude { get { return GetValue(() => Latitude); } private set { SetValue(() => Latitude, value); } } 

    [ProtoMember(2)] 
    public double Longitude { get { return GetValue(() => Longitude); } private set { SetValue(() => Longitude, value); } } 

    [ProtoMember(3)] 
    public string Notes { get { return GetValue(() => Notes); } set { SetValue(() => Notes, value); } } 

    [ProtoMember(4)] 
    public DateTime MinDate { get { return GetValue(() => MinDate); } private set { SetValue(() => MinDate, value); } } 

    [ProtoMember(5)] 
    public DateTime MaxDate { get { return GetValue(() => MaxDate); } private set { SetValue(() => MaxDate, value); } } 

    [ProtoMember(6)] 
    public List<ClimateDailyData> DailyData { get { return GetValue(() => DailyData); } private set { SetValue(() => DailyData, value); } } 
    #endregion 

    #region Method 
    public static ClimateFile Load(string filePath) 
    { 
     try 
     { 
      var ext = Path.GetExtension(filePath).ToUpper(); 
      if (ext == ".P51") 
       return new ClimateFile(filePath); 
      else if (ext == ".P51X") 
      { 
       ClimateFile climateFile; 
       using (var file = File.OpenRead(filePath)) 
       { 
        climateFile = Serializer.Deserialize<ClimateFile>(file); 
       } 
       return climateFile; 
      } 
     } 
     catch (Exception e) 
     { 
      throw new InvalidDataException(String.Format("The file \"{0}\" could not be opened, {1}", filePath, ExceptionUtilities.JoinExceptionMessages(e))); 
     } 

     throw new ArgumentException("filePath was not a .P51 or .P51X file."); 
    } 

    public void LoadP51File(string filePath) 
    { 
     List<string[]> lines = GetFileLines(filePath); 
     Latitude = double.Parse(lines[0][0]); 
     Longitude = double.Parse(lines[0][1]); 
     for (int i = 2; i < lines[0].Length; ++i) 
      Notes += String.Format("{0} ", lines[0][i]); 
     MinDate = GetDate(lines[2][0]); 
     MaxDate = GetDate(lines[lines.Count - 1][0]); 

     // Parse daily data 
     lines.RemoveRange(0, 2); 
     var dailyData = lines.Select(row => new ClimateDailyData() 
      { 
       DataDate = GetDate(row[0]), 
       MaxTemperature = double.Parse(row[2]), 
       MinTemperature = double.Parse(row[3]), 
       Rainfall = double.Parse(row[4]), 
       Evaporation = double.Parse(row[5]), 
       SolarRadiation = double.Parse(row[6]) 
      }).ToList(); 
     DailyData = dailyData; 
    } 

    public void SaveP51XFile(string filePath) 
    { 
     using (var file = File.Create(filePath)) 
     { 
      Serializer.Serialize<ClimateFile>(file, this); 
     } 
    } 

    public List<string[]> GetFileLines(string filePath) 
    { 
     var rows = new List<string[]>(); 
     var cells = new List<string>(); 
     var cell = new StringBuilder(); 
     using (var fs = new BufferedStream(File.OpenRead(filePath))) 
     { 
      int buffer; 
      while ((buffer = fs.ReadByte()) != -1) 
      { 
       char nextChar = (char)buffer; 

       if (nextChar >= '!') // If the character is a non-whitespace printable character 
       { 
        cell.Append(nextChar); 
        continue; 
       } 

       if (nextChar == ' ' || nextChar == '\t') 
       { 
        if (cell.Length > 0) 
        { 
         cells.Add(cell.ToString()); 
         cell.Clear(); 
        } 
        continue; 
       } 

       if (nextChar == '\r' || nextChar == '\n') 
       { 
        if (cell.Length > 0) 
        { 
         cells.Add(cell.ToString()); 
         cell.Clear(); 
        } 
        if (cells.Count > 0) 
        { 
         rows.Add(cells.ToArray()); 
         cells.Clear(); 
        } 
        continue; 
       } 
       throw new InvalidDataException("The climate file contains unknown characters."); 
      } 

      if (cell.Length > 0) 
       cells.Add(cell.ToString()); 
      if (cells.Count > 0) 
       rows.Add(cells.ToArray()); 
     } 
     return rows; 
    } 

    public DateTime GetDate(string date) 
    { 
     return DateTime.ParseExact(date, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None); 
    } 

    public override void Dispose() 
    { 
     if (Disposed) 
      return; 
     if (DailyData != null) 
      foreach (ClimateDailyData dailyData in DailyData) 
       dailyData.Dispose(); 
     base.Dispose(); 
    } 
    #endregion 

    #region Initialization 
    public ClimateFile() 
    { 
    } 

    public ClimateFile(string filePath) 
    { 
     LoadP51File(filePath); 
    } 
    #endregion 
} 

收集數據類:

[ProtoContract] 
public class ClimateDailyData : BaseModel 
{ 
    [ProtoMember(1)] 
    public DateTime DataDate { get { return GetValue(() => DataDate); } set { SetValue(() => DataDate, value); } } 

    [ProtoMember(2)] 
    public int JulianDay { get { return DataDate.DayOfYear; } } 

    [ProtoMember(3)] 
    public double MaxTemperature { get { return GetValue(() => MaxTemperature); } set { SetValue(() => MaxTemperature, value); } } 

    [ProtoMember(4)] 
    public double MinTemperature { get { return GetValue(() => MinTemperature); } set { SetValue(() => MinTemperature, value); } } 

    [ProtoMember(5)] 
    public double Rainfall { get { return GetValue(() => Rainfall); } set { SetValue(() => Rainfall, value); } } 

    [ProtoMember(6)] 
    public double Evaporation { get { return GetValue(() => Evaporation); } set { SetValue(() => Evaporation, value); } } 

    [ProtoMember(7)] 
    public double SolarRadiation { get { return GetValue(() => SolarRadiation); } set { SetValue(() => SolarRadiation, value); } } 
} 

系列化命令:

public ICommand ImportP51 
    { 
     get 
     { 
      return new RelayCommand(delegate 
       { 
        OpenFileDialog openDialogue = new OpenFileDialog() 
        { 
         AddExtension = true, 
         CheckPathExists = true, 
         CheckFileExists = true, 
         DefaultExt = ".p51", 
         Filter = "Climate Files|*.p51", 
         InitialDirectory = DataPath, 
         Multiselect = false, 
         Title = "Select a File to Open" 
        }; 

        if ((bool)openDialogue.ShowDialog()) 
        { 
         string filePath = String.Empty; 
         try 
         { 
          filePath = openDialogue.FileName; 
          var climate = new Climate(); 
          climate.FilePath = filePath; 
          var savePath = String.Format("{0}\\{1}.p51x", ClimateDataPath, Path.GetFileNameWithoutExtension(filePath)); 
          climate.FileData.SaveP51XFile(savePath); 
         } 
         catch (Exception e) 
         { 
          MessageBox.Show(String.Format("The file \"{0}\" could not be opened, {1}", filePath, ExceptionUtilities.JoinExceptionMessages(e)), "Invalid File"); 
         } 
        } 
       }); 
     } 
    } 

當執行ImportP51,我得到的例外 「規定的方法不支持」 ,我使用的是2012年10月12日發佈的protobuf-net V2 r594我正在考慮嘗試使用以前版本之一,如果我無法使用此版本的話。有人可以告訴我我做錯了什麼嗎?

回答

3

我試圖重構代碼的工作版本(因爲我沒有你BaseModel做),我已經通過使用自動實現的屬性,並添加一個初始化的名單(DailyData),並明確完成參考r594從谷歌代碼。我得到的唯一錯誤是:

不能將更改應用於財產ClimateDailyData.JulianDay

這是有道理的,因爲它不能正確地反序列化數據到一個只讀屬性,所以我刪除了從一個序列化標記:

// [ProtoMember(2)] removed - serialized implicitly via DataData 
public int JulianDay { get { return DataDate.DayOfYear; } } 

之後,它工作得很好。由於我沒有你的命令的框架,我有:

static class Program 
{ 
    static void Main() 
    { 
     var climateFile = new ClimateFile(); 
     climateFile.InitSomeDataForSerialization(); 

     climateFile.SaveP51XFile("foo.P51X"); 
     var clone = ClimateFile.Load("foo.P51X"); 
    } 
} 

其中InitSomeDataForSerialization只是設置一些值(因爲他們有私人制定者,我不能這樣做,在Main):

public void InitSomeDataForSerialization() 
{ 
    Longitude = 10; Latitude = 4; Notes = "Test"; 

    DailyData.Add(
     new ClimateDailyData { DataDate = DateTime.Today, MinTemperature = 12, MaxTemperature = 35} 
    ); 
} 

而且...它的工作原理。

在預感上,我檢查瞭如果引用「CoreOnly」而不是「Full」,會發生什麼情況,但然後拒絕編譯,因爲Serializer.Serialize<T>Serializer.Deserialize<T>不存在。

我很樂意提供幫助,但據我所知,沒有什麼是錯的。

事我會在下一個建議:

  • 顯示在這個異常,包括任何內部異常會發生什麼的全堆棧跟蹤(請參閱下面的修復)
  • 請準確檢查的文件你在594壓縮文件中引用了這個文件(看看「What Files Do I Need.txt」,但我猜你正確的是「Full/net30/...」; nuget包會自動配置最合適的文件)
  • 請顯示一個完全可重複的例子,即在那裏我可以按F5和看到確切的異常(我不得不改變代碼的例子爲它來編譯,這意味着我不再測試同樣的事情)

修正了正確的例外包裝:

catch (Exception e) 
{ 
    throw new InvalidDataException(String.Format("The file \"{0}\" could not be opened", filePath), e); 
} 
+0

嘿,我沒有意識到,在那個例子中,我仍然在JulianDay上有ProtoMember,我確定它應該檢查我正在粘貼的東西。但是我通過將兩個版本恢復到2011年12月發行版來實現。我在你的項目頁面添加了一個問題,如果我編譯了最新版本,它甚至可以工作,而不是如果我使用了從下載部分預編譯的V2 r594版本。如果可以的話,我真的很想使用你最近發佈的一個特色版本。 –

+0

@Alex在我的示例項目中,我明確地使用了下載的r594。我不能讓它失敗。你還能讓它失敗嗎?如果是這樣,你能告訴我你正在引用哪個dll嗎? (如果這很棘手,以字節爲單位的文件大小應該是足夠的,我猜) –

+0

好吧,這很奇怪......我從下載部分再次下載它,這次它工作。我想我一定是引用了錯誤的dll或者是很尷尬的東西... –

相關問題