Comment copier des fichiers du dossier 'assets' vers sdcard?

251

J'ai quelques fichiers dans le assetsdossier. J'ai besoin de les copier tous dans un dossier disons / sdcard / folder. Je veux le faire à partir d'un fil. Comment fait-on ça?

Rohith Nandakumar
la source
Recherchez-vous ce stackoverflow.com/questions/4447477/…
DropAndTrap
2
Avant de copier / coller l'une des (excellentes!) Solutions ci-dessous, envisagez d'utiliser cette bibliothèque pour le faire en une seule ligne de code: stackoverflow.com/a/41970539/9648
JohnnyLambada

Réponses:

346

Si quelqu'un d'autre a le même problème, c'est comme ça que je l'ai fait

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

Référence: déplacer un fichier à l'aide de Java

Rohith Nandakumar
la source
28
pour écrire des fichiers dans la carte SD, vous devez donner l'autorisation sur le manifeste, par exemple <uses-permission android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
IronBlossom
22
Je ne compterais pas non plus sur sdcard situé dans / sdcard, mais récupérer le chemin avec Environment.getExternalStorageDirectory ()
Axarydax
2
Dois-je utiliser: 16 * 1024 (16 Ko) J'ai tendance à opter pour 16 Ko ou 32 Ko comme bon équilibre entre l'utilisation de la mémoire et les performances.
Nam Vu
3
@rciovati a obtenu cette erreur d'exécutionFailed to copy asset file: myfile.txt java.io.FileNotFoundException: myfile.txt at android.content.res.AssetManager.openAsset(Native Method)
likejudo
7
Pour moi, ce code ne fonctionne que si j'ajoute ceci: in = assetManager.open("images-wall/"+filename);où "images-wall" est mon dossier à l'intérieur des ressources
Ultimo_m
62

Sur la base de votre solution, j'ai fait quelque chose de moi-même pour autoriser les sous-dossiers. Quelqu'un pourrait trouver cela utile:

...

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

}
DannyA
la source
1
assetManager.list(path)peut être lent sur l'appareil, pour créer au préalable la liste des chemins d'accès aux ressources, cet extrait peut être utilisé à partir de assetsdir:find . -name "*" -type f -exec ls -l {} \; | awk '{print substr($9,3)}' >> assets.list
alexkasko
3
Bonne solution! Le seul correctif requis consiste à supprimer les séparateurs de tête au début de copyFileOrDir (): path = path.startsWith ("/")? path.substring (1): chemin;
Cross_
Ce stackoverflow est sur certains appareils, par exemple: S5
behelit
2
remplacez "/ data / data /" + this.getPackageName () par this.getFilesDir (). getAbsolutePath ()
ibrahimyilmaz
1
... et fermer les flux en finallybloc))
Mixaz
48

La solution ci-dessus n'a pas fonctionné en raison de certaines erreurs:

  • la création du répertoire n'a pas fonctionné
  • les actifs retournés par Android contiennent également trois dossiers: images, sons et webkit
  • Ajout d'un moyen de gérer les fichiers volumineux: ajoutez l'extension .mp3 au fichier dans le dossier des ressources de votre projet et pendant la copie, le fichier cible sera sans l'extension .mp3

Voici le code (j'ai laissé les instructions Log mais vous pouvez les supprimer maintenant):

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: correction d'un ";" mal placé qui lançait une erreur systématique "impossible de créer dir".

Yoram Cohen
la source
4
cela doit devenir la solution!
Massimo Variolo
1
REMARQUE: Log.i ("tag", "n'a pas pu créer dir" + fullPath); arrive toujours comme; est mal placé sur l'if.
RoundSparrow hilltx
façon géniale! Merci beaucoup! Mais pourquoi vous vérifiez le fichier jpg?
Phuong
32

Je sais que cela a été répondu, mais j'ai une façon légèrement plus élégante de copier du répertoire des actifs vers un fichier sur la carte SD. Il ne nécessite pas de boucle "for" mais utilise à la place des flux de fichiers et des canaux pour effectuer le travail.

(Remarque) Si vous utilisez n'importe quel type de fichier compressé, APK, PDF, ... vous voudrez peut-être renommer l'extension de fichier avant de l'insérer dans l'actif, puis renommer une fois que vous le copiez sur 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();
}

