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)
有任何想法吗?     

解决方法

        在资产文件夹中打开压缩文件存在限制。这是因为未压缩的文件可以直接内存映射到进程的虚拟地址空间,因此避免了再次需要相同数量的内存进行解压缩。 在Android Apps中处理资产压缩讨论了一些处理压缩文件的技术。您可以通过使用未压缩的扩展名(例如
mp3
)来欺骗ѭ1not不压缩文件,或者您可以将它们手动添加到
apk
中而不进行压缩,而不是让
aapt
完成工作。     ,        您可以为某些扩展名禁用资产压缩,如下所示:
android {
    aaptOptions {
        noCompress \"pdf\"
    }
}
资源     ,        人们正在使用Tensorflow Lite文件运行此问题, 将以下行添加到android {}中的Gradle文件中。
aaptOptions {
    noCompress \"tflite\"
}
    ,        之所以会出现这种令人恼火的情况,是因为在构建“ 7”时,有些资产在存储之前会被压缩,而另一些资产则被视为已压缩(例如,图像,视频)并被单独放置。后一组可以使用ѭ8opened打开,前一组则不能-如果尝试尝试,则会出现\“此文件无法作为文件描述符打开;可能已压缩\”错误。 一种选择是欺骗构建系统以使其不压缩资产(请参阅@nicstrong的答案中的链接),但这很奇怪。最好以更可预测的方式尝试解决该问题。 我提出的解决方案使用的事实是,虽然您无法为资产开价9英镑,但仍然可以开10英镑。您可以使用它来将资产复制到应用程序的文件缓存中,然后返回该描述符的描述:
@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),-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();
    }
}
这确实意味着您的应用将保留缓存文件,但这很好。它还不会尝试重复使用您可能会或不会在意的现有缓存文件。     ,        只需添加:
    aaptOptions {
       noCompress \"your-file-name\"
    }
到您的build.gradle文件。     ,        仅当尝试打开
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,read1);
            }
        } finally {
            try {
                if(inputStream != null) {
                    inputStream.close();
                }
            } finally {
                if(outputStream != null) {
                    outputStream.close();
                }

            }

        }

    }
}
    ,        可以通过调用以下方法引发此异常:
final AssetFileDescriptor afd = activity.getAssets().openFd(path);
我通过将文件保存在
res/raw
目录而不是资产文件夹中来解决此问题,然后通过以下方式获取get9ѭ:
final AssetFileDescriptor afd = activity.getResources().openRawResourceFd(rawId);
然后ѭ24消失了,该文件不再压缩。     ,        如果要从资产文件夹中获取的文件大于1MB,那么对我有用的是将文件压缩为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,BUFFER_SIZE)) != -1 ) {
            fout.write(buffer,size);
        }

        zin.closeEntry();
    } finally {
        fout.flush();
        fout.close();
    }
}
    ,        我只是遇到了同样的问题,因为gnome-sound-recorder创建了OGG文件,我无法使用MediaPlayer播放这些文件。因此,我使用ffmpeg将其转换为MP3并成功了。所以我想这是最简单的方法。
ffmpeg -i youroggfile yournewfile.mp3
我还注意到的是,它仍然在资源中显示一个问号,并且当我使用R.raw.yournewfile访问它时,我没有在代码中写入\ .mp3 \扩展名。     

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...