Assetsフォルダへの保存について

8,079 views
Skip to first unread message

Nikku

unread,
Feb 24, 2010, 1:30:42 AM2/24/10
to 日本Androidの会
Nikkuと申します。
Androidでアプリ開発を初めてみたのですが、
Assetsフォルダへのアクセスについて
一か月位悩んでいます。

プロジェクト内のAssetsフォルダに予めファイルを1つ用意し、
アプリケーション実行中に
ウェブから同名のファイルをダウンロードして
Assetsフォルダにあるファイルに上書きするという処理を行いたいのですが、
上手くいきません。


ソースは以下のような感じです。
ビルドエラーなどは特に無く、(エミュレーターで)実行もされるのですが、
Assetsフォルダのファイルを見ると上書きされた様子はありません。


検索などで調べたのですが、関連する情報が見つからなかったので
どなたか教えていただけないでしょうか。
よろしくお願いします。


public int downloadAss(String url,String fileNAME){
final String Path = fileNAME;
URLConnection conn = null;
InputStream in = null;
AssetManager as = getResources().getAssets();
FileOutputStream fos = null;
InputStreamReader inp =null;
OutputStreamWriter out =null;


// assetsに保存する
try{
URL dlURL = new URL(url+fileNAME); // ダウンロードする ファイルの
URL
conn = dlURL.openConnection();
in = conn.getInputStream();
AssetFileDescriptor afd = as.openFd(Path);
fos = afd.createOutputStream();
inp = new InputStreamReader(in);
out = new OutputStreamWriter(fos);
int c;
while ((c = inp.read()) != -1)
out.write(c);
}catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inp != null) inp.close();
if (out != null) {
out.flush();
out.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return 1;
}

Keiji Ariyama

unread,
Feb 24, 2010, 2:24:45 AM2/24/10
to android-g...@googlegroups.com
有山です。

 Assetsフォルダは上書きできないと認識しています。

 初回起動時にAssetsフォルダのデータをデータフォルダにコピーして、以後
は、そのファイルを上書きするという方法ではどうでしょうか。

/*********************************************
有限会社シーリス
代表 有山 圭二
@Address
〒530-0044
大阪市北区東天満二丁目2番5号
第2新興ビル 601
@Web http://www.c-lis.co.jp
*********************************************/

Nikku

unread,
Feb 24, 2010, 3:09:51 AM2/24/10
to 日本Androidの会
早々のご回答有難うございます。その手法も出来れば行いたいのですが、

利用しているライブラリ内で、「Assetsフォルダにあるファイルを開く」という事が行われているため、
ファイルの上書きもAssetsフォルダ内で行わないといけないというものです。
或いはライブラリの拡張?などを考えているのですが・・
その辺りは素人に近いため難しい状況です。

Assets関連のクラスに
AssetFileDescriptor createOutputStream()
AssetFileDescriptor.AutoCloseOutputStream write(byte[] buffer)
このようなものがあったのでどうにか使えないかなと考えた次第です。

因みに補足ですが、行おうとしているのは、
nyartoolkitのmqoファイルをプログラム実行中にダウンロード・・というような感じです

Keiji Ariyama

unread,
Feb 24, 2010, 6:20:47 AM2/24/10
to android-g...@googlegroups.com
有山@大阪です。

 確かにNikkuさんが仰る方法でAssetsへの保存はいけそうですね。。。

 リファレンスを呼んだ限りでは、AssetManagerを取得して、openFd(fileName)
でAssetFileDescriptorを取得。そこからcreateOutputStream()で
FileOutputStreamを取得して操作と言う流れになりそうなんですが、まだ試して
ません。

 現状はどうやってて、どんなエラーが起きているかとか、教えてもらえませんか?


/*********************************************
有限会社シーリス
代表 有山 圭二
@Address
〒530-0044
大阪市北区東天満二丁目2番5号
第2新興ビル 601
@Web http://www.c-lis.co.jp
*********************************************/

Nikku

unread,
Feb 24, 2010, 10:23:03 PM2/24/10
to 日本Androidの会

現状では、

■openFd(fileName)のファイル名を例えば"a.mqo"や"a.txt"などとすると以下のようなエラーが出ます。しかし拡張子をなぜ
かmp3にすると、このエラーは出ません。
ava.io.FileNotFoundException: This file can not be opened as a file
descriptor; it is probably compressed

