如何从cppwinrt中的StorageFile读取字节数据?

时间:2018-02-14 19:48:17

标签: c++-winrt

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 *,但随后 错误是“类'winrt :: Windows :: Storage :: Streams :: IBuffer'没有成员'ToArray'”

事实上,Intellisense没有为IBuffer列出这样的成员。然而,IBuffer被指定为ReadBufferAsync的返回类型。看来上面的示例代码无法正常运行。

在FileIO的文档中,我发现建议使用DataReader从缓冲区中读取,在cppwinrt中应该看起来像

DataReader dataReader = DataReader::FromBuffer(buffer);

编译。然后应该可以使用以下DataReader方法读取字节,幸运的是,它以cppwinrt形式提供在UWP文档中:

void ReadBytes(Byte[] value) const;

但是,由于在cppwinrt中无法识别类型字节,因此无法编译。如果我改为创建一个字节数组:

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帖子称阵列视图“已经死亡”,我不知道如何声明一个,或者它是否会有所帮助。用于从缓冲区读取字节的原始单行方法回想起来看起来非常漂亮。这是一个很长的帖子,但是有人可以建议最简单的方法来简单地从cppwinrt中的StorageFile引用中读取原始字节吗?如果StorageFile上只有GetFileBytes()和GetFileBytesAsync()方法,那就太好了。

---更新:这是向前迈出的一步。我在去年找到了肯尼克尔的评论,解释说不应该直接声明array_view,而是可以使用std :: vector或std :: array。这被接受为DataReader的ReadBytes方法的参数:

std::vector<unsigned char>fileBytes;
dataReader.ReadBytes(fileBytes);

现在唯一的麻烦是std :: vector没有接收到任何字节,即使引用文件的大小在buffer.Length()中正确返回为167,513字节。这似乎表明缓冲区是好的,所以我不确定为什么应用于该缓冲区的ReadBytes方法不会产生任何数据。

更新#2:肯尼建议在矢量中保留空间,这是我尝试过的方式,这样:

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的工作方式,也许可能无法异步循环,但我们会看到。

2 个答案:

答案 0 :(得分:4)

array_view填补了Windows API和C ++数组类型之间的空白。在此示例中,ReadBytes方法期望调用者提供一些可以将字节复制到的数组。 array_view将指针转发给调用者的数组及其大小。在这种情况下,您传递一个空向量。在调用ReadBytes之前尝试调整向量的大小。

答案 1 :(得分:0)

当您知道期望的字节数(在本例中为 2 个字节)时,这对我有用:

    std::vector<unsigned char>fileBytes;
    fileBytes.resize(2);        
    DataReader reader = DataReader::FromBuffer(buffer);
    reader.ReadBytes(fileBytes);
    cout<< fileBytes[0] << endl;
    cout<< fileBytes[1] << endl;