ฉันมีไฟล์สองสามไฟล์ในassets
โฟลเดอร์ ฉันต้องการคัดลอกทั้งหมดไปยังโฟลเดอร์ที่พูด / sdcard / โฟลเดอร์ ฉันต้องการทำสิ่งนี้จากภายในเธรด ฉันต้องทำอย่างไร?
ฉันมีไฟล์สองสามไฟล์ในassets
โฟลเดอร์ ฉันต้องการคัดลอกทั้งหมดไปยังโฟลเดอร์ที่พูด / sdcard / โฟลเดอร์ ฉันต้องการทำสิ่งนี้จากภายในเธรด ฉันต้องทำอย่างไร?
คำตอบ:
หากใครมีปัญหาเดียวกันนี่คือสิ่งที่ฉันทำ
private void copyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
if (files != null) for (String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
File outFile = new File(getExternalFilesDir(null), filename);
out = new FileOutputStream(outFile);
copyFile(in, out);
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// NOOP
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
// NOOP
}
}
}
}
}
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);
}
}
การอ้างอิง: ย้ายไฟล์โดยใช้ Java
Failed to copy asset file: myfile.txt java.io.FileNotFoundException: myfile.txt at android.content.res.AssetManager.openAsset(Native Method)
in = assetManager.open("images-wall/"+filename);
โดยที่ "images-wall" เป็นโฟลเดอร์ของฉันภายในเนื้อหา
ตามวิธีการแก้ปัญหาของคุณฉันทำบางอย่างของตัวเองเพื่ออนุญาตให้โฟลเดอร์ย่อย บางคนอาจพบว่ามีประโยชน์:
...
copyFileOrDir("myrootdir");
...
private 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());
}
}
assetManager.list(path)
อาจช้าในอุปกรณ์เพื่อสร้างรายการเส้นทางสินทรัพย์ก่อนตัวอย่างนี้อาจใช้จากassets
dir:find . -name "*" -type f -exec ls -l {} \; | awk '{print substr($9,3)}' >> assets.list
finally
บล็อก))
การแก้ปัญหาข้างต้นไม่ทำงานเนื่องจากข้อผิดพลาด:
นี่คือรหัส (ฉันออกจากบันทึกการใช้งาน แต่คุณสามารถวางได้ตอนนี้):
final static String TARGET_BASE_PATH = "/sdcard/appname/voices/";
private void copyFilesToSdCard() {
copyFileOrDir(""); // copy all files in assets folder in my project
}
private void copyFileOrDir(String path) {
AssetManager assetManager = this.getAssets();
String assets[] = null;
try {
Log.i("tag", "copyFileOrDir() "+path);
assets = assetManager.list(path);
if (assets.length == 0) {
copyFile(path);
} else {
String fullPath = TARGET_BASE_PATH + path;
Log.i("tag", "path="+fullPath);
File dir = new File(fullPath);
if (!dir.exists() && !path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit"))
if (!dir.mkdirs())
Log.i("tag", "could not create dir "+fullPath);
for (int i = 0; i < assets.length; ++i) {
String p;
if (path.equals(""))
p = "";
else
p = path + "/";
if (!path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit"))
copyFileOrDir( p + 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;
String newFileName = null;
try {
Log.i("tag", "copyFile() "+filename);
in = assetManager.open(filename);
if (filename.endsWith(".jpg")) // extension was added to avoid compression on APK file
newFileName = TARGET_BASE_PATH + filename.substring(0, filename.length()-4);
else
newFileName = TARGET_BASE_PATH + 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", "Exception in copyFile() of "+newFileName);
Log.e("tag", "Exception in copyFile() "+e.toString());
}
}
แก้ไข: แก้ไขการวางผิดที่ ";" ที่กำลังขว้างข้อผิดพลาด "ไม่สามารถสร้าง dir" ได้อย่างเป็นระบบ
ฉันรู้ว่าสิ่งนี้ได้รับคำตอบแล้ว แต่ฉันมีวิธีที่สง่างามกว่าเล็กน้อยในการคัดลอกจากไดเรกทอรีสินทรัพย์ไปยังไฟล์บน sdcard มันไม่จำเป็นต้องใช้ "for" loop แต่ใช้ File Streams and Channels แทนเพื่อทำงาน
(หมายเหตุ) หากใช้ไฟล์บีบอัดชนิดใด APK, PDF, ... คุณอาจต้องการเปลี่ยนชื่อนามสกุลไฟล์ก่อนที่จะแทรกลงในเนื้อหาแล้วเปลี่ยนชื่อเมื่อคุณคัดลอกไปยัง SDcard)
AssetManager am = context.getAssets();
AssetFileDescriptor afd = null;
try {
afd = am.openFd( "MyFile.dat");
// Create new file to copy into.
File file = new File(Environment.getExternalStorageDirectory() + java.io.File.separator + "NewFile.dat");
file.createNewFile();
copyFdToFile(afd.getFileDescriptor(), file);
} catch (IOException e) {
e.printStackTrace();
}
วิธีการคัดลอกไฟล์โดยไม่ต้องวนซ้ำ
public static void copyFdToFile(FileDescriptor src, File dst) throws IOException {
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
} finally {
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
}
This file can not be opened as a file descriptor; it is probably compressed
มันเป็นไฟล์ pdf รู้วิธีการแก้ไขที่?
ลองใช้มันง่ายกว่านี้จะช่วยให้คุณ:
// Open your local db as the input stream
InputStream myInput = _context.getAssets().open(YOUR FILE NAME);
// Path to the just created empty db
String outFileName =SDCARD PATH + YOUR FILE NAME;
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
นี่จะเป็นวิธีรัดกุมใน Kotlin
fun AssetManager.copyRecursively(assetPath: String, targetFile: File) {
val list = list(assetPath)
if (list.isEmpty()) { // assetPath is file
open(assetPath).use { input ->
FileOutputStream(targetFile.absolutePath).use { output ->
input.copyTo(output)
output.flush()
}
}
} else { // assetPath is folder
targetFile.delete()
targetFile.mkdir()
list.forEach {
copyRecursively("$assetPath/$it", File(targetFile, it))
}
}
}
นี่คือเวอร์ชั่นที่ล้างแล้วสำหรับอุปกรณ์ Android ปัจจุบันการออกแบบวิธีการทำงานเพื่อให้คุณสามารถคัดลอกไปยังคลาส AssetsHelper เช่น;)
/**
*
* Info: prior to Android 2.3, any compressed asset file with an
* uncompressed size of over 1 MB cannot be read from the APK. So this
* should only be used if the device has android 2.3 or later running!
*
* @param c
* @param targetFolder
* e.g. {@link Environment#getExternalStorageDirectory()}
* @throws Exception
*/
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public static boolean copyAssets(AssetManager assetManager,
File targetFolder) throws Exception {
Log.i(LOG_TAG, "Copying files from assets to folder " + targetFolder);
return copyAssets(assetManager, "", targetFolder);
}
/**
* The files will be copied at the location targetFolder+path so if you
* enter path="abc" and targetfolder="sdcard" the files will be located in
* "sdcard/abc"
*
* @param assetManager
* @param path
* @param targetFolder
* @return
* @throws Exception
*/
public static boolean copyAssets(AssetManager assetManager, String path,
File targetFolder) throws Exception {
Log.i(LOG_TAG, "Copying " + path + " to " + targetFolder);
String sources[] = assetManager.list(path);
if (sources.length == 0) { // its not a folder, so its a file:
copyAssetFileToFolder(assetManager, path, targetFolder);
} else { // its a folder:
if (path.startsWith("images") || path.startsWith("sounds")
|| path.startsWith("webkit")) {
Log.i(LOG_TAG, " > Skipping " + path);
return false;
}
File targetDir = new File(targetFolder, path);
targetDir.mkdirs();
for (String source : sources) {
String fullSourcePath = path.equals("") ? source : (path
+ File.separator + source);
copyAssets(assetManager, fullSourcePath, targetFolder);
}
}
return true;
}
private static void copyAssetFileToFolder(AssetManager assetManager,
String fullAssetPath, File targetBasePath) throws IOException {
InputStream in = assetManager.open(fullAssetPath);
OutputStream out = new FileOutputStream(new File(targetBasePath,
fullAssetPath));
byte[] buffer = new byte[16 * 1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
out.flush();
out.close();
}
แก้ไขคำตอบSOนี้โดย @DannyA
private void copyAssets(String path, String outPath) {
AssetManager assetManager = this.getAssets();
String assets[];
try {
assets = assetManager.list(path);
if (assets.length == 0) {
copyFile(path, outPath);
} else {
String fullPath = outPath + "/" + path;
File dir = new File(fullPath);
if (!dir.exists())
if (!dir.mkdir()) Log.e(TAG, "No create external directory: " + dir );
for (String asset : assets) {
copyAssets(path + "/" + asset, outPath);
}
}
} catch (IOException ex) {
Log.e(TAG, "I/O Exception", ex);
}
}
private void copyFile(String filename, String outPath) {
AssetManager assetManager = this.getAssets();
InputStream in;
OutputStream out;
try {
in = assetManager.open(filename);
String newFileName = outPath + "/" + 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();
out.flush();
out.close();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
การเตรียมการ
ในsrc/main/assets
เพิ่มโฟลเดอร์ด้วยชื่อfold
การใช้
File outDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());
copyAssets("fold",outDir.toString());
ในไดเรกทอรีภายนอกค้นหาไฟล์และไดเรกทอรีทั้งหมดที่อยู่ในสินทรัพย์เท่า
คัดลอกไฟล์และไดเรกทอรีทั้งหมดจากทรัพย์สินไปยังโฟลเดอร์ของคุณ!
สำหรับการคัดลอกที่ดีกว่าให้ใช้ apache ทั่วไป io
public void doCopyAssets() throws IOException {
File externalFilesDir = context.getExternalFilesDir(null);
doCopy("", externalFilesDir.getPath());
}
// นี่คือวิธีการหลักในการทำสำเนา
private void doCopy(String dirName, String outPath) throws IOException {
String[] srcFiles = assets.list(dirName);//for directory
for (String srcFileName : srcFiles) {
String outFileName = outPath + File.separator + srcFileName;
String inFileName = dirName + File.separator + srcFileName;
if (dirName.equals("")) {// for first time
inFileName = srcFileName;
}
try {
InputStream inputStream = assets.open(inFileName);
copyAndClose(inputStream, new FileOutputStream(outFileName));
} catch (IOException e) {//if directory fails exception
new File(outFileName).mkdir();
doCopy(inFileName, outFileName);
}
}
}
public static void closeQuietly(AutoCloseable autoCloseable) {
try {
if(autoCloseable != null) {
autoCloseable.close();
}
} catch(IOException ioe) {
//skip
}
}
public static void copyAndClose(InputStream input, OutputStream output) throws IOException {
copy(input, output);
closeQuietly(input);
closeQuietly(output);
}
public static void copy(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[1024];
int n = 0;
while(-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
}
ตามคำตอบของ Yoram Cohen นี่คือรุ่นที่สนับสนุนไดเรกทอรีเป้าหมายที่ไม่ใช่แบบคงที่
ออกใบแจ้งหนี้ด้วยcopyFileOrDir(getDataDir(), "")
เพื่อเขียนไปยังโฟลเดอร์ที่เก็บข้อมูลภายในแอพ / data / data / pkg_name /
หลีกเลี่ยงการคัดลอกโฟลเดอร์ทรัพย์สินปลอมเช่น "images" ฯลฯ
private void copyFileOrDir(String TARGET_BASE_PATH, String path) {
AssetManager assetManager = this.getAssets();
String assets[] = null;
try {
Log.i("tag", "copyFileOrDir() "+path);
assets = assetManager.list(path);
if (assets.length == 0) {
copyFile(TARGET_BASE_PATH, path);
} else {
String fullPath = TARGET_BASE_PATH + "/" + path;
Log.i("tag", "path="+fullPath);
File dir = new File(fullPath);
if (!dir.exists() && !path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit"))
if (!dir.mkdirs())
Log.i("tag", "could not create dir "+fullPath);
for (int i = 0; i < assets.length; ++i) {
String p;
if (path.equals(""))
p = "";
else
p = path + "/";
if (!path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit"))
copyFileOrDir(TARGET_BASE_PATH, p + assets[i]);
}
}
} catch (IOException ex) {
Log.e("tag", "I/O Exception", ex);
}
}
private void copyFile(String TARGET_BASE_PATH, String filename) {
AssetManager assetManager = this.getAssets();
InputStream in = null;
OutputStream out = null;
String newFileName = null;
try {
Log.i("tag", "copyFile() "+filename);
in = assetManager.open(filename);
if (filename.endsWith(".jpg")) // extension was added to avoid compression on APK file
newFileName = TARGET_BASE_PATH + "/" + filename.substring(0, filename.length()-4);
else
newFileName = TARGET_BASE_PATH + "/" + 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", "Exception in copyFile() of "+newFileName);
Log.e("tag", "Exception in copyFile() "+e.toString());
}
}
ใช้แนวคิดบางอย่างในคำตอบของคำถามนี้ฉันเขียนคลาสที่เรียกว่าAssetCopier
การคัดลอก/assets/
อย่างง่าย มันมีอยู่ในGitHubและสามารถเข้าถึงได้ด้วยjitpack.io :
new AssetCopier(MainActivity.this)
.withFileScanning()
.copy("tocopy", destDir);
ดูhttps://github.com/flipagram/android-assetcopierสำหรับรายละเอียดเพิ่มเติม
โดยพื้นฐานแล้วมีสองวิธีในการทำเช่นนี้
ก่อนอื่นคุณสามารถใช้AssetManager.openและตามที่อธิบายโดยRohith Nandakumarและทำซ้ำผ่านอินพุตสตรีม
ประการที่สองคุณสามารถใช้AssetManager.openFdซึ่งช่วยให้คุณใช้FileChannel (ซึ่งมี [transferTo] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferTo(long , ยาว java.nio.channels.WritableByteChannel) และ [transferFrom] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferFrom(java.nio.channels.ReadableByteChannelยาว) ยาว)) วิธีการ) ดังนั้นคุณไม่ต้องวนซ้ำอินพุตสตรีมด้วยตัวคุณเอง
ฉันจะอธิบายวิธี openFd ที่นี่
ก่อนอื่นคุณต้องแน่ใจว่าไฟล์นั้นถูกบีบอัดไว้ ระบบบรรจุภัณฑ์อาจเลือกที่จะบีบอัดไฟล์ใด ๆ ที่มีส่วนขยายที่ไม่ได้ทำเครื่องหมายเป็นnoCompressและไฟล์บีบอัดไม่สามารถแมปหน่วยความจำได้ดังนั้นคุณจะต้องพึ่งพาAssetManager.openในกรณีนั้น
คุณสามารถเพิ่มส่วนขยาย '.mp3' ลงในไฟล์ของคุณเพื่อหยุดการบีบอัด แต่วิธีแก้ไขที่เหมาะสมคือการแก้ไขไฟล์แอพ / build.gradleของคุณและเพิ่มบรรทัดต่อไปนี้ (เพื่อปิดการบีบอัดไฟล์ PDF)
aaptOptions {
noCompress 'pdf'
}
โปรดทราบว่าผู้ทำแพ็กเกจยังคงสามารถบรรจุไฟล์หลาย ๆ ไฟล์เป็นไฟล์เดียวดังนั้นคุณไม่สามารถอ่านไฟล์ทั้งหมดที่AssetManagerให้มา คุณต้องถามAssetFileDescriptorว่าต้องการชิ้นส่วนใด
เมื่อคุณได้มั่นใจไฟล์ของคุณจะถูกเก็บไว้ไม่มีการบีบอัด, คุณสามารถใช้AssetManager.openFdวิธีการที่จะได้รับAssetFileDescriptorซึ่งสามารถนำมาใช้เพื่อให้ได้FileInputStream (เหมือนAssetManager.openซึ่งส่งกลับInputStream ) ที่มีFileChannel นอกจากนี้ยังมีออฟเซ็ตเริ่มต้น (getStartOffset)และขนาด (getLength)ซึ่งคุณต้องได้รับส่วนที่ถูกต้องของไฟล์
ตัวอย่างการใช้งานได้รับด้านล่าง:
private void copyFileFromAssets(String in_filename, File out_file){
Log.d("copyFileFromAssets", "Copying file '"+in_filename+"' to '"+out_file.toString()+"'");
AssetManager assetManager = getApplicationContext().getAssets();
FileChannel in_chan = null, out_chan = null;
try {
AssetFileDescriptor in_afd = assetManager.openFd(in_filename);
FileInputStream in_stream = in_afd.createInputStream();
in_chan = in_stream.getChannel();
Log.d("copyFileFromAssets", "Asset space in file: start = "+in_afd.getStartOffset()+", length = "+in_afd.getLength());
FileOutputStream out_stream = new FileOutputStream(out_file);
out_chan = out_stream.getChannel();
in_chan.transferTo(in_afd.getStartOffset(), in_afd.getLength(), out_chan);
} catch (IOException ioe){
Log.w("copyFileFromAssets", "Failed to copy file '"+in_filename+"' to external storage:"+ioe.toString());
} finally {
try {
if (in_chan != null) {
in_chan.close();
}
if (out_chan != null) {
out_chan.close();
}
} catch (IOException ioe){}
}
}
คำตอบนี้จะขึ้นอยู่กับคำตอบของ JPM
import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Environment;
import android.os.Bundle;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
copyReadAssets();
}
private void copyReadAssets()
{
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
String strDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+ File.separator + "Pdfs";
File fileDir = new File(strDir);
fileDir.mkdirs(); // crear la ruta si no existe
File file = new File(fileDir, "example2.pdf");
try
{
in = assetManager.open("example.pdf"); //leer el archivo de assets
out = new BufferedOutputStream(new FileOutputStream(file)); //crear el archivo
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag", e.getMessage());
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "Pdfs" + "/example2.pdf"), "application/pdf");
startActivity(intent);
}
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);
}
}
}
เปลี่ยนส่วนของรหัสดังนี้:
out = new BufferedOutputStream(new FileOutputStream(file));
ตัวอย่างก่อนหน้านี้สำหรับไฟล์ PDF ในกรณีที่เป็นตัวอย่าง. txt
FileOutputStream fos = new FileOutputStream(file);
ใช้AssetManagerช่วยให้สามารถอ่านไฟล์ในเนื้อหา จากนั้นใช้ Java IO ปกติเพื่อเขียนไฟล์ไปยัง sdcard
Google เป็นเพื่อนของคุณค้นหาตัวอย่าง
สวัสดีพวกฉันทำบางสิ่งเช่นนี้ สำหรับการคัดลอกโฟลเดอร์และไฟล์ความลึก N-th เพื่อคัดลอก ซึ่งช่วยให้คุณสามารถคัดลอกโครงสร้างไดเรกทอรีทั้งหมดเพื่อคัดลอกจาก Android AssetManager :)
private void manageAssetFolderToSDcard()
{
try
{
String arg_assetDir = getApplicationContext().getPackageName();
String arg_destinationDir = FRConstants.ANDROID_DATA + arg_assetDir;
File FolderInCache = new File(arg_destinationDir);
if (!FolderInCache.exists())
{
copyDirorfileFromAssetManager(arg_assetDir, arg_destinationDir);
}
} catch (IOException e1)
{
e1.printStackTrace();
}
}
public String copyDirorfileFromAssetManager(String arg_assetDir, String arg_destinationDir) throws IOException
{
File sd_path = Environment.getExternalStorageDirectory();
String dest_dir_path = sd_path + addLeadingSlash(arg_destinationDir);
File dest_dir = new File(dest_dir_path);
createDir(dest_dir);
AssetManager asset_manager = getApplicationContext().getAssets();
String[] files = asset_manager.list(arg_assetDir);
for (int i = 0; i < files.length; i++)
{
String abs_asset_file_path = addTrailingSlash(arg_assetDir) + files[i];
String sub_files[] = asset_manager.list(abs_asset_file_path);
if (sub_files.length == 0)
{
// It is a file
String dest_file_path = addTrailingSlash(dest_dir_path) + files[i];
copyAssetFile(abs_asset_file_path, dest_file_path);
} else
{
// It is a sub directory
copyDirorfileFromAssetManager(abs_asset_file_path, addTrailingSlash(arg_destinationDir) + files[i]);
}
}
return dest_dir_path;
}
public void copyAssetFile(String assetFilePath, String destinationFilePath) throws IOException
{
InputStream in = getApplicationContext().getAssets().open(assetFilePath);
OutputStream out = new FileOutputStream(destinationFilePath);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0)
out.write(buf, 0, len);
in.close();
out.close();
}
public String addTrailingSlash(String path)
{
if (path.charAt(path.length() - 1) != '/')
{
path += "/";
}
return path;
}
public String addLeadingSlash(String path)
{
if (path.charAt(0) != '/')
{
path = "/" + path;
}
return path;
}
public void createDir(File dir) throws IOException
{
if (dir.exists())
{
if (!dir.isDirectory())
{
throw new IOException("Can't create directory, a file is in the way");
}
} else
{
dir.mkdirs();
if (!dir.isDirectory())
{
throw new IOException("Unable to create directory");
}
}
}
ในท้ายที่สุดสร้าง Asynctask:
private class ManageAssetFolders extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... arg0)
{
manageAssetFolderToSDcard();
return null;
}
}
เรียกมันว่าจากกิจกรรมของคุณ:
new ManageAssetFolders().execute();
การแก้ไขเล็กน้อยของคำตอบข้างต้นเพื่อคัดลอกโฟลเดอร์ซ้ำและรองรับปลายทางที่กำหนดเอง
public void copyFileOrDir(String path, String destinationDir) {
AssetManager assetManager = this.getAssets();
String assets[] = null;
try {
assets = assetManager.list(path);
if (assets.length == 0) {
copyFile(path,destinationDir);
} else {
String fullPath = destinationDir + "/" + path;
File dir = new File(fullPath);
if (!dir.exists())
dir.mkdir();
for (int i = 0; i < assets.length; ++i) {
copyFileOrDir(path + "/" + assets[i], destinationDir + path + "/" + assets[i]);
}
}
} catch (IOException ex) {
Log.e("tag", "I/O Exception", ex);
}
}
private void copyFile(String filename, String destinationDir) {
AssetManager assetManager = this.getAssets();
String newFileName = destinationDir + "/" + filename;
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(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());
}
new File(newFileName).setExecutable(true, false);
}
จากวิธีแก้ปัญหาของ Rohith Nandakumar ฉันได้ทำบางสิ่งเป็นของตัวเองเพื่อคัดลอกไฟล์จากโฟลเดอร์ย่อยของสินทรัพย์ (เช่น "assets / MyFolder ") นอกจากนี้ฉันกำลังตรวจสอบว่าไฟล์มีอยู่แล้วใน sdcard ก่อนที่จะพยายามคัดลอกอีกครั้ง
private void copyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("MyFolder");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
if (files != null) for (String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open("MyFolder/"+filename);
File outFile = new File(getExternalFilesDir(null), filename);
if (!(outFile.exists())) {// File does not exist...
out = new FileOutputStream(outFile);
copyFile(in, out);
}
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// NOOP
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
// NOOP
}
}
}
}
}
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);
}
}
นี่คือทางออกที่ดีที่สุดที่ฉันสามารถหาได้บนอินเทอร์เน็ต ผมเคยใช้การเชื่อมโยงต่อไปนี้https://gist.github.com/mhasby/026f02b33fcc4207b302a60645f6e217 ,
แต่มันก็มีข้อผิดพลาดเดียวที่ฉันคงที่และแล้วมันทำงานเช่นเสน่ห์ นี่คือรหัสของฉัน คุณสามารถใช้มันได้อย่างง่ายดายเนื่องจากเป็นคลาส java อิสระ
public class CopyAssets {
public static void copyAssets(Context context) {
AssetManager assetManager = context.getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", "Failed to get asset file list.", e);
}
if (files != null) for (String filename : files) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
out = new FileOutputStream(Environment.getExternalStorageDirectory()+"/www/resources/" + filename);
copyFile(in, out);
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
finally {
if (in != null) {
try {
in.close();
in = null;
} catch (IOException e) {
}
}
if (out != null) {
try {
out.flush();
out.close();
out = null;
} catch (IOException e) {
}
}
}
}
}
public static 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);
}
}}
อย่างที่คุณเห็นเพียงแค่สร้างตัวอย่าง CopyAssets
ในคลาส java ของคุณที่มีกิจกรรม You cannot use AssetManager if the class has no activity
ตอนนี้ส่วนนี้มีความสำคัญเท่าที่ทดสอบของฉันและการวิจัยในอินเทอร์เน็ต มันมีบางอย่างที่เกี่ยวข้องกับบริบทของคลาส java
ตอนนี้c.copyAssets(getApplicationContext())
เป็นวิธีที่ง่ายในการเข้าถึงวิธีการที่c
เป็นและตัวอย่างของการCopyAssets
เรียน ตามความต้องการของฉันฉันอนุญาตให้โปรแกรมคัดลอกไฟล์ทรัพยากรทั้งหมดของฉันภายในasset
โฟลเดอร์ไปยัง/www/resources/
ไดเรกทอรีภายในของฉัน
คุณสามารถค้นหาส่วนที่คุณต้องการทำการเปลี่ยนแปลงในไดเรกทอรีตามการใช้งานของคุณ อย่าลังเลที่จะ ping ฉันหากคุณต้องการความช่วยเหลือ
สำหรับผู้ที่กำลังอัพเดทเป็น Kotlin:
ต่อไปนี้ขั้นตอนในการหลีกเลี่ยงFileUriExposedExceptions
การใช้งานเผื่อว่าได้รับได้รับอนุญาตและไฟล์ของคุณอยู่ในWRITE_EXTERNAL_STORAGE
assets/pdfs/mypdf.pdf
private fun openFile() {
var inputStream: InputStream? = null
var outputStream: OutputStream? = null
try {
val file = File("${activity.getExternalFilesDir(null)}/$PDF_FILE_NAME")
if (!file.exists()) {
inputStream = activity.assets.open("$PDF_ASSETS_PATH/$PDF_FILE_NAME")
outputStream = FileOutputStream(file)
copyFile(inputStream, outputStream)
}
val uri = FileProvider.getUriForFile(
activity,
"${BuildConfig.APPLICATION_ID}.provider.GenericFileProvider",
file
)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, "application/pdf")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
}
activity.startActivity(intent)
} catch (ex: IOException) {
ex.printStackTrace()
} catch (ex: ActivityNotFoundException) {
ex.printStackTrace()
} finally {
inputStream?.close()
outputStream?.flush()
outputStream?.close()
}
}
@Throws(IOException::class)
private fun copyFile(input: InputStream, output: OutputStream) {
val buffer = ByteArray(1024)
var read: Int = input.read(buffer)
while (read != -1) {
output.write(buffer, 0, read)
read = input.read(buffer)
}
}
companion object {
private const val PDF_ASSETS_PATH = "pdfs"
private const val PDF_FILE_NAME = "mypdf.pdf"
}