Wie kopiere ich Dateien aus dem Ordner "Assets" auf die SD-Karte?

251

Ich habe ein paar Dateien im assetsOrdner. Ich muss sie alle in einen Ordner kopieren, z. B. / sdcard / folder. Ich möchte dies aus einem Thread heraus tun. Wie mache ich es?

Rohith Nandakumar
quelle
Suchen Sie nach diesem stackoverflow.com/questions/4447477/…
DropAndTrap
2
Bevor Sie eine der folgenden (großartigen!) Lösungen kopieren / einfügen, sollten Sie diese Bibliothek in einer Codezeile verwenden: stackoverflow.com/a/41970539/9648
JohnnyLambada

Antworten:

346

Wenn jemand das gleiche Problem hat, habe ich es so gemacht

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

Referenz: Datei mit Java verschieben

Rohith Nandakumar
quelle
28
Um Dateien auf die SD-Karte zu schreiben, müssen Sie die Berechtigung für das Manifest erteilen, z. B. <Verwendungsberechtigung android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
IronBlossom
22
Ich würde mich auch nicht darauf verlassen, dass sich die SD-Karte unter / sdcard befindet, sondern den Pfad mit Environment.getExternalStorageDirectory ()
Axarydax
2
Sollte ich verwenden: 16 * 1024 (16kb) Ich tendiere dazu, 16K oder 32K als eine gute Balance zwischen Speichernutzung und Leistung zu wählen.
Nam Vu
3
@rciovati bekam diesen LaufzeitfehlerFailed to copy asset file: myfile.txt java.io.FileNotFoundException: myfile.txt at android.content.res.AssetManager.openAsset(Native Method)
likejudo
7
Für mich funktioniert dieser Code nur, wenn ich in = assetManager.open("images-wall/"+filename);
Folgendes
62

Basierend auf Ihrer Lösung habe ich etwas Eigenes getan, um Unterordner zuzulassen. Jemand könnte dies hilfreich finden:

...

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
quelle
1
assetManager.list(path)kann auf dem Gerät langsam sein, um Assets Pfade Liste im Voraus zu erstellen, kann dieses Snippet aus assetsdir verwendet werden:find . -name "*" -type f -exec ls -l {} \; | awk '{print substr($9,3)}' >> assets.list
alexkasko
3
Schöne Lösung! Die einzige erforderliche Korrektur besteht darin, führende Trennzeichen am Anfang von copyFileOrDir () zu kürzen: path = path.startsWith ("/")? path.substring (1): path;
Cross_
Dieser Stackoverflow ist auf bestimmten Geräten zB: S5
siehe
2
Ersetzen Sie "/ data / data /" + this.getPackageName () durch this.getFilesDir (). getAbsolutePath ()
ibrahimyilmaz
1
... und Streams im finallyBlock schließen))
Mixaz
48

Die obige Lösung hat aufgrund einiger Fehler nicht funktioniert:

  • Die Verzeichniserstellung hat nicht funktioniert
  • Von Android zurückgegebene Assets enthalten außerdem drei Ordner: Bilder, Sounds und Webkit
  • Möglichkeit zum Umgang mit großen Dateien hinzugefügt: Fügen Sie der Datei im Assets-Ordner Ihres Projekts die Erweiterung .mp3 hinzu, und während des Kopierens wird die Zieldatei ohne die Erweiterung .mp3 angezeigt

Hier ist der Code (ich habe die Log-Anweisungen verlassen, aber Sie können sie jetzt löschen):

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: Ein falsches ";" Das warf einen systematischen Fehler "Dir konnte nicht erstellt werden".

Yoram Cohen
quelle
4
das muss die lösung werden!
Massimo Variolo
1
HINWEIS: Log.i ("Tag", "Verzeichnis konnte nicht erstellt werden" + fullPath); passiert immer als; ist auf dem if verlegt.
RoundSparrow Hilltx
super Weg! Vielen Dank! Aber warum überprüfen Sie die JPG-Datei?
Phuong
32

Ich weiß, dass dies beantwortet wurde, aber ich habe eine etwas elegantere Möglichkeit, aus dem Asset-Verzeichnis in eine Datei auf der SD-Karte zu kopieren. Es erfordert keine "for" -Schleife, sondern verwendet stattdessen Dateistreams und Kanäle, um die Arbeit zu erledigen.

(Hinweis) Wenn Sie eine komprimierte Datei, APK, PDF, ... verwenden, möchten Sie möglicherweise die Dateierweiterung vor dem Einfügen in das Asset umbenennen und nach dem Kopieren auf die SD-Karte umbenennen.)

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

