我正在尝试使用我的资源文件夹中的目录,并将其作为File
访问。是否可以以File
的形式访问Assets目录中的内容?如果没有,我如何将目录从Assets文件夹复制到应用程序的本地目录?
我会像这样复制一个文件:
try
{
InputStream stream = this.getAssets().open("myFile");
OutputStream output = new BufferedOutputStream(new FileOutputStream(this.getFilesDir() + "/myNewFile"));
byte data[] = new byte[1024];
int count;
while((count = stream.read(data)) != -1)
{
output.write(data, 0, count);
}
output.flush();
output.close();
stream.close();
}
catch(IOException e)
{
e.printStackTrace();
}
但是,我不确定如何为目录执行此操作。
我宁愿不围绕不起作用的东西构建我的基础架构,那么如何将目录从Assets复制到本地目录,或者是否可以作为File
访问我的Assets中的目录?
修改 的
这就是我为自己的项目解决的问题:
InputStream stream = null;
OutputStream output = null;
for(String fileName : this.getAssets().list("demopass"))
{
stream = this.getAssets().open("directoryName/" + fileName);
output = new BufferedOutputStream(new FileOutputStream(this.getFilesDir() + "/newDirectory/" + fileName));
byte data[] = new byte[1024];
int count;
while((count = stream.read(data)) != -1)
{
output.write(data, 0, count);
}
output.flush();
output.close();
stream.close();
stream = null;
output = null;
}
答案 0 :(得分:10)
正如上面评论中dmaxi所建议的那样,你可以使用他的链接,使用以下代码:
void displayFiles (AssetManager mgr, String path) {
try {
String list[] = mgr.list(path);
if (list != null)
for (int i=0; i<list.length; ++i)
{
Log.v("Assets:", path +"/"+ list[i]);
displayFiles(mgr, path + "/" + list[i]);
}
} catch (IOException e) {
Log.v("List error:", "can't list" + path);
}
}
我在this link上接受了它。 也许你可以把这个代码和先例代码结合起来。
编辑:另见AssetManager。
private void copyFolder(String name) {
// "Name" is the name of your folder!
AssetManager assetManager = getAssets();
String[] files = null;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
// Checking file on assets subfolder
try {
files = assetManager.list(name);
} catch (IOException e) {
Log.e("ERROR", "Failed to get asset file list.", e);
}
// Analyzing all file on assets subfolder
for(String filename : files) {
InputStream in = null;
OutputStream out = null;
// First: checking if there is already a target folder
File folder = new File(Environment.getExternalStorageDirectory() + "/yourTargetFolder/" + name);
boolean success = true;
if (!folder.exists()) {
success = folder.mkdir();
}
if (success) {
// Moving all the files on external SD
try {
in = assetManager.open(name + "/" +filename);
out = new FileOutputStream(Environment.getExternalStorageDirectory() + "/yourTargetFolder/" + name + "/" + filename);
Log.i("WEBVIEW", Environment.getExternalStorageDirectory() + "/yourTargetFolder/" + name + "/" + filename);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e("ERROR", "Failed to copy asset file: " + filename, e);
} finally {
// Edit 3 (after MMs comment)
in.close();
in = null;
out.flush();
out.close();
out = null;
}
}
else {
// Do something else on failure
}
}
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// We can only read the media
} else {
// Something else is wrong. It may be one of many other states, but all we need
// is to know is we can neither read nor write
}
}
// Method used by copyAssets() on purpose to copy a file.
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
编辑2:我在上面添加了一个示例:这段代码只复制了从资产到SD卡的特定文件夹。让我知道它是否有效!
答案 1 :(得分:2)
您可以使用以下方法将资产文件夹复制到SD卡中的某个位置。从您的调用方法中调用moveAssetToStorageDir(&#34;&#34;)来移动整个资产文件夹。如果是子文件夹,您可以指定资产文件夹中的相对路径。
public void moveAssetToStorageDir(String path){
File file = getExternalFilesDir(null);
String rootPath = file.getPath() + "/" + path;
try{
String [] paths = getAssets().list(path);
for(int i=0; i<paths.length; i++){
if(paths[i].indexOf(".")==-1){
File dir = new File(rootPath + paths[i]);
dir.mkdir();
moveAssetToStorageDir(paths[i]);
}else {
File dest = null;
InputStream in = null;
if(path.length() == 0) {
dest = new File(rootPath + paths[i]);
in = getAssets().open(paths[i]);
}else{
dest = new File(rootPath + "/" + paths[i]);
in = getAssets().open(path + "/" + paths[i]);
}
dest.createNewFile();
FileOutputStream out = new FileOutputStream(dest);
byte [] buff = new byte[in.available()];
in.read(buff);
out.write(buff);
out.close();
in.close();
}
}
}catch (Exception exp){
exp.printStackTrace();
}
}
答案 2 :(得分:1)
以下是OP答案的简洁版本。
public void copyAssetFolderToFolder(Context activity, String assetsFolder, File destinationFolder) {
InputStream stream = null;
OutputStream output = null;
try {
for (String fileName : activity.getAssets().list(assetsFolder)) {
stream = activity.getAssets().open(assetsFolder + ((assetsFolder.endsWith(File.pathSeparator))?"":File.pathSeparator) + fileName);
output = new BufferedOutputStream(new FileOutputStream(new File(destinationFolder, fileName)));
byte data[] = new byte[1024];
int count;
while ((count = stream.read(data)) != -1) {
output.write(data, 0, count);
}
output.flush();
output.close();
stream.close();
stream = null;
output = null;
}
} catch (/*any*/Exception e){e.printStackTrace();}
}
为了将来参考,请为每个人解决问题并发布内容完整的源列表。对于初学者和专家来说,这个网站可以是一个很好的编码资源,只要你能发布完整的答案。人们不能假设其他任何人都能理解&#34;随机代码块所属的地方,或代码应该在其中执行的上下文。
此示例调用活动的上下文,其中包含getAssets()
方法。在android平台中,除了Activity
之外,它们还可以提供此上下文。一个例子是(通用引用)Service
类。
答案 3 :(得分:0)
事情是......资产很特别。您无法将其包装在File
对象中并询问isDirectory()
,并且您无法将这些资产传递到NDK中。因此最好将它们包装起来并将它们移动到缓存目录或SDCard,这就是你在这里的原因。
我已经看到许多SO答案涉及某些版本的滚动文件或目录字符串数组,然后创建目录,然后是递归调用并复制单个文件。这导致您创建一个文件夹或文件,而您无法从资产中判断出来。
我的建议是将您要发送到SDCard或内部缓存文件夹的每个任意资产集合并将其压缩。该问题的结构与Assets概念更加兼容。
AssetManager assetManager = context.getAssets();
String fullAssetPath = fromAssetPath + "/" + zipFilename;
String toPath = "/wherever/I/want";
try {
InputStream inputStream = assetManager.open(fullAssetPath);
ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(inputStream));
ZipEntry zipEntry;
byte[] buffer = new byte[8192];
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
String fileOrDirectory = zipEntry.getName();
Uri.Builder builder = new Uri.Builder();
builder.scheme("file");
builder.appendPath(toPath);
builder.appendPath(fileOrDirectory);
String fullToPath = builder.build().getPath();
if (zipEntry.isDirectory()) {
File directory = new File(fullToPath);
directory.mkdirs();
continue;
}
FileOutputStream fileOutputStream = new FileOutputStream(fullToPath);
while ((count = zipInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, count);
}
fileOutputStream.close();
zipInputStream.closeEntry();
}
zipInputStream.close();
} catch (IOException e) {
Log.e(TAG, e.getLocalizedMessage());
}
我已经看到很多涉及非常小的缓冲区大小的示例,例如1024.除非您只是想浪费时间,请随意尝试更大的字节缓冲区大小。即使我选择的8192在现代硬件上也可能很小。
请注意使用Uri.Builder
构建路径。我更喜欢这种路径构造方式而不是directory
+&#34; /&#34; + file
。然后,为了保持一致性,您需要分配String d = "myDirectory/"
或String f = "/file.txt"
以及其他此类字符串黑客废话。
答案 4 :(得分:0)
这是复制资产文件夹的代码,目录和文件都复制到sdcard文件夹中... 这个对我很有用......
public void copyFileOrDir(String path) {
AssetManager assetManager = this.getAssets();
String assets[] = null;
try {
assets = assetManager.list(path);
if (assets.length == 0) {
copyFile(path);
} else {
String fullPath = "/data/data/" + this.getPackageName() + "/" + path;
File dir = new File(fullPath);
if (!dir.exists())
dir.mkdir();
for (int i = 0; i < assets.length; ++i) {
copyFileOrDir(path + "/" + assets[i]);
}
}
} catch (IOException ex) {
Log.e("tag", "I/O Exception", ex);
}
}
private void copyFile(String filename) {
AssetManager assetManager = this.getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
String newFileName = "/data/data/" + this.getPackageName() + "/" + filename;
out = new FileOutputStream(newFileName);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
答案 5 :(得分:0)
这里有一个递归函数可以执行此操作-copyAssetFolder
。
public static boolean copyAssetFolder(Context context, String srcName, String dstName) {
try {
boolean result = true;
String fileList[] = context.getAssets().list(srcName);
if (fileList == null) return false;
if (fileList.length == 0) {
result = copyAssetFile(context, srcName, dstName);
} else {
File file = new File(dstName);
result = file.mkdirs();
for (String filename : fileList) {
result &= copyAssetFolder(context, srcName + File.separator + filename, dstName + File.separator + filename);
}
}
return result;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
public static boolean copyAssetFile(Context context, String srcName, String dstName) {
try {
InputStream in = context.getAssets().open(srcName);
File outFile = new File(dstName);
OutputStream out = new FileOutputStream(outFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
out.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
答案 6 :(得分:0)
这是用kotlin编写的递归解决方案。它适用于文件和目录。
用法-copyAssetDir(context, "<asset path>", "<dest dir>")
import android.content.Context
import java.io.File
import java.io.FileOutputStream
fun copyAssetDir(context: Context, assetPath: String, destDirPath: String) {
walkAssetDir(context, assetPath) {
copyAssetFile(context, it, "$destDirPath/$it")
}
}
fun walkAssetDir(context: Context, assetPath: String, callback: ((String) -> Unit)) {
val children = context.assets.list(assetPath) ?: return
if (children.isEmpty()) {
callback(assetPath)
} else {
for (child in children) {
walkAssetDir(context, "$assetPath/$child", callback)
}
}
}
fun copyAssetFile(context: Context, assetPath: String, destPath: String): File {
val destFile = File(destPath)
File(destFile.parent).mkdirs()
destFile.createNewFile()
context.assets.open(assetPath).use { src ->
FileOutputStream(destFile).use { dest ->
src.copyTo(dest)
}
}
return destFile
}