androidからサウンドボードをプログラミングしています。問題は、一部のサウンドが機能し、一部が機能しないことです。これは私が機能しない音のために私が得るトレースバックです
05-31 13:23:04.227 18440 18603 W System.err: Java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
05-31 13:23:04.227 18440 18603 W System.err: at Android.content.res.AssetManager.openAssetFd(Native Method)
05-31 13:23:04.227 18440 18603 W System.err: at Android.content.res.AssetManager.openFd(AssetManager.Java:331)
05-31 13:23:04.227 18440 18603 W System.err: at com.phonegap.AudioPlayer.startPlaying(AudioPlayer.Java:201)
05-31 13:23:04.227 18440 18603 W System.err: at com.phonegap.AudioHandler.startPlayingAudio(AudioHandler.Java:181)
05-31 13:23:04.235 18440 18603 W System.err: at com.phonegap.AudioHandler.execute(AudioHandler.Java:64)
05-31 13:23:04.235 18440 18603 W System.err: at com.phonegap.api.PluginManager$1.run(PluginManager.Java:86)
05-31 13:23:04.235 18440 18603 W System.err: at Java.lang.Thread.run(Thread.Java:1096)
何か案は?
アセットフォルダー内の圧縮ファイルを開くには制限があります。これは、非圧縮ファイルをプロセスの仮想アドレス空間に直接メモリマップできるため、解凍のために同じ量のメモリを再度必要としないためです。
Android Apps でのアセット圧縮の扱い)では、圧縮ファイルを処理するためのいくつかの手法について説明しています。aapt
をだまして、拡張子を使用してファイルを圧縮しないようにすることができます圧縮されていない(例:mp3
)または、apk
を取得する代わりに、圧縮せずに手動でaapt
に追加して作業を行うことができます。
この問題が発生しているTensorflow Liteファイルを使用しているユーザーは、
Android {}内のGradleファイルに次の行を追加します。
aaptOptions {
noCompress "tflite"
}
単に追加:
aaptOptions {
noCompress "your-file-name"
}
Build.gradleファイルに。
この明らかにイライラする状況は、.apk
が作成され、一部のアセットは保存する前に圧縮されますが、他のアセットは既に圧縮されているものとして扱われ(画像、ビデオなど)、そのままになります。後者のグループはopenAssetFd
を使用して開くことができますが、前者のグループはできません-実行しようとすると、「このファイルはファイル記述子として開くことができません。おそらく圧縮されています」というエラーが表示されます。
1つのオプションは、ビルドシステムをだましてアセットを圧縮しないようにすることです(@nicstrongの回答のリンクを参照)。しかし、これは面倒です。より予測可能な方法で問題を回避して回避することをお勧めします。
私が思いついた解決策は、アセットのAssetFileDescriptor
を開くことはできないが、InputStream
を開くことができるという事実を利用しています。これを使用して、アセットをアプリケーションのファイルキャッシュにコピーし、その記述子を返すことができます。
@Override
public AssetFileDescriptor openAssetFile(final Uri uri, final String mode) throws FileNotFoundException
{
final String assetPath = uri.getLastPathSegment(); // or whatever
try
{
final boolean canBeReadDirectlyFromAssets = ... // if your asset going to be compressed?
if (canBeReadDirectlyFromAssets)
{
return getContext().getAssets().openFd(assetPath);
}
else
{
final File cacheFile = new File(getContext().getCacheDir(), assetPath);
cacheFile.getParentFile().mkdirs();
copyToCacheFile(assetPath, cacheFile);
return new AssetFileDescriptor(ParcelFileDescriptor.open(cacheFile, MODE_READ_ONLY), 0, -1);
}
}
catch (FileNotFoundException ex)
{
throw ex;
}
catch (IOException ex)
{
throw new FileNotFoundException(ex.getMessage());
}
}
private void copyToCacheFile(final String assetPath, final File cacheFile) throws IOException
{
final InputStream inputStream = getContext().getAssets().open(assetPath, ACCESS_BUFFER);
try
{
final FileOutputStream fileOutputStream = new FileOutputStream(cacheFile, false);
try
{
//using Guava IO lib to copy the streams, but could also do it manually
ByteStreams.copy(inputStream, fileOutputStream);
}
finally
{
fileOutputStream.close();
}
}
finally
{
inputStream.close();
}
}
これは、アプリがキャッシュファイルを嘘のままにすることを意味しますが、それで問題ありません。また、既存のキャッシュファイルを再利用することもありません。
この例外は、FileDesriptor
を開こうとした場合にのみ発生します。ファイルを読み取るだけの場合は、InputStream
(AssetManager.open("filename.ext")
)を使用できます。これでうまくいきました。
事前にファイルサイズが必要な場合は、FileDescriptor
(したがって圧縮されていないファイル)がgetLength()
メソッドを呼び出す必要があります。そうでない場合は、ストリーム全体を読み取ってサイズを決定する必要があります。
私は散歩をしました、私は使います:
ParcelFileDescriptor mFileDescriptor = context.getAssets().openFd(file).getParcelFileDescriptor();
しかし、その戻り値:Java.io.FileNotFoundException:このファイルはファイル記述子として開くことができません。おそらく圧縮されています。
この実装の代わりに、ParcelFileDescriptorの関数を使用してファイルを直接開きます。
private void openRenderer(Context context,String fileName) throws IOException {
File file= FileUtils.fileFromAsset(context, fileName);
ParcelFileDescriptor parcelFileDescriptor = ParcelFileDescriptor.open(file,ParcelFileDescriptor.MODE_READ_WRITE);
mPdfRenderer = new PdfRenderer(parcelFileDescriptor);
}`
public class FileUtils {
private FileUtils() {
}
public static File fileFromAsset(Context context, String assetName) throws IOException {
File outFile = new File(context.getCacheDir(), assetName );
copy(context.getAssets().open(assetName), outFile);
return outFile;
}
public static void copy(InputStream inputStream, File output) throws IOException {
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(output);
boolean read = false;
byte[] bytes = new byte[1024];
int read1;
while((read1 = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read1);
}
} finally {
try {
if(inputStream != null) {
inputStream.close();
}
} finally {
if(outputStream != null) {
outputStream.close();
}
}
}
}
}
この例外は、次の呼び出しによってスローできます。
final AssetFileDescriptor afd = activity.getAssets().openFd(path);
この問題を修正するには、assetsフォルダではなくres/raw
ディレクトリにファイルを保存し、AssetFileDescriptor
を次のように取得します。
final AssetFileDescriptor afd = activity.getResources().openRawResourceFd(rawId);
その後、FileNotFoundException
はなくなり、ファイルは圧縮されなくなりました。
gnome-sound-recorderがOGGファイルを作成するため、MediaPlayerを使用して再生できないため、同じ問題が発生しました。だから私はffmpegでそれらをMP3に変換し、それはうまくいきました。これが一番簡単な方法だと思います。
ffmpeg -i youroggfile yournewfile.mp3
また、リソースに疑問符が付いたまま表示されること、およびR.raw.yournewfileを使用してアクセスすると、コードに ".mp3"拡張子を記述しないことにも気付きました。 。
アセットフォルダーから取得するファイルが1 MBを超える場合、私にとって効果的なのは、ファイルをZipファイルとして圧縮し、使用する前に解凍して、圧縮せずに外部ストレージに保存することです。
InputStream fileInputStream = getAssets().open("your_file.your_file_extension.Zip");
unzipInputStream(fileInputStream, "your_folder_in_external_storage");
私が使用したunzipInputStream
メソッドはこれです:
public static void unzipInputStream(InputStream inputStream, String location)
{
try {
if ( !location.endsWith(File.separator) ) {
location += File.separator;
}
File f = new File(location);
if(!f.isDirectory()) {
f.mkdirs();
}
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(inputStream, BUFFER_SIZE));
try {
ZipEntry ze;
while ((ze = zin.getNextEntry()) != null) {
String path = location + ze.getName();
File unzipFile = new File(path);
if (ze.isDirectory()) {
if(!unzipFile.isDirectory()) {
unzipFile.mkdirs();
}
} else {
createParentDirectoriesIfMissing(unzipFile);
unzipFile(zin, unzipFile);
}
}
} finally {
zin.close();
}
} catch (Exception e) {
Log.e("", "Unzip exception", e);
}
}
private static void createParentDirectoriesIfMissing(File unzipFile)
{
File parentDir = unzipFile.getParentFile();
if ( null != parentDir ) {
if ( !parentDir.isDirectory() ) {
parentDir.mkdirs();
}
}
}
private static void unzipFile(ZipInputStream zin, File unzipFile) throws IOException
{
int size;
byte[] buffer = new byte[BUFFER_SIZE];
FileOutputStream out = new FileOutputStream(unzipFile, false);
BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE);
try {
while ( (size = zin.read(buffer, 0, BUFFER_SIZE)) != -1 ) {
fout.write(buffer, 0, size);
}
zin.closeEntry();
} finally {
fout.flush();
fout.close();
}
}