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)

любые идеи?

Ответ 1

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

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

Ответ 2

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

android {
    aaptOptions {
        noCompress "pdf"
    }
}

Источник

Ответ 3

Люди, работающие с файлом Tensorflow Lite, сталкиваются с этой проблемой,

Добавьте следующие строки в свой файл Gradle внутри android {}.

aaptOptions {
    noCompress "tflite"
}

Ответ 4

Эта явно раздражающая ситуация возникает, потому что, когда создается .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();
    }
}

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

Ответ 5

Просто добавьте:

    aaptOptions {
       noCompress "your-file-name"
    }

В ваш файл build.gradle.

Ответ 6

Вы должны получить это исключение только при попытке открыть FileDesriptor. Для простого чтения файла вы можете пройти через InputStream (AssetManager.open("filename.ext")). Это сработало для меня.

Если вам нужен размер файла заранее, вам понадобится FileDescriptor (и, следовательно, несжатый файл), чтобы вызвать его метод getLength(), в противном случае вы должны прочитать весь поток, чтобы определить его размер.

Ответ 7

Я сделал прогулку, я использую:

ParcelFileDescriptor mFileDescriptor = context.getAssets().openFd(file).getParcelFileDescriptor();

Но это return: java.io.FileNotFoundException: этот файл не может быть открыт в качестве дескриптора файла; он, вероятно, сжат.

Вместо этой реализации я открываю файл напрямую, используя функции form 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();
                }

            }

        }

    }
}

Ответ 8

Это исключение можно вызвать, вызвав:

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

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

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

Затем FileNotFoundException, и файл больше не сжимается.

Ответ 9

Если размер файла, который нужно получить из папки ресурсов, превышает 1 МБ, тогда мне нужно сжимать файл в виде 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();
    }
}