web-dev-qa-db-ja.com

java.io.FileNotFoundException:このファイルはファイル記述子として開くことができません。おそらく圧縮されています

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)

何か案は?

40
ihucos

アセットフォルダー内の圧縮ファイルを開くには制限があります。これは、非圧縮ファイルをプロセスの仮想アドレス空間に直接メモリマップできるため、解凍のために同じ量のメモリを再度必要としないためです。

Android Apps でのアセット圧縮の扱い)では、圧縮ファイルを処理するためのいくつかの手法について説明しています。aaptをだまして、拡張子を使用してファイルを圧縮しないようにすることができます圧縮されていない(例:mp3)または、apkを取得する代わりに、圧縮せずに手動でaaptに追加して作業を行うことができます。

36
Nic Strong

次のように、特定の拡張機能のアセット圧縮を無効にすることができます。

Android {
    aaptOptions {
        noCompress "pdf"
    }
}

ソース

75
Brian Bowman

この問題が発生しているTensorflow Liteファイルを使用しているユーザーは、

Android {}内のGradleファイルに次の行を追加します。

aaptOptions {
    noCompress "tflite"
}
21
devDeejay

単に追加:

    aaptOptions {
       noCompress "your-file-name"
    }

Build.gradleファイルに。

6

この明らかにイライラする状況は、.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();
    }
}

これは、アプリがキャッシュファイルを嘘のままにすることを意味しますが、それで問題ありません。また、既存のキャッシュファイルを再利用することもありません。

5
skaffman

この例外は、FileDesriptorを開こうとした場合にのみ発生します。ファイルを読み取るだけの場合は、InputStreamAssetManager.open("filename.ext"))を使用できます。これでうまくいきました。

事前にファイルサイズが必要な場合は、FileDescriptor(したがって圧縮されていないファイル)がgetLength()メソッドを呼び出す必要があります。そうでない場合は、ストリーム全体を読み取ってサイズを決定する必要があります。

3
cybergen

私は散歩をしました、私は使います:

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();
                }

            }

        }

    }
}
2
Alfaplus

この例外は、次の呼び出しによってスローできます。

final AssetFileDescriptor afd = activity.getAssets().openFd(path);

この問題を修正するには、assetsフォルダではなくres/rawディレクトリにファイルを保存し、AssetFileDescriptorを次のように取得します。

final AssetFileDescriptor afd = activity.getResources().openRawResourceFd(rawId);

その後、FileNotFoundExceptionはなくなり、ファイルは圧縮されなくなりました。

1
Q Locker

gnome-sound-recorderがOGGファイルを作成するため、MediaPlayerを使用して再生できないため、同じ問題が発生しました。だから私はffmpegでそれらをMP3に変換し、それはうまくいきました。これが一番簡単な方法だと思います。

ffmpeg -i youroggfile yournewfile.mp3

また、リソースに疑問符が付いたまま表示されること、およびR.raw.yournewfileを使用してアクセスすると、コードに ".mp3"拡張子を記述しないことにも気付きました。 。

0

アセットフォルダーから取得するファイルが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();
    }
}
0
xarlymg89