Un moyen de copier un fichier sans avoir à le parcourir.

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();
    }
}
JPM
la source
J'ai bien aimé cela par rapport aux autres solutions, un peu plus soigné. Légère modification sur la mienne qui inclut la création de dossiers manquants. à votre santé!
Chris.Jenkins
3
Cela ne fonctionnerait pas après le descripteur de fichier pour moi, This file can not be opened as a file descriptor; it is probably compressed- c'est un fichier pdf. Vous savez comment résoudre ce problème?
Gaʀʀʏ
1
Cela suppose que inChannel.size () renvoie la taille de la taille du fichier. Il n'offre aucune garantie de ce genre . J'obtiens 2,5 Mio pour 2 fichiers de 450 Kio chacun.
AI0867
1
Je viens de découvrir que AssetFileDescriptor.getLength () retournera la taille de fichier correcte.
AI0867
1
En plus de ce qui précède, l'actif peut ne pas démarrer à l'emplacement 0 dans le descripteur de fichier. AssetFileDescriptor.getStartOffset () renverra l'offset de départ.
AI0867
5

essayez, c'est beaucoup plus simple, cela vous aidera à:

// 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();
GOLDEE
la source
5

Ce serait une manière concise à 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))
            }
        }
    }
cchcc
la source
list (assetPath)?. laisser {...}, en fait. C'est nul.
Gábor
4

Voici une version nettoyée pour les appareils Android actuels, une conception de méthode fonctionnelle pour que vous puissiez la copier dans une classe AssetsHelper, par exemple;)

