如何在UWP应用程序中将文本附加到文件

时间:2016-09-09 09:44:28

标签: c++-cli uwp

我需要在UWP应用程序中创建一个简单的日志类(只是"保存到文件"方法)以进行调试,但AppendTextAsync与ofstream有很大不同,我不知道如何使用。 这是我的班级

#pragma once
ref class winRTLog sealed
{
public:
    winRTLog();
    void save(Platform::String^ log);
private:
    Platform::String^ myFilename = L"myLog.txt";
    Windows::Storage::StorageFolder^ myFolder;
    Windows::Storage::StorageFile^ myFile;
    Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ createMyFile;
    concurrency::task<Windows::Storage::StorageFile^> myFileTask;
};

这是我到目前为止试图理解文档的混乱

#include "pch.h"
#include <ppltasks.h>   
#include "winRTLog.h"

winRTLog::winRTLog()
{
    myFolder = Windows::Storage::ApplicationData::Current->LocalFolder;
    createMyFile = myFolder->CreateFileAsync(myFilename, Windows::Storage::CreationCollisionOption::OpenIfExists);
    myFileTask = concurrency::create_task(myFolder->GetFileAsync(myFilename));
    //how to make myFile point the file I've created?
}

void winRTLog::save(Platform::String^ log)
{
    //?? 
    myFileTask.then([&]()
    {
        //how to use Windows::Storage::FileIO::AppendTextAsync
        //with myFile and log?
    });
}

2 个答案:

答案 0 :(得分:2)

不要使用StorageFile API将数据保存到本地文件夹中。只有在需要时才使用它:对于需要将它们传递到存储文件中的API,或者访问没有真实路径的图片库这样的地方。与传统API相比,StorageFile API非常慢。最糟糕的是,所有文件操作都是异步的,这意味着它们很难处理,甚至更难以调试。

对于您的方案,如果您熟悉它,我只使用std :: wofstream:

#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.");
}

或者,您可以使用Win32文件API:

#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()));
}

注意,出于示例目的,我使用throw std :: runtime_error进行错误处理:您可能希望以不同方式执行此操作。

答案 1 :(得分:0)

基于@Sunius 的回答,但对于 UWP 应用程序中的 C++/WinRT,请注意日志文件将位于 %appdata%\..\Local\Packages\<YOUR_UWP_APP PACKAGE>\LocalState 文件夹中:

// WinRtLog.cpp
#include "WinRtLog.h"
#include "winrt/Windows.Storage.h"

using namespace winrt::Windows;

winRTLog::winRTLog(std::wstring fileName) :
    m_OutStream(std::wstring(Storage::ApplicationData::Current().LocalFolder().Path().data()) + L"\\" + fileName, std::ios::app)
{
    if (!m_OutStream.is_open())
        throw std::runtime_error("Failed to open the log file.");
}

void winRTLog::save(std::string log)
{
    m_OutStream << log.data();
    if (m_OutStream.fail())
        throw std::runtime_error("Failed to write to the log file.");
}

和标题:

// WinRtLog.h
#pragma once
#include <fstream>
#include "winrt/Windows.ApplicationModel.Core.h"

class winRTLog
{
    public:
        winRTLog(std::wstring fileName);
        void save(std::string log);

    private:
        std::wofstream m_OutStream;
};

请注意,如果要将日志文件存储在任意文件夹中,则 UWP broadFileSystemAccess 中需要 Package.appxmanifest 功能——必须在代码中设置此功能(Appx GUI 不会显示它)如图所示in this SO post