Як скопіювати файли з папки "Активи" на sdcard?


250

У мене в assetsпапці є кілька файлів . Мені потрібно скопіювати їх у папку say / sdcard / folder. Я хочу це зробити з нитки. Як це зробити?



2
Перед тим, як копіювати / вставити один з наведених нижче рішень, рекомендується використовувати цю бібліотеку , щоб зробити це в одному рядку коду: (великий!) Stackoverflow.com/a/41970539/9648
JohnnyLambada

Відповіді:


345

Якщо у когось іншого виникає така ж проблема, це я і зробив

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


28
щоб писати файли на sdcard, ви повинні дати дозвіл на маніфест, наприклад <використання-дозволу android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
IronBlossom

22
Я також не покладався б на те, щоб sdcard знаходився за адресою / sdcard, але отримував шлях із Environment.getExternalStorageDirectory ()
Axarydax,

2
Якщо я повинен використовувати: 16 * 1024 (16 кб), я схильний вибирати 16 К або 32 К як хороший баланс між використанням пам'яті та продуктивністю.
Нам Ву

3
@rciovati отримав цю помилку виконанняFailed to copy asset file: myfile.txt java.io.FileNotFoundException: myfile.txt at android.content.res.AssetManager.openAsset(Native Method)
likejudo

7
Для мене цей код працює лише в тому випадку, якщо я додаю це: in = assetManager.open("images-wall/"+filename);де "images-wall" - моя папка всередині активів
Ultimo_m

62

На основі вашого рішення я зробив щось власне, щоб дозволити вкладені папки. Хтось може вважати це корисним:

...

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());
    }

}

1
assetManager.list(path)може бути повільним на пристрої, щоб заздалегідь створити список шляхів до активів, цей фрагмент може бути використаний з assetsfind . -name "*" -type f -exec ls -l {} \; | awk '{print substr($9,3)}' >> assets.list
режисура

3
Приємне рішення! Єдине необхідне виправлення - обрізати провідні роздільники на початку copyFileOrDir (): path = path.startsWith ("/")? path.substring (1): шлях;
Хрест_


2
замініть "/ data / data /" + this.getPackageName () на
this.getFilesDir

1
... і близькі потоки в finallyблоці))
Міксаз

48

Наведене вище рішення не спрацювало через деякі помилки:

  • створення каталогу не працювало
  • активи, повернені Android, містять також три папки: зображення, звуки та веб-каси
  • Доданий спосіб поводження з великими файлами: Додайте розширення .mp3 у файл у папці активів у вашому проекті, а під час копіювання цільовий файл буде без розширення .mp3

Ось код (я залишив заяви Журналу, але ви можете їх зараз скинути):

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());
    }

}

EDIT: виправлено неправильне ";" це кидало систематичну помилку "не могло створити реж".


4
це повинно стати рішенням!
Массімо Варіоло

1
ПРИМІТКА: Log.i ("тег", "не вдалося створити dir" + fullPath); завжди буває як; неправильно розміщено на if.
RoundSparrow hilltx

дивовижний спосіб! Дуже дякую! Але чому ви перевіряєте jpg-файл?
Пхуонг

32

Я знаю, що на це відповіли, але у мене є трохи більш елегантний спосіб копіювання з каталогу активів у файл на sdcard. Він не вимагає циклу "для", але замість цього використовує файлові потоки та канали для виконання роботи.

(Примітка) Якщо ви використовуєте будь-який тип стисненого файлу, 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();
    }
}

Сподобалось це іншим рішенням, трохи акуратніше. Незначна модифікація шахти, що включає створення відсутніх папок файлів. ура!
Chris.Jenkins

3
Це не вдалося пройти повз дескриптор файлу для мене, This file can not be opened as a file descriptor; it is probably compressed- це pdf-файл. Знаєте, як це виправити?
жовтня

1
Це передбачає, що inChannel.size () повертає розмір розміру файлу. Це не дає такої гарантії . Я отримую 2,5 Мбіт для 2 файлів, по 450 Кб кожен.
AI0867