Eine Möglichkeit, eine Datei zu kopieren, ohne sie durchlaufen zu müssen.

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
quelle
Gefiel dies gegenüber den anderen Lösungen, etwas ordentlicher. Leichte Änderung an meiner, die das Erstellen fehlender Dateiformate umfasst. Prost!
Chris.Jenkins
3
Dies würde für mich nicht über den Dateideskriptor hinaus funktionieren This file can not be opened as a file descriptor; it is probably compressed- es ist eine PDF-Datei. Wissen Sie, wie Sie das beheben können?
Gaʀʀʏ
1
Dies setzt voraus, dass inChannel.size () die Größe der Dateigröße zurückgibt. Es gibt keine solche Garantie . Ich bekomme 2,5 MiB für 2 Dateien mit jeweils 450 KiB.
AI0867
1
Ich habe gerade festgestellt, dass AssetFileDescriptor.getLength () die richtige Dateigröße zurückgibt.
AI0867
1
Darüber hinaus startet das Asset möglicherweise nicht an Position 0 im Dateideskriptor. AssetFileDescriptor.getStartOffset () gibt den Startoffset zurück.
AI0867
5

Probieren Sie es aus, es ist viel einfacher, dies wird Ihnen helfen:

// 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
quelle
5

Dies wäre in Kotlin prägnant.

    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
quelle
list (assetPath)?. let {...}, tatsächlich. Es ist nullable.
Gábor
4

Hier ist eine bereinigte Version für aktuelle Android-Geräte, funktionales Methodendesign, damit Sie sie in eine AssetsHelper-Klasse kopieren können, zB;)

