2020년 1월 30일 목요일

RapidJson Traverse Example for MFC

이번에 소개 할것은 JsonCPP 라이브러리만 쓰다 속도의 이슈가 있어서 다른 Json 라이브러리를 찾다가

알게된 "RapidJson" 라이브러리 입니다.

라이브러리는 헤더파일로 구성되어 별도의 라이브러리가 없습니다.
https://rapidjson.org/index.html

위 사이트 가셔서 라이브러리 소스는 다운로드 하시면 됩니다.

공식적인 성능면에서도 우수한 속도를 냅니다.

제가 가지고 있는 json 파일이 20k 정도 하여서 파싱만 처리를 속도를 체크 해봤는데 속도가 5분의 1로 줄었습니다.

성능면에서는 우수합니다.

단 개발자로서 코드를 다루는 입장에서는 접근하는 방법이 좀 까다로운점 말고는 괜찮아 이 라이브러리를 도입하게 되었습니다.


들어가기 전에 개발된 샘플은 Visual Studio 2017 버젼에서 제작 된겁니다.

샘플 구성은 TestJson.json 파일을 읽어서 파싱하고 안에 내용을 순회 하며 결과를 출력하는 샘플입니다.



CString sFilePath;
 sFilePath = "D:\\TestJson.json";

 CFile file;
 Document rapidJsonDoc;

 if (file.Open(sFilePath, CFile::modeRead))
 {
  LPBYTE lpTmp = new BYTE[file.GetLength()];
  memset(lpTmp, 0x00, file.GetLength());

  unsigned long nReadSize = file.Read(lpTmp, file.GetLength());
  if (nReadSize > 0)
  {
   CString sReadCon((LPSTR)lpTmp, file.GetLength());
   OutputDebugString(_T("Start RapidJson Parse\n"));

   rapidJsonDoc.Parse(sReadCon);
   if (rapidJsonDoc.HasParseError())
   {
    OutputDebugString(_T("Read Failed\n"));
   }
   else
   {
    OutputDebugString(_T("Read Success\n"));

    for (rapidjson::Value::ConstMemberIterator itr = rapidJsonDoc.MemberBegin(); itr != rapidJsonDoc.MemberEnd(); ++itr)
    {
     CString sKey((LPSTR)itr->name.GetString(), strlen((LPSTR)itr->name.GetString()));
     doTraversRapidJson(rapidJsonDoc[itr->name.GetString()], sKey);
    }
   }

   OutputDebugString(_T("End RapidJson Parse\n"));
  }
 }



void doTraversRapidJson(const rapidjson::Value& oRoot, CString sKey)
{
 CString sDebugStr;
 switch (oRoot.GetType())
 {
 case kNullType:
 {
  sDebugStr.Format(_T("[%s]=null\n"), (LPCTSTR)sKey);
  OutputDebugString(sDebugStr);
 }break;
 case kFalseType:
 case kTrueType:
 {
  sDebugStr.Format(_T("[%s]=%s\n"), (LPCTSTR)sKey, oRoot.GetBool() ? _T("true") : _T("false"));
  OutputDebugString(sDebugStr);
 }break;
 case kStringType:
 {
  CString sValue;
  sValue = oRoot.GetString();
  sDebugStr.Format(_T("[%s]=%s\n"), (LPCTSTR)sKey, (LPCTSTR)sValue);
  OutputDebugString(sDebugStr);
 }break;
 case kNumberType:
 {
  if (oRoot.IsInt())
  {
   sDebugStr.Format(_T("[%s]=%d\n"), (LPCTSTR)sKey, oRoot.GetInt());
   OutputDebugString(sDebugStr);
  }
  else if (oRoot.IsUint())
  {
   sDebugStr.Format(_T("[%s]=%d\n"), (LPCTSTR)sKey, oRoot.GetUint());
   OutputDebugString(sDebugStr);
  }
  else if (oRoot.IsDouble())
  {
   sDebugStr.Format(_T("[%s]=%f\n"), (LPCTSTR)sKey, oRoot.GetDouble());
   OutputDebugString(sDebugStr);
  }
  else if (oRoot.IsInt64())
  {
  }
  else if (oRoot.IsUint64())
  {
  }
 }break;
 case kObjectType:
 {
  sDebugStr.Format(_T("[%s]=Object\n"), (LPCTSTR)sKey);
  OutputDebugString(sDebugStr);
  CString sPath;
  for (rapidjson::Value::ConstMemberIterator itr = oRoot.MemberBegin(); itr != oRoot.MemberEnd(); ++itr)
  {
   CString sName;
   sName = itr->name.GetString();
   if (sKey != _T(""))
   {
    sPath.Format(_T("%s/%s"), (LPCTSTR)sKey, (LPCTSTR)sName);
   }
   else
   {
    sPath = sName;
   }

   doTraversRapidJson(oRoot[itr->name.GetString()], sPath);
  }
 }break;
 case kArrayType:
 {
  sDebugStr.Format(_T("[%s]=Array\n"), (LPCTSTR)sKey);
  OutputDebugString(sDebugStr);
  unsigned int nArrCnt = oRoot.Size();
  CString sPath;
  for (unsigned int index = 0; index < nArrCnt; ++index)
  {
   sDebugStr.Format(_T("[%s][%d]"), (LPCTSTR)sKey, index);
   if (sKey != _T(""))
   {
    sPath.Format(_T("%s/%d"), (LPCTSTR)sKey, index);
   }
   else
   {
    sPath.Format(_T("%d"), index);
   }

   doTraversRapidJson(oRoot[index], sPath);
  }
 }break;
 }
}

보면 아시겠지만 doTraversRapidJson 함수는 재귀 함수 입니다.

사용을 하시기 위해서는 아래의 것을 선행 하셔야 합니다.

rapidjson\document.h

rapidjson\reader.h

위 두파일을 인쿠르드 하시고


​using namespace rapidjson;

을 선언합니다.


소스에 .GetString() 해서 값을 얻어 오는 부분이 있는데 이값을 UniCode에서 MutiByteCode 로 변환을 하셔야 합니다.

변환 하는 방법은 제 블로그에 내용이 있으니 참조 하시면 됩니다.
https://blog.naver.com/berdo_seok/220931299353

사용법은 여기까지 입니다. 그럼 ^^

댓글 없음: