问题
I am using NDK and I need to read resource media file. So, as far as I understand in order to access to resources I need to use AAssetManager
, and eventually I need to get std::basic_istream
to work with it.
So, question is, how to get std::basic_istream
from AAssetManager
?
回答1:
The answer is actually very different whether you have a compressed asset (e.g. text) or uncompressed (by default, Jpeg images and mp3 are stored by the packer). For these uncompressed assets, you can get the file descriptor with AAsset_openFileDescriptor()
, and then follow the ways of How to construct a c++ fstream from a POSIX file descriptor?. For compressed assets, you may look for a (potentially API-level-dependent) hack that will let you get the file descriptor (or file path) to the transient file that the OS opens for you when it unpacks your asset.
回答2:
You can adapt this example to work with the "buffer" mode of AAssetManager
.
This will read the entire asset into memory, though. You could make an implementation that works more like std::fstream
by reading chunks into a memory buffer, but that is significantly more complex.
Note: I only test-compiled the code below.
class asset_streambuf : public std::streambuf {
public:
asset_streambuf(AAsset * the_asset)
: the_asset_(the_asset) {
begin_ = current_ = (const char *)AAsset_getBuffer(the_asset);
end_ = begin_ + AAsset_getLength64(the_asset);
}
~asset_streambuf() {
AAsset_close(the_asset_);
}
private:
int_type underflow() {
if (current_ == end_) {
return traits_type::eof();
}
return traits_type::to_int_type(*current_);
}
int_type uflow() {
if (current_ == end_) {
return traits_type::eof();
}
return traits_type::to_int_type(*current_++);
}
int_type pbackfail(int_type ch) {
if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1])) {
return traits_type::eof();
}
return traits_type::to_int_type(*--current_);
}
std::streamsize showmanyc() {
return end_ - current_;
}
AAsset * the_asset_;
const char * begin_;
const char * end_;
const char * current_ = nullptr;
};
Usage:
AAsset * asset = AAssetManager_open(mgr, "some_asset.bin", AASSET_MODE_BUFFER);
asset_streambuf sb(asset);
std::istream is(&sb);
来源:https://stackoverflow.com/questions/61190087/how-to-get-stdbasic-istream-from-aassetmanager