首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >java.io.FileNotFoundException:此文件无法作为文件描述符打开;它可能已压缩

java.io.FileNotFoundException:此文件无法作为文件描述符打开;它可能已压缩
EN

Stack Overflow用户
提问于 2011-05-31 19:27:41
回答 13查看 50.3K关注 0票数 54

我正在编程一个声板从安卓。问题是有些声音是有效的,而有些则不起作用。下面是我对不起作用的声音的回溯

代码语言:javascript
复制
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)

有什么想法吗?

EN

Stack Overflow用户

发布于 2014-06-19 12:19:35

这种令人恼火的情况是因为当构建.apk时,一些资产在存储之前会被压缩,而其他资产则被视为已经压缩(例如图像、视频)并被单独处理。后一组可以使用openAssetFd打开,前一组则不能-如果您尝试这样做,您会得到"This file can not be as a file descriptor;it This is compressed“错误。

一种选择是欺骗构建系统不压缩资产(参见@nicstrong的答案中的链接),但这很麻烦。最好尝试以一种更可预测的方式解决这个问题。

我使用的解决方案使用了这样一个事实,即虽然您不能打开资产的AssetFileDescriptor,但您仍然可以打开InputStream。您可以使用它将资源复制到应用程序的文件缓存中,然后返回该资源的描述符:

代码语言:javascript
复制
@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
EN
查看全部 13 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6186866

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档