StackOverflow 上的 2012 年回答(“我如何在 Windows 应用商店应用程序中读取二进制文件”)建议使用这种从 Windows 应用商店应用程序中的 StorageFile 读取字节数据的方法:
IBuffer buffer = await FileIO.ReadBufferAsync(theStorageFile);
byte[] bytes = buffer.ToArray();
这看起来很简单。当我在 cppwinrt 中工作时,我已将其翻译为以下内容,在生成 StorageFiles 向量的同一个 IAsyncAction 中。首先,我使用 theFilesVector.GetAt(index) 从 VectorView 获取一个 StorageFile;
//然后这一行编译没有错误:
IBuffer buffer = co_await FileIO::ReadBufferAsync(theStorageFile);
//但是我找不到使缓冲区调用起作用的方法。
byte[] bytes = buffer.ToArray();
“byte[]”一开始就不能工作,所以我把它改成byte*,但是错误是“class 'winrt::Windows::Storage::Streams::IBuffer' has no member 'ToArray' ”</p>
事实上,Intellisense 没有为 IBuffer 列出这样的成员。然而 IBuffer 被指定为 ReadBufferAsync 的返回类型。上面的示例代码似乎无法正常运行。
在 FileIO 的文档中,我发现建议使用 DataReader 从缓冲区中读取,在 cppwinrt 中应该看起来像
DataReader dataReader = DataReader::FromBuffer(buffer);
编译。然后应该可以使用以下 DataReader 方法读取字节,幸运的是,该方法在 UWP 文档中以 cppwinrt 形式提供:
void ReadBytes(Byte[] value) const;
但是,这不会编译,因为在 cppwinrt 中无法识别 Byte 类型。如果我改为创建一个字节数组:
byte* fileBytes = new byte(buffer.Length());
这是不被接受的。错误是
‘No suitable constructor exists to convert from “byte*” to “winrt::arrayView::<uint8_t>”’
uint8_t 当然是一个字节,所以我们试试
uint8_t fileBytes = new uint8_t(buffer.Length());
这是错误的——显然我们确实需要创建一个 winrt::array_view。然而,2015 年 Reddit 的一篇帖子说 array_view “死了”,我不确定如何声明它,或者它是否会有所帮助。回想起来,从缓冲区读取字节的原始单行方法看起来非常漂亮。这是一篇很长的文章,但是任何人都可以建议从 cppwinrt 中的 StorageFile 引用中简单地读取原始字节的最佳当前方法吗?如果 StorageFile 上只有 GetFileBytes() 和 GetFileBytesAsync() 方法,那就太好了。
---更新:这是向前迈出的一步。去年我发现 Kenny Kerr 的评论解释说 array_view 不应该直接声明,但可以使用 std::vector 或 std::array 代替。这被接受为 DataReader 的 ReadBytes 方法的参数:
std::vector<unsigned char>fileBytes;
dataReader.ReadBytes(fileBytes);
现在唯一的麻烦是 std::vector 没有接收任何字节,即使引用文件的大小在 buffer.Length() 中正确返回为 167,513 字节。这似乎表明缓冲区很好,所以我不确定为什么应用于该缓冲区的 ReadBytes 方法不会产生任何数据。
更新 #2:Kenny 建议在向量中保留空间,这是我尝试过的,这样:
m_file_bytes.reserve(buffer.Length());
但这并没有什么不同。这是现在使用 DataReader 的代码示例。
buffer = co_await FileIO::ReadBufferAsync(nextFile);
dataReader = DataReader::FromBuffer(buffer);
//The following line may be needed, but crashes
//co_await dataReader.LoadAsync(buffer.Length());
if (buffer.Length())
{
m_file_bytes.reserve(buffer.Length());
dataReader.ReadBytes(m_file_bytes);
}
The crash, btw, is
throw hresult_error(result, hresult_error::from_abi);
那么,是否证实上面引用的 2012 年原始解决方案在当今世界行不通?但是当然必须有某种方法可以从文件中读取字节,所以我只是遗漏了一些对其他人来说可能很明显的东西。
最后(我认为)更新:肯尼关于向量需要大小的建议已经达到了目标。如果首先使用 m_file_bytes.assign(buffer.Length(),0) 准备向量,那么它确实会填充文件数据。现在我唯一担心的是我并不真正了解 IAsyncAction 的工作方式,并且可能无法异步循环它,但我们会看到的。