java.Ио.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.run(PluginManager.java:86)
05-31 13:23:04.235 18440 18603 W System.err:    at java.lang.Thread.run(Thread.java:1096)

какие идеи?

6 ответов


существует ограничение на открытие сжатых файлов в папке assets. Это связано с тем, что несжатые файлы могут быть напрямую сопоставлены с виртуальным адресным пространством процессов, поэтому для распаковки не требуется столько же памяти.

работа с сжатием активов в приложениях Android обсуждаются некоторые методы работы со сжатыми файлами. Вы можете обмануть aapt в не сжатие файла с помощью расширения, которое не сжатый (например,mp3) или вы можете вручную добавить их в apk без сжатия вместо aapt для выполнения работы.


вы можете отключить сжатие активов для определенных расширений, например:

android {
    aaptOptions {
        noCompress "pdf"
    }
}

источник


эта решительно раздражающая ситуация возникает потому, что когда .apk построен, некоторые активы сжимаются перед их хранением, в то время как другие рассматриваются как уже сжатые (например, изображения, видео) и остаются в покое. Последнюю группу можно открыть с помощью openAssetFd, первая группа не может - если вы попытаетесь, вы получите ошибку" этот файл не может быть открыт как дескриптор файла; вероятно, он сжат".

один из вариантов-обмануть систему сборки, чтобы не сжимать активы (см. ссылку в ответе @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.Ио.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);

я исправил проблему, сохранив файл в каталоге res/raw вместо папки assets, а затем получите AssetFileDescriptor следующим образом:

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

затем исключение FileNotFoundException исчезло, и файл больше не сжимается.