我正在编写一个来自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)
任何想法?
答案 0 :(得分:57)
答案 1 :(得分:29)
在资源文件夹中打开压缩文件存在限制。这是因为未压缩文件可以直接内存映射到进程虚拟地址空间,因此避免再次需要相同数量的内存进行解压缩。
Dealing with Asset Compression in Android Apps讨论了处理压缩文件的一些技巧。您可以通过使用未压缩的扩展(例如aapt
)来欺骗mp3
不压缩文件,或者您可以手动将它们添加到apk
而不压缩而不是{{1}做这项工作。
答案 2 :(得分:16)
正在使用Tensorflow Lite文件的人们遇到了这个问题,
将以下行添加到android {}中的Gradle文件中。
aaptOptions {
noCompress "tflite"
}
答案 3 :(得分: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();
}
}
这确实意味着您的应用会留下缓存文件,但这很好。它也不会尝试重复使用您可能会或可能不关心的现有缓存文件。
答案 4 :(得分:3)
只有在尝试打开FileDesriptor
时才会出现此异常。只需阅读文件即可完成InputStream
(AssetManager.open("filename.ext")
)。这对我有用。
如果您需要提前调整文件大小,则需要FileDescriptor
(因此是未压缩的文件)来调用其getLength()
方法,否则您必须读取整个流以确定其大小。
答案 5 :(得分:3)
只需添加:
aaptOptions {
noCompress "your-file-name"
}
到您的build.gradle文件。
答案 6 :(得分:1)
我已经走了一圈,我用:
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();
}
}
}
}
}
答案 7 :(得分:1)
可以通过调用抛出此异常:
final AssetFileDescriptor afd = activity.getAssets().openFd(path);
我通过将文件保存在res/raw
目录而不是资产文件夹中,然后通过以下方式获取AssetFileDescriptor
来解决了这个问题:
final AssetFileDescriptor afd = activity.getResources().openRawResourceFd(rawId);
然后FileNotFoundException
消失了,文件不再被压缩。
答案 8 :(得分:0)
如果要从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();
}
}
答案 9 :(得分:0)
我只是遇到了同样的问题,因为 gnome-sound-recorder 创建了OGG文件,我无法使用MediaPlayer播放它们。因此,我用 ffmpeg 将它们转换为MP3并成功了。所以我想这是最简单的方法。
ffmpeg -i youroggfile yournewfile.mp3
我还注意到,它仍然在资源中显示一个问号,并且当我使用 R.raw.yournewfile 访问它时,我没有写“ .mp3”扩展名在代码中。
答案 10 :(得分:0)
我遇到了同样的问题,然后将文件从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();
}
}
}
答案 11 :(得分:0)
只需在build.gradle中添加我的文件扩展名(如下所示)并解决我的问题
android {
aaptOptions {
noCompress "tflite"
noCompress "txt"
noCompress "pdf"
}
}
答案 12 :(得分:0)
就我而言,它是由resource.arsc 引起的被压缩。使用未压缩的资源重新构建.arsc 解决问题。