我在资产文件夹里有几个文件。我需要把它们都复制到一个文件夹,比如/sdcard/folder。我想从一个线程中做这件事。我该怎么做?


当前回答

由于一些错误,上述解决方案无法工作:

目录创建失败 Android返回的资产也包含三个文件夹:图像,声音和webkit 增加了处理大文件的方法:在项目的资产文件夹中添加扩展名.mp3到文件,在复制目标文件时将没有.mp3扩展名

下面是代码(我留下了Log语句,但你现在可以删除它们):

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

}

编辑:更正了一个错位的“;”,这是抛出一个系统的“无法创建目录”错误。

其他回答

你可以用Kotlin在几个步骤中做到这一点,在这里我只复制几个文件,而不是所有从资产到我的应用程序文件目录。

private fun copyRelatedAssets() {
    val assets = arrayOf("myhome.html", "support.css", "myscript.js", "style.css")
    assets.forEach {
        val inputStream = requireContext().assets.open(it)
        val nameSplit = it.split(".")
        val name = nameSplit[0]
        val extension = nameSplit[1]
        val path = inputStream.getFilePath(requireContext().filesDir, name, extension)
        Log.v(TAG, path)
    }
}

这是扩展函数,

fun InputStream.getFilePath(dir: File, name: String, extension: String): String {
    val file = File(dir, "$name.$extension")
    val outputStream = FileOutputStream(file)
    this.copyTo(outputStream, 4096)
    return file.absolutePath
}

洛格猫

/data/user/0/com.***.***/files/myhome.html
/data/user/0/com.***.***/files/support.css
/data/user/0/com.***.***/files/myscript.js
/data/user/0/com.***.***/files/style.css

修改了@ danya的SO回答

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 /主/资产 添加名称折叠文件夹

使用

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

在外部目录中找到折叠资产内的所有文件和目录

这就是我的个性化文本提取类,希望对大家有用。

package lorenzo.morelli.platedetector;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;

import com.googlecode.tesseract.android.TessBaseAPI;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class TextExtractor {

    private final Context context;
    private final String dirName;
    private final String language;

    public TextExtractor(final Context context, final String dirName, final String language) {
        this.context = context;
        this.dirName = dirName;
        this.language = language;
    }

    public String extractText(final Bitmap bitmap) {
        final TessBaseAPI tessBaseApi = new TessBaseAPI();
        final String datapath = this.context.getFilesDir()+ "/tesseract/";
        checkFile(new File(datapath + this.dirName + "/"), datapath, this.dirName, this.language);

        tessBaseApi.init(datapath, this.language);
        tessBaseApi.setImage(bitmap);
        final String extractedText = tessBaseApi.getUTF8Text();
        tessBaseApi.end();
        return extractedText;
    }

    private void checkFile(final File dir, final String datapath, final String dirName, final String language) {
        //directory does not exist, but we can successfully create it
        if (!dir.exists()&& dir.mkdirs()) {
            copyFiles(datapath, dirName, language);
        } //The directory exists, but there is no data file in it
        if(dir.exists()) {
            final String datafilepath = datapath + "/" + dirName + "/" + language + ".traineddata";
            final File datafile = new File(datafilepath);
            if (!datafile.exists()) {
                copyFiles(datapath, dirName, language);
            }
        }
    }

    private void copyFiles(final String datapath, final String dirName, final String language) {
        try {
            //location we want the file to be at
            final String filepath = datapath + "/" + dirName + "/" + language + ".traineddata";

            //get access to AssetManager
            final AssetManager assetManager = this.context.getAssets();

            //open byte streams for reading/writing
            final InputStream instream = assetManager.open(dirName + "/" + language + ".traineddata");
            final OutputStream outstream = new FileOutputStream(filepath);

            //copy the file to the location specified by filepath
            byte[] buffer = new byte[1024];
            int read;
            while ((read = instream.read(buffer)) != -1) {
                outstream.write(buffer, 0, read);
            }
            outstream.flush();
            outstream.close();
            instream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

要使用它,你需要训练过的数据文件。你可以从这个链接下载trainddata文件。

一旦你下载了你想要的traineddata文件,你需要在你的Android项目中创建一个名为assets的Android资源目录。在新创建的资产文件夹中,你需要创建一个名为“tessdata”的常规目录,在那里你可以放置你的训练数据文件。 最后你必须初始化MainActivity中的“TextExtractor”类。

final TextExtractor textExtractor = new TextExtractor(this, "tessdata", "eng");

第一个参数是上下文,第二个参数是刚刚创建的目录名,最后一个参数是刚刚下载的训练数据的语言。

要提取文本,你必须调用"extractText"方法:

final String text = textExtractor.extractText(imageWithText);

注意,extractText需要一个位图图像才能工作!! 你可以用这一行从你的可绘制文件中创建一个BitMap图像:

final BitMap image = BitmapFactory.decodeResource(getResources(), R.drawable.test_image);

如果你需要更多的支持,我建议你遵循这个有用的指南:https://github.com/SamVanRoy/Android_OCR_App

复制所有文件和目录从资产到您的文件夹!

为了更好地复制,使用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);
    }
}

这里是一个针对当前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();
}