■以下のソースのような形で、
mp3のファイル同士の入出力を行うと
bw.write(response);のところでエラーがでました。
responseには値はちゃんとはいっていました。
なおダウンロードするファイルは65KB程です。
java.io.IOException: Bad file number

■ファイルのサイズを極端に少なくした場合42B
responseには値は入っていて、bw.close();のところで同じエラーがでました。
java.io.IOException: Bad file number

--------------------------------------------------
private String getStringFromWeb(String location,String name){
AssetManager as = getResources().getAssets();
HttpURLConnection http = null;
InputStream in = null;
URL url = null;
String response = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// 通信関連
url = new URL(location+name);
http = (HttpURLConnection) url.openConnection();
http.setRequestMethod("POST");
http.connect();
// 以下保存関連
AssetFileDescriptor afd = as.openFd(name);
FileOutputStream fos = afd.createOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(fos,"略");
BufferedWriter bw = new BufferedWriter(osw);

// HTTP通信でデータを取得
in = http.getInputStream();
int len;
byte[] buf = new byte[4096];
while ( (len = in.read(buf))> 0) {
baos.write(buf, 0, len);
}
// 取得したデータを Stringへ変換
response = new String(baos.toByteArray());
//取得した文字列を保存
bw.write(response);
bw.close();
osw.close();
fos.close();


} catch (Exception e) {
e.printStackTrace();
} finally{

省略
}

l.b.

unread,
Feb 25, 2010, 10:33:50 AM2/25/10
to 日本Androidの会

 村上です。

 まず、リファレンスにはAssetManagerについて、" This class presents a lower-level API
that allows you to open and read raw files that have been bundled with
the application as a simple stream of bytes."とあります。なのでReadのみ出来るような仕様なので
しょう。

 実際にソースを見ると、AssetManager#openFdは最終的にC++のAssetクラスを継承するframework/base/
include/utilis/Asset.hの_CompressedAsset::openFileDescriptorか、framework/
base/libs/utils/Asset.cppの_FileAsset:: openFileDescriptorを呼び出しています。

 で、_CompressedAsset::openFileDescriptorは常に-1が返されていますし、_FileAsset::
openFileDescriptorではopen("ファイル名", O_RDONLY | O_BINARY)が返されています。
 なので読み込み専用で書き込みは出来ないようになっています。

 以下はPackageManagerやAssetManagerの動作を調べていないので想像です。
 apkをインストールして展開する時、mp3のような圧縮済みファイルは実ファイルシステム上に展開され、_FileAssetクラスとして
AssetManagerから呼び出されるのでファイルディスクリプタが割り当てられますが、テキストファイルなどはapkファイルから展開されず
_CompressedAssetクラスとして呼び出されるのでファイルディスクリプタが常に-1となり


ava.io.FileNotFoundException: This file can not be opened as a file

descriptor; it is probably compressedとなるのでは無いかと想像しています。

 以上です。

Nikku

unread,
Feb 26, 2010, 11:49:39 PM2/26/10
to 日本Androidの会
なるほど、ご指摘有難う御座います。

AssetManagerのopenFdが利用できないとなると、保存する以前の問題ですね。

createOutputStream() や
AssetFileDescriptor.AutoCloseOutputStream辺りを利用するような形で
Assetsフォルダへの保存がどうにか出来ないものでしょうか・・・

> > java.io.IOException: Bad file number- 引用テキストを表示しない -
>
> - 引用テキストを表示 -

宮山

unread,
Feb 28, 2010, 9:10:16 PM2/28/10
to 日本Androidの会
こんにちは、宮山です。

Assetsフォルダはapk内部のフォルダなので、そもそもアプリから変更を行う場所では
無いかと思います。

恐らく使われているライブラリは内部ファイルにアクセスする為のものだと思いますので
インストール後にネットワークからファイルの追加を行うのであれば、それ用の処理を別に
用意した方がいいと思います。
ファイルの扱いについてはDRMとかの絡みがあるかと思いますので
目的別に「ストリーミング読込」、「SD保存」、「端末保存」、「SQLite」
とか色々とあるかと思います。

以上、よろしくお願いいたします。

Reply all
Reply to author
Forward
0 new messages