如何从资产文件中获取URI?

161

我一直在尝试获取资产文件的URI路径。

uri = Uri.fromFile(new File("//assets/mydemo.txt"));

当我检查文件是否存在时,我发现文件不存在

File f = new File(filepath);
if (f.exists() == true) {
    Log.e(TAG, "Valid :" + filepath);
} else {
    Log.e(TAG, "InValid :" + filepath);
}

有人可以告诉我如何提及存在于资产文件夹中的文件的绝对路径吗?

13个回答

189

在资产文件夹中,不存在“文件的绝对路径”。您项目的assets/文件夹中的内容已打包到 APK 文件中。使用AssetManager对象获取资产上的InputStream

对于WebView,您可以使用file Uri方案,就像使用 URL 一样。 资产的语法为file:///android_asset/...(注意:三个斜杠),其中省略号是从assets/文件夹中获取文件的路径。


35
file://android_asset/...中的...是指在项目的assets/目录中的相对路径。 - CommonsWare
5
这是一个使用 file://android_asset/ 的示例项目,虽然不是用于 Uri。https://github.com/commonsguy/cw-advandroid/tree/master/WebView/GeoWeb1 - CommonsWare
22
@CommonsWare 似乎在 URI 中漏掉了一个斜杆。正确的写法应该是 file:///。请注意第三个斜杠。 - ThomasW
11
我尝试使用new File("file:///android_asset/sounds/beep.mid"),但结果文件不存在。有什么想法吗?附言:文件在assets/sounds/文件夹中。 - uncle Lem
6
´file:///android_asset/...´只能在WebView中使用,无法在WebView之外使用URI/URL/Uri获取InputStream,这说法正确吗? - Lubbo
显示剩余5条评论

80

正确的URL是:

file:///android_asset/RELATIVEPATH

RELATIVEPATH是相对于assets文件夹的资源路径。

请注意:方案中有3个斜杠。如果只用2个斜杠(之前由CommonsWare评论过),Web视图将无法加载我的任何资产。然后我查看了CommonsWare在github上的源代码,并注意到多了一个正斜杠。

这种测试只在1.6 Android模拟器上进行过,但我怀疑在真实设备或更高版本上也不会有所不同。

编辑:CommonsWare更新了他的答案以反映这个微小的变化。因此,我已编辑了这个内容,以使其与他当前的答案保持一致。


3
不再起作用了String fileName = "file:///android_asset/file.csv";System.out.println(new File(fileName).exists()); // 输出 false - Elgirhath
@Elgirhath,接受字符串参数的 File 构造函数期望传入一个“路径”而不是一个“URI”。我已经有几年没有编写 Android 代码了,事情可能已经发生了变化。我不确定是否可以使用普通的 Java File 类访问嵌入式资产文件夹。我记得你必须使用 AssetManager。位于 assets 文件夹中的文件被放置在设备的只读捆绑 APK 中并且被压缩(APK 实际上是 zip 文件),因此需要更多的工作来读取它。尝试类似这样的代码: new File(new URI(filename)) - Russ

31

最后,我发现了一种从 Kotlin 中的 这个 回答中获取 assets 文件路径的方法。在这里,我们将 assets 文件复制到缓存中,并从该缓存文件获取文件路径。

@Throws(IOException::class)
    fun getFileFromAssets(context: Context, fileName: String): File = File(context.cacheDir, fileName)
            .also {
               if (!it.exists()) {
                it.outputStream().use { cache ->
                    context.assets.open(fileName).use { inputStream ->
                            inputStream.copyTo(cache)
                    }
                  }
                }
            }

获取文件路径的方法如下:

val filePath =  getFileFromAssets(context, "fileName.extension").absolutePath

1
请注意,如果fileName有目录dir/file,它将崩溃并显示路径cache/dir/file不存在。此外,我认为最好在also块内进行检查if(!it.exist),这样即使文件已经在缓存中,它也不会每次都复制文件。 - Yeung
检查缓存中是否存在该文件名的文件?@binrebin - Shailendra Madda
@SamChen 很高兴它对你有帮助。 - Shailendra Madda
@Shailendra Madda,你能帮我解决这个问题吗:https://dev59.com/27T3oIgBc1ULPQZFlF_X,非常感激! - Sam Chen
2
如果文件名之前有一些目录,例如 -> ("raw/filename.ext" ),在 it.outputStream().use { cache -> ... 之前的 !it.exists() 块内添加以下代码以创建目录(如果不存在)--> val fileDir = File( context.cacheDir, File.separator.toString() + "raw" ) fileDir.mkdir() - A S A D I
显示剩余4条评论

15
请尝试这段代码,它能正常工作。
 Uri imageUri = Uri.fromFile(new File("//android_asset/luc.jpeg"));

    /* 2) Create a new Intent */
    Intent imageEditorIntent = new AdobeImageIntent.Builder(this)
            .setData(imageUri)
            .build();

7

请确保你的资源文件夹放置在正确的位置。

注意:本段话涉及IT技术相关内容,通俗易懂是指尽可能用简单的语言表达,不要使用过于专业的词汇和解释。

这里输入图片描述


2
你可以将它放在任何地方,并在build.gradle文件中定义路径,如下所示:sourceSets { main { assets.srcDirs = ['src/main/assets'] } } - Marcel Bro
6
如何获取hello.html文件的路径?请添加。 - Rohit Singh

6

在WebView中有效,但似乎在URL.openStream()上失败。因此,您需要区分file://协议并按建议通过AssetManager处理它们。


3
InputStream is = getResources().getAssets().open("terms.txt");
String textfile = convertStreamToString(is);
    
public static String convertStreamToString(InputStream is)
        throws IOException {

    Writer writer = new StringWriter();
    char[] buffer = new char[2048];

    try {
        Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        int n;
        while ((n = reader.read(buffer)) != -1) {
            writer.write(buffer, 0, n);
        }
    } finally {
        is.close();
    }

    String text = writer.toString();
    return text;
}

3

试一下这个,它有效:

InputStream in_s = 
    getClass().getClassLoader().getResourceAsStream("TopBrands.xml");

如果出现空值异常,请尝试以下方法(使用类TopBrandData):
InputStream in_s1 =
    TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");

如果不起作用,请尝试这个:InputStream in_s1 = TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml"); - Jaspreet Singh

1

try this :

Uri uri = Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.cat); 

我已经做了,而且它起作用了。

2
实际上它是有效的。请检查ContentResolver.openAssetFileDescriptor - Hippo Seven
1
工作了。非常感谢。哈哈,我只是在寻找获取URI内部文件的方法//在RES中创建RAW文件夹,然后命名文件仅包含小写字母a..z0..9字符,不得有大写字母!!! - phnghue

1

由于它实际上是APK文件中的数据而不是在模拟器上,因此您将无法找到“绝对路径”。我最终以相当简单的方式实现了这一点:

private fun getUriFromAsset(context: Context, assetFileName: String): Uri? {
    val assetManager = context.assets
    var inputStream: InputStream? = null
    var outputStream: FileOutputStream? = null
    var tempFile: File? = null

    return try {
        inputStream = assetManager.open(assetFileName)
        tempFile = File.createTempFile("temp_asset", null, context.cacheDir)
        outputStream = FileOutputStream(tempFile)

        inputStream.copyTo(outputStream)

        Uri.fromFile(tempFile)
    } catch (e: IOException) {
        e.printStackTrace()
        null
    } finally {
        inputStream?.close()
        outputStream?.close()
        tempFile?.deleteOnExit()
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接