1
Щойно я виявив, що AssetFileDescriptor.getLength () поверне правильний розмір файлів.
AI0867

1
На додаток до вищезазначеного, актив може не починатись із місця 0 у дескрипторі файлів. AssetFileDescriptor.getStartOffset () поверне початкове зміщення.
AI0867

5

спробуйте це набагато простіше, це допоможе вам:

// 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();

5

Це було б стисло у Котліні.

    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))
            }
        }
    }

список (resourcePath) ?. Нехай насправді {...}. Це нікчемне.
Габор

4

Ось очищена версія для поточних пристроїв 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();
}

4

Модифікований цей 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());

У зовнішньому каталозі знайдіть усі файли та каталоги, що знаходяться в складних ресурсах


3

Скопіюйте всі файли та каталоги з активів у свою папку!

для копіювання краще використовувати apache commons 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);
    }
}

2

На основі відповіді Йорама Коена, ось версія, яка підтримує нестатичний цільовий каталог.

Запросити copyFileOrDir(getDataDir(), "")до запису до внутрішньої папки зберігання додатків / даних / даних / pkg_name /

  • Підтримує папки.
  • Підтримує спеціальний і нестатичний цільовий каталог
  • Уникає копіювання подібних папок "зображення" тощо

    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());
    }
    
    }

2

Використовуючи деякі поняття у відповідях на це запитання, я написав клас, покликаний AssetCopierзробити копіювання /assets/простим. Доступний на github і доступ до нього можна отримати за допомогою jitpack.io :

new AssetCopier(MainActivity.this)
        .withFileScanning()
        .copy("tocopy", destDir);

Докладнішу інформацію див. На https://github.com/flipagram/android-assetcopier .


2

По суті є два способи зробити це.

По-перше, ви можете скористатися AssetManager.open і, як описано Рохітом Нандакумаром, і повторити його над вхідним потоком.

По-друге, ви можете використовувати AssetManager.openFd , що дозволяє використовувати FileChannel (який має [transferTo] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferTo(long , long, java.nio.channels.WritableByteChannel)) і [transferFrom] ( https://developer.android.com/reference/java/nio/nio/channels/FileChannel.html#transferFrom(java.nio.channels.ReadableByteChannel , long, довгі)) методи), тому вам не доведеться самостійно перебирати вхідний потік.

Я опишу тут метод 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 .


1
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));

попередній приклад - для Pdfs, у випадку з прикладом .txt

FileOutputStream fos = new FileOutputStream(file);

1

Використовуйте AssetManager , він дозволяє читати файли в активах. Потім використовуйте звичайний Java IO для запису файлів на sdcard.

Google - ваш друг, шукайте приклад.


1

Привіт, хлопці, я зробив щось подібне. Для копіювання папок і файлів на N-ту глибину. Що дозволяє копіювати всю структуру каталогів для копіювання з 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");
            }
        }
    }

Врешті-решт Створіть асинтакт:

    private class ManageAssetFolders extends AsyncTask<Void, Void, Void>
    {

        @Override
        protected Void doInBackground(Void... arg0)
        {
            manageAssetFolderToSDcard();
            return null;
        }

    }

зателефонуйте йому З вашої діяльності:

    new ManageAssetFolders().execute();

1

Незначна модифікація наведеної вище відповіді для копіювання папки рекурсивно та для розміщення спеціального призначення.

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);
}

1

На основі рішення Рохіта Нандакумара я зробив щось власне, щоб скопіювати файли з підпапки активів (тобто "активи / 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);
    }
}

0

Це, безумовно, найкраще рішення, яке мені вдалося знайти в Інтернеті. Я використав наступне посилання 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/мого внутрішнього каталогу.
Ви можете легко дізнатися частину, де потрібно внести зміни до каталогу відповідно до вашого використання. Якщо вам потрібна допомога, не соромтеся зателефонувати мені.


0

Для тих, хто оновлює Котлін:

Виконуючи ці дії, щоб уникнути 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"
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.