【问题标题】:java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressedjava.io.FileNotFoundException:这个文件不能作为文件描述符打开;它可能被压缩了
【发布时间】:2011-09-05 10:10:24
【问题描述】:

我正在从 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)

有什么想法吗?

【问题讨论】:

    标签: java android cordova filenotfoundexception


    【解决方案1】:

    您可以为某些扩展禁用资产压缩,如下所示:

    android {
        aaptOptions {
            noCompress "pdf"
        }
    }
    

    Source

    【讨论】:

    • 在我的情况下,资产文件夹中已经有一个 zip。所以它在编译时再次压缩了文件。我放了“zip”而不是“pdf”,错误消失了。
    • 您可以使用此命令验证哪些条目被压缩:unzip -lv MyApplication.apk“方法”列中的“已存储”表示文件未压缩。
    • 你救了我免于把我的头撞到墙上 :D 非常感谢!
    • 为我工作,我有一个 .xml 文件。一旦我将它添加到 noCompress 中,一切正常,谢谢
    • 非常感谢,伙计,这已经困扰我好几个星期了。由于某种原因,我不能再播放 ogg 文件了。我没有碰我的代码或手机,我只更新了 Android Studio。很高兴找到这个答案,再次感谢。
    【解决方案2】:

    使用 Tensorflow Lite 文件的人遇到了这个问题,

    将以下行添加到 android{} 块内的 Gradle 文件 (android/app/build.gradle)。

    aaptOptions {
        noCompress "tflite"
    }
    

    【讨论】:

    • 示例项目没问题。但是当我编译aar时,这个错误发生在新项目的aar模式下。
    【解决方案3】:

    在资产文件夹中打开压缩文件存在限制。这是因为解压后的文件可以直接内存映射到进程的虚拟地址空间,从而避免了再次需要相同数量的内存进行解压。

    Dealing with Asset Compression in Android Apps 讨论了处理压缩文件的一些技术。您可以欺骗aapt 使用未压缩的扩展名(例如mp3)不压缩文件,或者您可以手动将它们添加到apk 而不压缩,而不是让aapt 完成工作。

    【讨论】:

    • 最后,我所有问题的答案。这确实记录得很差! +1
    • 我拥有的二进制资产文件约为 1.1MB。我将它重命名为 jpg/png 等,这样压缩就不会启动。但是当复制到 sdcard 时,它会膨胀到 ~8MB。所以不知何故,AssetManager 仍然认为需要解压缩。有谁知道这里发生了什么?
    • 浪费了几个小时后,我终于设法从原始文件而不是资产中读取文件,并且它们不再“未压缩”。
    • 如果有一个未压缩的扩展列表就好了:-P
    • @GreenBee 您介意指出如何从原始目录复制文件吗?我已经尝试添加 noCompress 选项以获取具体扩展名,并复制文件(大于 1MB),但没有任何效果。我在复制的文件中获得了 APK 的大小。奇怪:S
    【解决方案4】:

    您应该禁用该文件的压缩。只需添加:

        aaptOptions {
           noCompress "your-file-name"
        }
    

    到您的应用级别build.gradle 文件内android { }

    【讨论】:

      【解决方案5】:

      之所以会出现这种令人恼火的情况,是因为在构建 .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();
          }
      }
      

      这确实意味着您的应用会留下缓存文件,但这没关系。它也不会尝试重用您可能关心或不关心的现有缓存文件。

      【讨论】:

        【解决方案6】:

        这个异常可以通过调用来抛出:

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

        我通过将文件保存在 res/raw 目录而不是 assets 文件夹中来解决问题,然后以这种方式获取 AssetFileDescriptor

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

        那么FileNotFoundException就没有了,文件也不再压缩了。

        【讨论】:

          【解决方案7】:

          只有在尝试打开FileDesriptor 时才会出现此异常。只需阅读文件,您可以通过InputStream (AssetManager.open("filename.ext"))。这对我有用。

          如果你需要提前知道文件大小,你需要FileDescriptor(因此是一个未压缩的文件)来调用它的getLength()方法,否则你必须读取整个流来确定它的大小。

          【讨论】:

            【解决方案8】:

            我已经走了一圈,我用:

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

            【讨论】:

              【解决方案9】:

              刚刚在 build.gradle 中添加了我的文件扩展名,如下所示,解决了我的问题

              android {
                 aaptOptions {
                    noCompress "tflite"
                    noCompress "txt"
                    noCompress "pdf"
                 }
              }
              

              【讨论】:

                【解决方案10】:

                如果要从 assets 文件夹中获取的文件大于 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, 0, BUFFER_SIZE)) != -1 ) {
                            fout.write(buffer, 0, size);
                        }
                
                        zin.closeEntry();
                    } finally {
                        fout.flush();
                        fout.close();
                    }
                }
                

                【讨论】:

                  【解决方案11】:

                  我刚刚遇到了同样的问题,因为 gnome-sound-recorder 创建了 OGG 文件,我无法使用 MediaPlayer 播放这些文件。所以我用 ffmpeg 将它们转换为 MP3 并且它工作。所以我想这是最简单的方法。

                  ffmpeg -i youroggfile yournewfile.mp3
                  

                  我还注意到,它仍然在资源中显示一个问号,并且当我使用 R.raw.yournewfile 访问它时,我没有编写“.mp3”扩展名在代码中。

                  【讨论】:

                    【解决方案12】:

                    我遇到了同样的问题,我将文件从 res/raw 复制到 /data/data/your.app.pkg/cache 文件夹,然后一切顺利:D

                    AssetFileDescriptor afd = null;
                    try {
                        File cache = new File(getCacheDir(), "my_data.dat");
                        if (!cache.exists()) {
                            copyInputStreamToFile(getResources().openRawResource(R.raw.my_data), cache);
                        }
                        afd = new AssetFileDescriptor(ParcelFileDescriptor.open(cache, ParcelFileDescriptor.MODE_READ_ONLY), 0, AssetFileDescriptor.UNKNOWN_LENGTH);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    
                    
                    private void copyInputStreamToFile(InputStream in, File file) {
                        BufferedOutputStream bfos = null;
                    
                        try {
                            bfos = new BufferedOutputStream(new FileOutputStream(file));
                            byte[] buf = new byte[4096];
                    
                            int len;
                            while ((len = in.read(buf)) != -1) {
                                bfos.write(buf, 0, len);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                if (bfos != null) {
                                    bfos.close();
                                }
                                in.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    

                    【讨论】:

                      【解决方案13】:

                      在我的情况下,它是由 resource.arsc 压缩引起的。用未压缩的resource.arsc重建解决问题。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-01-31
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多