/**
 * 
 * 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
quelle
4

Diese SO- Antwort wurde von @DannyA geändert

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

}

Vorbereitungen

im src/main/assets Ordner mit Namen hinzufügenfold

Verwendung

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

Suchen Sie im externen Verzeichnis alle Dateien und Verzeichnisse, die sich in den Fold-Assets befinden

Webserveis
quelle
3

Kopieren Sie alle Dateien und Verzeichnisse von Assets in Ihren Ordner!

Zum besseren Kopieren verwenden Sie Apache Commons io

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

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

}

// Dies ist die Hauptmethode für das Kopieren

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
quelle
2

Basierend auf der Antwort von Yoram Cohen ist hier eine Version, die nicht statisches Zielverzeichnis unterstützt.

Rechnung mit copyFileOrDir(getDataDir(), "")zum Schreiben in den internen App-Speicherordner / data / data / pkg_name /

  • Unterstützt Unterordner.
  • Unterstützt benutzerdefinierte und nicht statische Zielverzeichnisse
  • Vermeidet das Kopieren von "Bildern" usw. gefälschten Asset-Ordnern wie

    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
quelle
2

Unter Verwendung einiger Konzepte in den Antworten auf diese Frage habe ich eine Klasse geschrieben, die aufgerufen wurde AssetCopier, um das Kopieren zu /assets/vereinfachen. Es ist auf github verfügbar und kann mit jitpack.io aufgerufen werden :

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

Weitere Informationen finden Sie unter https://github.com/flipagram/android-assetcopier .

Johnny Lambada
quelle
2

Es gibt im Wesentlichen zwei Möglichkeiten, dies zu tun.

Zunächst können Sie AssetManager.open und, wie von Rohith Nandakumar beschrieben, verwenden und über den Eingabestream iterieren.

Zweitens können Sie AssetManager.openFd verwenden , mit dem Sie einen FileChannel (mit dem Befehl [transferTo] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferTo(long ,) verwenden können. long, java.nio.channels.WritableByteChannel)) und [transferFrom] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferFrom(java.nio.channels.ReadableByteChannel , long, long)) Methoden), so dass Sie den Eingabestream nicht selbst durchlaufen müssen.

Ich werde die openFd-Methode hier beschreiben.

Kompression

Zuerst müssen Sie sicherstellen, dass die Datei unkomprimiert gespeichert wird. Das Verpackungssystem kann sich dafür entscheiden, Dateien mit einer Erweiterung zu komprimieren, die nicht als noCompress gekennzeichnet ist , und komprimierte Dateien können nicht dem Speicher zugeordnet werden. In diesem Fall müssen Sie sich daher auf AssetManager.open verlassen .

Sie können Ihrer Datei die Erweiterung '.mp3' hinzufügen, um zu verhindern, dass sie komprimiert wird. Die richtige Lösung besteht jedoch darin, die Datei app / build.gradle zu ändern und die folgenden Zeilen hinzuzufügen (um die Komprimierung von PDF-Dateien zu deaktivieren).

aaptOptions {
    noCompress 'pdf'
}

Datei packen

Beachten Sie, dass der Packager immer noch mehrere Dateien in eine packen kann, sodass Sie nicht einfach die gesamte Datei lesen können, die Ihnen der AssetManager zur Verfügung stellt. Sie müssen den AssetFileDescriptor fragen, welche Teile Sie benötigen.

Den richtigen Teil der gepackten Datei finden

Sobald Sie sichergestellt haben, dass Ihre Datei unkomprimiert gespeichert ist, können Sie mit der AssetManager.openFd- Methode einen AssetFileDescriptor abrufen , mit dem Sie einen FileInputStream abrufen können (im Gegensatz zu AssetManager.open , der einen InputStream zurückgibt ), der einen FileChannel enthält . Es enthält auch den Startoffset (getStartOffset) und die Größe (getLength) , die Sie benötigen, um den richtigen Teil der Datei zu erhalten.

Implementierung

Eine beispielhafte Implementierung ist unten angegeben:

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

Diese Antwort basiert auf der Antwort von JPM .

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

Ändern Sie Teile des Codes wie folgt:

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

Das vorige Beispiel ist für Pdfs, im Fall von Beispiel .txt

FileOutputStream fos = new FileOutputStream(file);
Alex Zaraos
quelle
1

Verwenden Sie AssetManager , um die Dateien in den Assets zu lesen. Verwenden Sie dann reguläres Java IO, um die Dateien auf die SD-Karte zu schreiben.

Google ist dein Freund, suche nach einem Beispiel.

Drakosha
quelle
1

Hallo Leute, ich habe so etwas gemacht. Für N-ten Tiefenkopierordner und zu kopierende Dateien. Damit können Sie die gesamte Verzeichnisstruktur kopieren, um sie von Android AssetManager zu kopieren :)

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

Am Ende Erstellen Sie eine Asynctask:

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

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

    }

Nennen Sie es Von Ihrer Aktivität:

    new ManageAssetFolders().execute();
DropAndTrap
quelle
1

Leichte Änderung der obigen Antwort, um einen Ordner rekursiv zu kopieren und ein benutzerdefiniertes Ziel zu berücksichtigen.

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
quelle
1

Basierend auf der Lösung von Rohith Nandakumar habe ich selbst etwas unternommen, um Dateien aus einem Unterordner von Assets (dh "Assets / MyFolder ") zu kopieren . Außerdem überprüfe ich, ob die Datei bereits auf der SD-Karte vorhanden ist, bevor ich erneut versuche, sie zu kopieren.

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
quelle
0

Dies ist bei weitem die beste Lösung, die ich im Internet finden konnte. Ich habe den folgenden Link verwendet: https://gist.github.com/mhasby/026f02b33fcc4207b302a60645f6e217 ,
aber es gab einen einzelnen Fehler, den ich behoben habe, und dann funktioniert es wie ein Zauber. Hier ist mein Code. Sie können es leicht verwenden, da es sich um eine unabhängige Java-Klasse handelt.

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

Wie Sie sehen können, erstellen Sie einfach eine Instanz von CopyAssetsin Ihrer Java-Klasse, die eine Aktivität hat. Nun ist dieser Teil wichtig für meine Tests und Recherchen im Internet You cannot use AssetManager if the class has no activity. Es hat etwas mit dem Kontext der Java-Klasse zu tun.
Dies c.copyAssets(getApplicationContext())ist eine einfache Möglichkeit, auf die Methode zuzugreifen, wo csich eine Instanz der CopyAssetsKlasse befindet. Gemäß meiner Anforderung erlaubte ich dem Programm, alle meine Ressourcendateien im assetOrdner in das /www/resources/Verzeichnis meines internen Verzeichnisses zu kopieren .
Sie können leicht herausfinden, wo Sie gemäß Ihrer Verwendung Änderungen am Verzeichnis vornehmen müssen. Sie können mich gerne anrufen, wenn Sie Hilfe benötigen.

Shan Singh
quelle
0

Für diejenigen, die auf Kotlin aktualisieren:

Befolgen Sie diese Schritte, um zu vermeiden FileUriExposedExceptions, dass der Benutzer die Berechtigung WRITE_EXTERNAL_STORAGEerteilt hat und sich Ihre Datei in befindet 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"
}
Óscar
quelle