如何解决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 \扩展名。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。