【问题标题】:ofstream.is_open() always false in DirectX12 application using VS 2015ofstream.is_open() 在使用 VS 2015 的 DirectX12 应用程序中始终为假
【发布时间】:2016-05-10 06:55:27
【问题描述】:

我已经尝试了好几个小时,但我无法让我的 DirectX12 应用程序编写一个简单的文件...

关于我的设置:

  • Windows 10 已更新。
  • DirectX12 默认“旋转立方体”应用程序。 DirectX 12 应用(通用 Windows)
  • Visual Studio 2015

我正在这样做:

ofstream outFile;
// I have even tried with \\ slashes...
outFile.open("c://Users//pookie//Documents//WHERETHEFISMYFILE.txt");
if (outFile.is_open())
{
    outFile << "Writing this to a file.\n";
    outFile.close();
}

我尝试过的(几乎所有在阳光下和厨房水槽下的东西):

  • 我也尝试过使用fstreamwfstream 以及!outfile.fail()
  • 我已经检查了项目中的每个目录,甚至还尝试使用了 Microsoft DirectX SDK。
  • 我试过相对路径:outFile.open("WHERETHEFISMYFILE.txt");
  • 我尝试过设置绝对路径。
  • 我尝试通过允许“所有人”并授予完全访问权限来向文件夹添加权限 - 只是为了保持理智。
  • 我也尝试获取当前工作目录C:\Users\pookie\Documents\Visual Studio 2015\Projects\demoDX12\x64\Debug\demoDX12\AppX 并将其设置为c:\
  • 我已经在项目的每个文件夹中手动创建了文件...
  • 我已经尝试过调试和发布配置,以及 x86 和 x64 及其所有可能的组合
  • 我在文件路径中尝试了\\//
  • 我尝试用 %20 替换路径中的空格
  • 我也尝试过在管理员模式下运行 Visual Studio。

问题出现在这里:if (outFile.is_open())。由于某种原因,它总是返回 false。

我在这里做错了什么?

更新: 为了让我安心,我尝试了一个带有以下代码的空控制台应用程序:

#include <fstream>
#include <iostream>

using namespace std;

int main()
{
    try
    {
        wfstream  outFile;
        outFile.open("C:\\Users\\pookie\\Documents\\WHERETHEFISMYFILE.txt");
        if (outFile.is_open())
        {
            outFile << "Writing this to a file.\n";
            outFile.close();
        }
        else
        {
            cout << "sdsadsdsd";
        }
    }
    catch (const std::exception& ex)
    {
        cout << ex.what();
    }
    return 0;
}

结果相同:is_open() == false。伙计们,我不知所措。

更新 2:

根据要求,我正在更新此问题以显示我正在使用的确切项目。我正在使用默认的 DirectX12 应用程序 - 旋转立方体。我followed this tutorial

