2012-10-23 5 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 년 12 월 10 일에 출시 된 protobuf-net V2 r594를 사용하고 있습니다. 이 버전에서 작동하지 않으면 이전 버전 중 하나를 사용하려고 시도하고 있습니다. 누군가 내가 잘못하고있는 것을 말해 줄 수 있습니까?

답변

3

구현 된 속성을 자동으로 사용하고 목록의 이니셜 라이저 (DailyData)를 추가하고 명시 적으로 참조하여 코드의 작업 버전을 재구성하려고했습니다 (사용자의 BaseModel이 없으므로). Google 코드에서 r594. 내가 할 수있는 유일한 오류는 다음과 같습니다

이 바르게 읽기 전용 속성에 데이터를 역 직렬화 할 수 없기 때문에, 의미가 속성 ClimateDailyData.JulianDay

에 대한 변경 사항을 적용 할 수 없습니다, 그래서이 제거

하나에서 직렬화 마커 :

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

그것은 괜찮 았는데 그 후. 내가 명령 프레임 워크를 가지고 있지 않기 때문에, 내가 가진 :

InitSomeDataForSerialization 단지 일부 값 (그들은 개인 세터를 갖고 있기 때문에, 내가 Main에 할 수 없어) 설정
static class Program 
{ 
    static void Main() 
    { 
     var climateFile = new ClimateFile(); 
     climateFile.InitSomeDataForSerialization(); 

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

:

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

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

그리고 ... 작동합니다.

직감적으로 "전체"대신 "CoreOnly"를 참조하면 어떤 일이 발생하는지 확인했지만 Serializer.Serialize<T>Serializer.Deserialize<T>이 없기 때문에 컴파일을 거부합니다.

도와 드리겠습니다.하지만 제가 말할 수있는 한, 잘못된 것은 없습니다.

것들 내가 다음 제안 :

  • 정확히 어떤 파일을 를 확인하십시오 (아래 수정 참조) 모든 내부 - 예외를 포함하여이 예외에 무슨 일의 전체 스택 추적을 보여 당신은 594 zip ("What Files Do Need 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이나 꽤 당혹 스럽다는 것을 참조 했음에 틀림 없다고 생각한다. –

관련 문제