2012-06-16 53 views
3

我的問題很簡單,但我很難找到關於此在線的任何信息。我可以在Android NDK中使用ifstream來訪問資產嗎?

是否有可能使用ifstream從資產和/或資源使用Android NDK打開文件?

例如,將在/資產的test.txt文件,嘗試以下不工作:

char pLine[256]; 
    std::ifstream fin("/assets/test.txt"); 
    if(!fin.fail()) 
    { 
     LOGD("test.txt opened"); 
     while(!fin.eof()) 
     { 
      fin.getline(pLine, 256); 
      LOGD(pLine); 
     } 
    } 
    else 
    { 
     LOGD("test.txt FAILED TO OPEN!"); 
    } 
    fin.close(); 

也沒有任何變化:

std::ifstream fin("assets/test.txt"); 

    std::ifstream fin("test.txt"); 

等等...,也不將它放在/ res中。

那麼,是否有可能使用普通的ifstream運算符來訪問資產和/或資源文件?

回答

1

不,你不能。資產存儲在APK中,一個zip文件。 ifstream無法在zip文件中讀取。

要訪問這些文件,您需要在java中訪問它們並將它們保存到其他位置或提取apk的內容以獲取資源。

這是前一個例子。

http://www.itwizard.ro/android-phone-installing-assets-how-to-60.html

這裏是做後者的一個例子。

http://www.anddev.org/ndk_opengl_-_loading_resources_and_assets_from_native_code-t11978.html

+2

感謝您的信息。怎麼樣使用AAssetManager_open?這似乎在C++中起作用。 –

+0

我從來沒有用過那個b4(剛剛聽說它現在哈哈)。是的,它看起來應該工作。 – Jug6ernaut

0

這是正確的,性病:: ifstream的不能用,但我們可以創造一種可以以類似的方式被使用的assetistream。例如:

class asset_streambuf: public std::streambuf 
{ 
public: 
    asset_streambuf(AAssetManager* manager, const std::string& filename) 
    : manager(manager) 
    { 
     asset = AAssetManager_open(manager, filename.c_str(), AASSET_MODE_STREAMING); 
     buffer.resize(1024); 

     setg(0, 0, 0); 
     setp(&buffer.front(), &buffer.front() + buffer.size()); 
    } 

    virtual ~asset_streambuf() 
    { 
     sync(); 
     AAsset_close(asset); 
    } 

    std::streambuf::int_type underflow() override 
    { 
     auto bufferPtr = &buffer.front(); 
     auto counter = AAsset_read(asset, bufferPtr, buffer.size()); 

     if(counter == 0) 
      return traits_type::eof(); 
     if(counter < 0) //error, what to do now? 
      return traits_type::eof(); 

     setg(bufferPtr, bufferPtr, bufferPtr + counter); 

     return traits_type::to_int_type(*gptr()); 
    } 

    std::streambuf::int_type overflow(std::streambuf::int_type value) override 
    { 
     return traits_type::eof(); 
    }; 

    int sync() override 
    { 
     std::streambuf::int_type result = overflow(traits_type::eof()); 

     return traits_type::eq_int_type(result, traits_type::eof()) ? -1 : 0; 
    } 

private: 
    AAssetManager* manager; 
    AAsset* asset; 
    std::vector<char> buffer; 
}; 


class assetistream: public std::istream 
{ 
public: 
    assetistream(AAssetManager* manager, const std::string& file) 
    : std::istream(new asset_streambuf(manager, file)) 
    { 
    } 
    assetistream(const std::string& file) 
    : std::istream(new asset_streambuf(manager, file)) 
    { 
    } 

    virtual ~assetistream() 
    { 
     delete rdbuf(); 
    } 

    static void setAssetManager(AAssetManager* m) 
    { 
     manager = m; 
    } 

private: 
    static AAssetManager* manager; 
}; 

void foo(AAssetManager* manager) 
{ 
    assetistream::setAssetManager(manager); 

    assetistream as("text/tmp.txt"); 
    std::string s; 

    std::getline(as, s); 
} 

改進非常受歡迎。

+1

爲什麼你重寫'.sync()'和'.overflow()'?爲什麼你要存儲'AAssetManager'?爲什麼使用單獨的動態緩衝區而不是數組成員?順便說一句,調整功能,向量可能拋出,泄漏'AAsset'如果它被成功收購。你真的應該處理可能無法通過投擲來打開ctor中的資產。並考慮使用'std :: unique_ptr'管理資產。 – Deduplicator

+0

感謝您的提示。但我不明白爲什麼不重寫同步和溢出。因爲istream永遠不會打電話給他們? –

+0

那和繼承的都很好。 – Deduplicator

相關問題