在我的项目中,有一个名为 void DX::DeviceResources::Present() 的方法,我试图在此方法中写入文件(尽管我在该项目的许多其他地方也尝试过。

这里是:

// Present the contents of the swap chain to the screen.
void DX::DeviceResources::Present()
{
    // The first argument instructs DXGI to block until VSync, putting the application
    // to sleep until the next VSync. This ensures we don't waste any cycles rendering
    // frames that will never be displayed to the screen.
    HRESULT hr = m_swapChain->Present(1, 0);

    try
    {
        wfstream  outFile;
        std::string 
         //This has been done numerous ways, but ultimately, I believe that 
         //ios_base::out is required if the file does not yet exist.
        name("c:\\Users\\pookie\\Documents\\WHERETHEFISMYFILE.txt");
        outFile.open(name.c_str(), ios_base::out);
        if (outFile.is_open())
        {
            outFile << "Writing this to a file.\n";
            outFile.close();
        }
        else
        {
            cout << "sdsadsdsd";
        }
    }
    catch (const std::exception& ex)
    {
        cout << ex.what();
    }


    // If the device was removed either by a disconnection or a driver upgrade, we 
    // must recreate all device resources.
    if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
    {
        m_deviceRemoved = true;
    }
    else
    {
        DX::ThrowIfFailed(hr);

        MoveToNextFrame();
    }
}

更新 3

所以,一个带有文件输出的空白项目可以正常工作,如果我使用

name("c:\\Users\\pookie\\Documents\\WHERETHEFISMYFILE.txt");
outFile.open(name.c_str(), ios_base::out);

注意ios_base::out

这很好。但是,这在默认的 DirectX12 应用程序中仍然不起作用。

这绝对是 DirectX 相关问题。见this。我已尝试按照该帖子中建议的解决方案进行操作,但仍然无法使其正常工作。

我还可以确认一个全新的 DirectX12 项目也有同样的问题。试试看。

解决方案

感谢 ebyrob,我已经完成了这项工作。事实证明,这些新的 Windows 应用程序只能写入某些文件夹......更具体地说,这是:

auto platformPath = ApplicationData::Current->RoamingFolder->Path;

可惜路径不是标准字符串……所以必须先转换一下:

auto platformPath = ApplicationData::Current->RoamingFolder->Path;
std::wstring platformPathW(platformPath->Begin());
std::string convertedPlatformPath(platformPathW.begin(), platformPathW.end());

然后只需添加文件名:

std::string path = convertedPlatformPath + "\\WHERETHFISMYFILE.txt";

最后:

try
{
    wofstream  outFile;
    char buff[256]; 
    outFile.open(path.c_str(), ios_base::out);
    if (outFile.is_open())
    {
        outFile << "Writing this to a file.\n";
        outFile.close();
    }
    else
    {
        cout << "Cannot open file " << name << ": " << strerror_s(buff,0) << endl;
    }
}
catch (const std::exception& ex)
{
    cout << ex.what();
}

谢谢你!

【问题讨论】:

  • 如果将每个// 替换为/ 会发生什么?
  • 你有没有看这个问题:stackoverflow.com/questions/27075930/…
  • @pookie 好吧,您在示例中显示的// 绝对是错误的。而且跟direct-x没关系。
  • 不幸的是,我被 Windows 困住了,真的,我不应该仅仅为了写入文本文件而更换操作系统;)
  • @AnmolSinghJaggi:由于perror 是一个 POSIX 函数,我认为我们不应该对它无法在 Windows 10 上编译感到完全惊讶。

标签: c++ ofstream directx-12


【解决方案1】:

看到这个答案:

std::fstream doesn't create file

您需要为wfstream::open() 指定正确的选项才能创建新文件。 ::in 没有 ::trunc 将需要现有文件。

例子:

outFile.open("C:\\Users\\pookie\\Documents\\WHERETHEFISMYFILE.txt", ios_base::out);

在这种情况下,似乎还有另一个问题。该应用程序是 Windows 10 应用商店的一部分,因此它只能访问少数几个位置的文件。

请看这个帖子:Can't create file using fstream in windows store app 8.1

了解如何在本地或漫游用户配置文件目录中打开应用程序实际确实可以访问的文件。

【讨论】:

  • 不幸的是,这也不起作用。我尝试了空白控制台应用程序,它在那里工作,但不适用于默认的 DirectX12 应用程序,我怀疑这是导致冲突的原因。但是,有人不断删除我的 DX12 标签...
  • 您的独立应用也有同样的问题,但没有 dx12
  • @pookie 我得看看我以后能做什么,因为我现在在 Windows 7 上运行。请使用来自您的 DX12 应用程序的简短而准确的电流源更新您的问题。 (也使用 Oleg 的 strerror(errno) 想法)
  • @pookie 我认为这可能是应用商店的问题,在这种情况下这可能是相关的:stackoverflow.com/questions/25815285/…
  • @ebyrob 辉煌!!有用!太感谢了!更新您的答案,我将标记为正确。再次感谢!
【解决方案2】:

这里的根本问题是发帖者正在编写 UWP,而不是 Win32 桌面应用程序,这意味着该应用程序对文件系统的任意部分没有读写权限,特别是 C:\\Users\\pookie\\Documents\\WHERETHEFISMYFILE.txt

是否使用 DirectX 12 与问题无关。

