Do not use StorageFile APIs to save data to a local folder. Use it only if you need it: for APIs that need to transfer them to the storage file or for access to an image library that does not have a real path. StorageFile APIs are very slow compared to traditional APIs. Worst of all, all file operations are asynchronous, which means that it hurts to work and even painfully debugs.
For your scenario, I would just use std :: wofstream if you are familiar with it:
#include <fstream> class winRTLog { public: winRTLog(Platform::String^ fileName); void save(Platform::String^ log); private: std::wofstream m_OutStream; }; winRTLog::winRTLog(Platform::String^ fileName) : m_OutStream(std::wstring(Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data()) + L"\\" + fileName->Data(), std::ios::app) { if (!m_OutStream.is_open()) throw std::runtime_error("Failed to open the log file."); } void winRTLog::save(Platform::String^ log) { m_OutStream << log->Data(); if (m_OutStream.fail()) throw std::runtime_error("Failed to write to the log file."); }
Alternatively, you can use the Win32 APIs:
#include <memory> #include <string> #include <windows.h> class winRTLog { public: winRTLog(Platform::String^ fileName); ~winRTLog(); void save(Platform::String^ log); private: HANDLE m_LogHandle; }; winRTLog::winRTLog(Platform::String^ fileName) { auto filePath = std::wstring(Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data()) + L"\\" + fileName->Data(); m_LogHandle = CreateFile2(filePath.c_str(), GENERIC_WRITE, 0, OPEN_ALWAYS, nullptr); if (m_LogHandle == INVALID_HANDLE_VALUE) throw std::runtime_error("Failed to open the log file: error code " + std::to_string(GetLastError())); if (SetFilePointer(m_LogHandle, 0, nullptr, FILE_END) == INVALID_SET_FILE_POINTER) throw std::runtime_error("Failed to set file pointer to the end of file: error code " + std::to_string(GetLastError())); } winRTLog::~winRTLog() { if (m_LogHandle != INVALID_HANDLE_VALUE) CloseHandle(m_LogHandle); } void winRTLog::save(Platform::String^ log) { // Convert to UTF8 std::string utf8; utf8.resize(4 * log->Length()); auto utf8Length = WideCharToMultiByte(CP_UTF8, 0, log->Data(), static_cast<int>(log->Length()), &utf8[0], static_cast<int>(4 * log->Length()), nullptr, nullptr); if (utf8Length == 0) throw std::runtime_error("Failed to convert log message to UTF8: error code " + std::to_string(GetLastError())); utf8.resize(utf8Length); // Write to actual log DWORD bytesWritten; auto writeResult = WriteFile(m_LogHandle, utf8.data(), static_cast<DWORD>(utf8.length()), &bytesWritten, nullptr); if (writeResult == FALSE || bytesWritten != utf8.length()) throw std::runtime_error("Failed to write log message to the log file: error code " + std::to_string(GetLastError())); }
Note that I used the std :: runtime_error throw to handle errors, for example: you can do it differently.
source share