i am programming a soundboard from android. the problem is that some sounds works, and some dont work. here is the traceback that i get for the sounds that doesnt work
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)
any ideas?
You can disable asset compression for certain extensions like so:
android {
aaptOptions {
noCompress "pdf"
}
}
Source
People working with Tensorflow Lite file running into this issue,
Add the following lines to your Gradle file (android/app/build.gradle
) inside the android{}
block.
aaptOptions {
noCompress "tflite"
}
There is a limitations on opening compressed files in the assets folder. This is because uncompressed files can be directly memory mapped into the processes virtual address space, therefore avoiding needing the same amount of memory again for decompression.
Dealing with Asset Compression in Android Apps discusses some techniques in dealing with compressed files. You can trick aapt
into not compressing the file by using an extension that is not compressed (e.g. mp3
) or you can manually add them to the apk
without compression instead of getting aapt
to do the work.
You should disable compression for that file. Simply add:
aaptOptions {
noCompress "your-file-name"
}
To your app level build.gradle
file inside android { }
This decidedly irritating situation comes about because when the .apk
is built, some assets are compressed before storing them, whereas other are treated as already compressed (e.g. images, video) and are left alone. The latter group can be opened using openAssetFd
, the former group can't - if you try, you get the "This file can not be opened as a file descriptor; it is probably compressed" error.
One option is to trick the build system into not compressing the assets (see the link in @nicstrong's answer), but this is fiddly. Better to try and work around the problem in a more predictable fashion.
The solution I cam up with uses the fact that while you can't open an AssetFileDescriptor
for the asset, you can still open an InputStream
. You can use this to copy the asset into the application's file cache, and then return a descriptor for that:
@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();
}
}
This does mean that your app will leave cache files lying about, but that's fine. It also doesn't attempt to re-use existing cache files, which you may or may not care about.
This exception can be thrown by calling:
final AssetFileDescriptor afd = activity.getAssets().openFd(path);
I fixed the problem by saving the file in res/raw
directory instead of assets folder, then get the AssetFileDescriptor
this way:
final AssetFileDescriptor afd = activity.getResources().openRawResourceFd(rawId);
Then the FileNotFoundException
is gone, and the file is not compressed anymore.
You should get this exception only if trying to open the FileDesriptor
. For just reading the file you can go the way through the InputStream
(AssetManager.open("filename.ext")
). This worked for me.
If you need the file size in advance, you need the FileDescriptor
(and therefore an uncompressed file) to call its getLength()
method, otherwise you have to read the whole stream to determine its size.
I have done a walk around, I use:
ParcelFileDescriptor mFileDescriptor = context.getAssets().openFd(file).getParcelFileDescriptor();
But that return: java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed.
Instead of this implementation I open the file directly using functions 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();
}
}
}
}
}
Just added the extension of my file like below in the build.gradle and solved my issue
android {
aaptOptions {
noCompress "tflite"
noCompress "txt"
noCompress "pdf"
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With