How to improve CStdioFile / CFile performance in WinCE?

My application has the requirement to dump memory to a file on command.  This file is about 500K.
It's taking me upwards of 4 minutes to complete the task.  Initially, the file location was on the "harddrive" -
the compact flash for this device.  I moved the file location to the ram disk area - it writes in about 3 seconds.

I then go into Windows Explorer, copy the file from the ram disk to the compact flash - and it takes 3 seconds
to copy.  This tells me that I can write to the compact flash just as fast as the copy command.  So, what the
heck is wrong with the code below.  To summarize what the code is doing, we have some preformatted
information going to the text dump and then unformatted binary data that I expand out 8 longwords per row.
Nothing complex.

Thanks for taking a look.  I'm at the point now to just write to RAM and then copy the file, but this
approach maxes out my tackiness meter.

void CFaultStackPopupDlg::DumpFaultDataToFile(CStringList *pMsgList, FAULT_STACK_TYPE *pFS)
   int i;

   CNLangString sText;
   CString sDebugText;
      char szFileTxt[1024];

   CFile dumpFile;
   CFileException ex;

   // Open the file in truncate mode.  There is one and only one text dump.  There may be
   // binary dumps later.

      //if (!dumpFile.Open(N_FAULT_LOG_FILE,
      if (!dumpFile.Open(_T("\\Windows\\FaultLog.txt"),
      CFile::modeCreate | CFile::modeWrite | CFile::shareDenyNone | CFile::typeBinary, &ex))
#ifdef _DEBUG
            // Complain if an error happened.
            // There is no reason to delete the ex object.
            TCHAR szError[1024];
            ex.GetErrorMessage(szError, 1024);

            afxDump << szError << _T(" (") << ex.m_cause << ")\n";
      // Extend the file to something approximating the actual file dump.  This works out to be about
      // 500K.
      long dwSize = 500000;

            // Prefix the dump with the current date and time (according to the ENGINE!).

      TIME_TYPE et = m_pNMS->get_Time(0);

            CString sText;
            sText.Format(_T("\r\nFault stack dump on %02.2d/%02.2d/%02.2d  %2.2d:%2.2d:%2.2d\r\n\r\n"),
         et.Day, et.Month, et.Year, et.Hour, et.Minute, et.Second);

            // Convert string from Unicode (16-bit) to 8-bit - so you can read what is in the log file.
            WideCharToMultiByte(CP_ACP, 0, sText, -1,  szFileTxt, 1024, NULL, NULL);

            // Append line to file.
            dumpFile.Write(szFileTxt, strlen(szFileTxt));

      // Now dump the fault stack.

      POSITION pos = pMsgList->GetHeadPosition();

      for (i = 0; i < pMsgList->GetCount(); i++)
         sText = pMsgList->GetNext(pos);
         sText += _T("\r\n");

               WideCharToMultiByte(CP_ACP, 0, sText, -1,  szFileTxt, 1024, NULL, NULL);
         dumpFile.Write(szFileTxt, strlen(szFileTxt));

      // Now that the preamble is complete, dump the stack data and then the channel data.
      // Format is "xx 0x00000000..."  where xx is the address in hex, followed by 8 longwords of data.

      sText = _T("\r\n\r\nStack Dump\r\n");
            WideCharToMultiByte(CP_ACP, 0, sText, -1,  szFileTxt, 1024, NULL, NULL);

      dumpFile.Write(szFileTxt, strlen(szFileTxt));

      for (i = 0; i < 50/8; i++)  // first full 6
         sText.Format(_T("%2.2x  0x%8.8x %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x\r\n"),
            i * 8,
            pFS->StackSpace[i + 0],
            pFS->StackSpace[i + 1],
            pFS->StackSpace[i + 2],
            pFS->StackSpace[i + 3],
            pFS->StackSpace[i + 4],
            pFS->StackSpace[i + 5],
            pFS->StackSpace[i + 6],
            pFS->StackSpace[i + 7]);

         WideCharToMultiByte(CP_ACP, 0, sText, -1,  szFileTxt, 1024, NULL, NULL);
         dumpFile.Write(szFileTxt, strlen(szFileTxt));

      // Last 2.
      sText.Format(_T("%2.2x  0x%8.8x %8.8x\r\n"),
         pFS->StackSpace[i + 0],
         pFS->StackSpace[i + 1]);
            WideCharToMultiByte(CP_ACP, 0, sText, -1,  szFileTxt, 1024, NULL, NULL);
      dumpFile.Write(szFileTxt, strlen(szFileTxt));

      // Now dump the channel data.  This comes in 24 sets of 2000 long words.
      // Same code as above.

      for (int nChannel = 0; nChannel < 24; nChannel++)
         sText.Format(_T("\r\n\r\nChannel %d Data:\r\n\r\n"), nChannel);
               WideCharToMultiByte(CP_ACP, 0, sText, -1,  szFileTxt, 1024, NULL, NULL);

         dumpFile.Write(szFileTxt, strlen(szFileTxt));

         // dump this channel's data.  2K longwords == 250 rows @ 8 lw/row.

         for (i = 0; i < 2000/8; i++)
            sText.Format(_T("%3.3x  0x%8.8x %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x %8.8x\r\n"),
               i * 8,
               pFS->Channel[nChannel][i + 0],
               pFS->Channel[nChannel][i + 1],
               pFS->Channel[nChannel][i + 2],
               pFS->Channel[nChannel][i + 3],
               pFS->Channel[nChannel][i + 4],
               pFS->Channel[nChannel][i + 5],
               pFS->Channel[nChannel][i + 6],
               pFS->Channel[nChannel][i + 7]);
                  WideCharToMultiByte(CP_ACP, 0, sText, -1,  szFileTxt, 1024, NULL, NULL);
            dumpFile.Write(szFileTxt, strlen(szFileTxt));

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

charles_gilleyAuthor Commented:
Addendum: I'm using Windows CE 4.1, x86 target.
The reason of the slowness is that you call CFile::Write() too frequently.

To improve the performance, try to reduce the number of CFile::Write() calls as much as possible. You can allocate a big memory buffer and write the content to the memory buffer first. Once the buffer is full, write the content of the buffer to the file.

You can also write to a CMemFile first and then call CFile::Write() only once.

Another way is to use file mapping.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
charles_gilleyAuthor Commented:

  Thank you very much for the pointers.  The CMemFile helped me out immensely as I really did not want to add yet more memory mgt. to an otherwise simple operation.

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Smartphone Programming

From novice to tech pro — start learning today.