UWP 可以直接访问的文件系统的唯一部分是:

  • 对已安装的打包目录的只读访问权限。 Windows::ApplicationModel::Package::Current-&gt;InstalledLocation

  • 对隔离临时文件目录的读写访问权限。 Windows::Storage::ApplicationData::Current-&gt;TemporaryFolder

  • 对本地或漫游的隔离的每个用户/每个应用程序文件目录的读写访问权限。 Windows::Storage::ApplicationData::Current-&gt;LocalFolderRoamingFolder;

要访问 UWP 中的用户文档文件夹,需要使用 Windows.Storage.Pickers 中的 Windows 运行时文件选择器或通过具有适当声明功能的 StorageFile 功能。对于此类受保护的文件,您也不能直接使用 C++ iostream 操作,因为它们甚至可能不是本地文件系统上的文件。您可以使用 Windows 运行时 API 将文件复制到上述位置之一,然后在该副本上使用传统的 C/C++ 函数。

以下是使用 C/C++ 函数读取位于受保护区域中的用户文件(如 UWP 中的用户文档)的示例:

#include <ppltasks.h>
using namespace concurrency;

using Windows::Storage;
using Windows::Storage::Pickers;

create_task(openPicker->PickSingleFileAsync()).then([](StorageFile^ file)
{
    if (file)
    {
        auto tempFolder = Windows::Storage::ApplicationData::Current->TemporaryFolder;
        create_task(file->CopyAsync(tempFolder, file->Name, NameCollisionOption::GenerateUniqueName)).then([](StorageFile^ tempFile)
        {
            if (tempFile)
            {
                ifstream inFile(tempFile->Path->Data())
                ...
            }
        });
    });
}

以下是使用 C/C++ 函数编写位于受保护区域中的用户文件(如 UWP 中的用户文档)的示例:

#include <ppltasks.h>
using namespace concurrency;

using Windows::Storage;
using Windows::Storage::Pickers;

auto folder = Windows::Storage::ApplicationData::Current->TemporaryFolder;

WCHAR fname[ _MAX_PATH ];
wcscpy_s( fname, folder->Path->Data() );
wcscat_s( fname, L"\\MYFILE.txt" );

ofstream outFile;
outFile.open(fname, ios_base::out);

...

outFile.close();

create_task(savePicker->PickSaveFileAsync()).then([](StorageFile^ file)
{
    if ( file )
    {
        auto folder = Windows::Storage::ApplicationData::Current->TemporaryFolder;
        auto task = create_task( folder->GetFileAsync("MYFILE.txt") );
        task.then([file](StorageFile^ tempFile) ->IAsyncAction^
        {
            return tempFile->MoveAndReplaceAsync( file );
        });
    }
});

File access and permissions (Windows Runtime apps)Dual-use Coding Techniques for Games

请注意,遵循 Windows Vista 时代 User Account Control 指南的任何人都应该熟悉此模型,您的安装目录应该是只读的(即在 C:\Program Files 下),并且您应该使用 SHGetFolderPath 和 @ 987654335@ / CSIDL_APPDATA 用于应用程序数据,GetTempPath 用于您具有读/写访问权限的临时目录。使用 UWP,文件系统的其余部分受到显式保护,而 UAC 则没有。

【讨论】:

    【解决方案3】:

    我不知道到底出了什么问题,但我希望这段代码可以帮助您诊断问题:

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <string.h>
    
    using namespace std;
    
    int main()
    {
        ofstream outFile;
        std::string name("c://Users//pookie//Documents//WHERETHEFISMYFILE.txt");
        outFile.open(name.c_str());
        if(outFile.is_open()) {
            outFile << "Writing this to a file.\n";
            outFile.close();
        } else {
            cout << "Cannot open file " << name << ": " << strerror(errno) << endl;
        }
    }
    

    此代码已在 MSVC++ here 上测试。

    【讨论】:

    • 谢谢,我用strerror试过了,结果是no error
    • @pookie 你可能还想试试线程安全的strerror_s()
    • @ebyrob 我也试过了 :) 这绝对与直接 X 有关。显然你必须写入 app X 文件夹,但这对我也不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    • 1970-01-01
    相关资源
    最近更新 更多