/**
 * 
 * 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();
}
Simon
la source
4

Modifié cette réponse SO par @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());
    }

}

Les préparatifs

dans le src/main/assets dossier d'ajout avec le nomfold

Usage

File outDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString());
copyAssets("fold",outDir.toString());

Dans le répertoire externe, trouvez tous les fichiers et répertoires qui se trouvent dans les actifs de pliage

Webserveis
la source
3

Copiez tous les fichiers et répertoires des ressources dans votre dossier!

pour copier mieux utiliser apache commons io

public void doCopyAssets() throws IOException {
    File externalFilesDir = context.getExternalFilesDir(null);

    doCopy("", externalFilesDir.getPath());

}

// CECI EST LA PRINCIPALE MÉTHODE DE COPIE

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);
    }
}
Serhii Bohutskyi
la source
2

Basé sur la réponse de Yoram Cohen, voici une version qui prend en charge le répertoire cible non statique.

Invoquez avec copyFileOrDir(getDataDir(), "")pour écrire dans le dossier de stockage de l'application interne / data / data / pkg_name /

  • Prend en charge les sous-dossiers.
  • Prend en charge le répertoire cible personnalisé et non statique
  • Évite de copier des "images", etc. de faux dossiers de ressources comme

    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());
    }
    
    }
KrisWebDev
la source
2

En utilisant certains des concepts dans les réponses à cette question, j'ai rédigé un cours appelé AssetCopierpour rendre la copie /assets/simple. Il est disponible sur github et est accessible avec jitpack.io :

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

Voir https://github.com/flipagram/android-assetcopier pour plus de détails.

JohnnyLambada
la source
2

Il existe essentiellement deux façons de procéder.

Tout d'abord, vous pouvez utiliser AssetManager.open et, comme décrit par Rohith Nandakumar, et parcourir le flux d' entrée .

Deuxièmement, vous pouvez utiliser AssetManager.openFd , qui vous permet d'utiliser un FileChannel (qui a le [transferTo] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferTo(long , long, java.nio.channels.WritableByteChannel)) et [transferFrom] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferFrom(java.nio.channels.ReadableByteChannel , long, long))), vous n'avez donc pas à faire de boucle sur le flux d'entrée vous-même.

Je décrirai ici la méthode openFd.

Compression

Vous devez d'abord vous assurer que le fichier est stocké non compressé. Le système de conditionnement peut choisir de compresser n'importe quel fichier avec une extension qui n'est pas marquée comme noCompress , et les fichiers compressés ne peuvent pas être mappés en mémoire, vous devrez donc compter sur AssetManager.open dans ce cas.

Vous pouvez ajouter une extension '.mp3' à votre fichier pour l'empêcher d'être compressé, mais la bonne solution consiste à modifier votre fichier app / build.gradle et à ajouter les lignes suivantes (pour désactiver la compression des fichiers PDF)

aaptOptions {
    noCompress 'pdf'
}

Emballage de fichiers

Notez que le conditionneur peut toujours regrouper plusieurs fichiers en un seul, vous ne pouvez donc pas simplement lire le fichier entier AssetManager vous donne. Vous devez demander au AssetFileDescriptor quelles pièces vous avez besoin.

Recherche de la bonne partie du fichier compressé

Une fois que vous avez vérifié votre fichier est stocké non compressé, vous pouvez utiliser la AssetManager.openFd méthode pour obtenir un AssetFileDescriptor , qui peut être utilisé pour obtenir un FileInputStream (contrairement AssetManager.open , qui renvoie un InputStream ) qui contient un FileChannel . Il contient également l' offset de départ (getStartOffset) et la taille (getLength) , dont vous avez besoin pour obtenir la bonne partie du fichier.

la mise en oeuvre

Un exemple d'implémentation est donné ci-dessous:

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

Cette réponse est basée sur la réponse de JPM .

AI0867
la source
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);
        }
    }
}

changer des parties de code comme celles-ci:

out = new BufferedOutputStream(new FileOutputStream(file));

l'exemple précédent est pour Pdfs, dans le cas de l'exemple .txt

FileOutputStream fos = new FileOutputStream(file);
Alex Zaraos
la source
1

Utiliser AssetManager , il permet de lire les fichiers dans les actifs. Utilisez ensuite Java IO normal pour écrire les fichiers sur sdcard.

Google est votre ami, recherchez un exemple.

Drakosha
la source
1

Salut les gars, j'ai fait quelque chose comme ça. Pour copier le dossier et les fichiers de la Nième profondeur. Ce qui vous permet de copier toute la structure du répertoire à copier depuis 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");
            }
        }
    }

À la fin, créez une tâche asynctrame:

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

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

    }

appelez-le De votre activité:

    new ManageAssetFolders().execute();
DropAndTrap
la source
1

Légère modification de la réponse ci-dessus pour copier un dossier de manière récursive et pour accueillir une destination personnalisée.

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);
}
Binoy Babu
la source
1

Basé sur la solution de Rohith Nandakumar, j'ai fait quelque chose de moi-même pour copier des fichiers à partir d'un sous-dossier d'actifs (c'est-à-dire "actifs / Mon dossier "). De plus, je vérifie si le fichier existe déjà dans sdcard avant d'essayer de copier à nouveau.

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);
    }
}
Pablo Alfonso
la source
0

C'est de loin la meilleure solution que j'ai pu trouver sur Internet. J'ai utilisé le lien suivant https://gist.github.com/mhasby/026f02b33fcc4207b302a60645f6e217 ,
mais il y avait une seule erreur que j'ai corrigée, puis cela fonctionne comme un charme. Voici mon code. Vous pouvez facilement l'utiliser car c'est une classe java indépendante.

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

Comme vous pouvez le voir, créez simplement une instance de CopyAssetsdans votre classe java qui a une activité. Maintenant , cette partie est importante, dans la mesure où mes tests et des recherches sur Internet, You cannot use AssetManager if the class has no activity. Cela a quelque chose à voir avec le contexte de la classe java.
Maintenant, le c.copyAssets(getApplicationContext())est un moyen facile d'accéder à la méthode, où cest et instance de CopyAssetsclasse. Selon mes besoins, j'ai autorisé le programme à copier tous mes fichiers de ressources dans le assetdossier vers le /www/resources/répertoire interne.
Vous pouvez facilement trouver la partie où vous devez apporter des modifications au répertoire selon votre utilisation. N'hésitez pas à me cingler si vous avez besoin d'aide.

Shan Singh
la source
0

Pour ceux qui mettent à jour Kotlin:

En suivant ces étapes pour éviter FileUriExposedExceptions, en supposant que l'utilisateur a accordé l' WRITE_EXTERNAL_STORAGEautorisation et que votre fichier se trouve 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"
}
Oscar
la source