Ответ 2012 года на StackOverflow («Как мне прочитать двоичный файл в приложении Windows Store») предлагает следующий метод чтения байтовых данных из StorageFile в приложении Windows Store:
IBuffer buffer = await FileIO.ReadBufferAsync(theStorageFile);
byte[] bytes = buffer.ToArray();
Это выглядит достаточно просто. Поскольку я работаю в cppwinrt, я перевел это на следующее в том же IAsyncAction, который создал вектор StorageFiles. Сначала я получаю StorageFile из VectorView с помощью theFilesVector.GetAt (index);
// Тогда эта строка компилируется без ошибок:
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, который, к счастью, предоставляется в документации UWP в форме cppwinrt:
void ReadBytes(Byte[] value) const;
Однако это не компилируется, потому что тип Byte не распознается в 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. Тем не менее, в сообщении Reddit за 2015 год говорится, что array_view «умер», и я не уверен, как его объявить и поможет ли это. Этот оригинальный однострочный метод чтения байтов из буфера в ретроспективе выглядит так красиво. Это длинный пост, но может ли кто-нибудь предложить лучший текущий метод для простого чтения необработанных байтов из ссылки StorageFile в cppwinrt? Было бы хорошо, если бы в StorageFile были просто методы GetFileBytes () и GetFileBytesAsync ().
--- Обновление: вот шаг вперед. В прошлом году я нашел комментарий Кенни Керра, объясняющий, что array_view не следует объявлять напрямую, но вместо этого можно использовать std :: vector или std :: array. И это принимается в качестве аргумента для метода ReadBytes объекта DataReader:
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, и, возможно, у меня могут возникнуть проблемы с асинхронным циклом, но посмотрим.