programing

'자산' 폴더에서 sdcard로 파일을 복사하는 방법은 무엇입니까?

goodsources 2023. 8. 4. 23:02
반응형

'자산' 폴더에서 sdcard로 파일을 복사하는 방법은 무엇입니까?

는 나몇개파있다습에 몇 .assets폴더를 누릅니다.저는 그것들을 모두 /sdcard/folder라고 하는 폴더에 복사해야 합니다.저는 이것을 실 안에서 하고 싶습니다.제가 그걸 어떻게 합니까?

다른 사람들도 같은 문제를 겪고 있다면, 저는 이렇게 했습니다.

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를 사용하여 파일 이동

귀하의 솔루션에 따라 하위 폴더를 허용하기 위해 제 나름의 작업을 수행했습니다.누군가는 이것이 유용하다고 생각할 수 있습니다.

...

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

}

위의 솔루션은 몇 가지 오류로 인해 작동하지 않았습니다.

  • 디렉터리 생성이 작동하지 않았습니다.
  • Android에서 반환한 자산에는 이미지, 사운드 및 웹킷이라는 세 개의 폴더도 포함됩니다.
  • 대용량 파일 처리 방법 추가:프로젝트의 자산 폴더에 있는 파일에 확장자 .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());
    }

}

편집: 체계적인 "could create dir" 오류를 발생시키는 잘못 배치된 ";"를 수정했습니다.

답변이 완료된 것은 알지만 자산 디렉토리에서 sdcard의 파일로 복사하는 좀 더 우아한 방법이 있습니다."for" 루프가 필요하지 않고 대신 파일 스트림과 채널을 사용하여 작업을 수행합니다.

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

이것은 코틀린에서 간결한 방법일 것입니다.

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

이것을 사용해 보세요. 훨씬 더 간단합니다. 이것은 당신에게 도움이 될 것입니다.

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

다음은 현재 Android 장치에 대한 정리된 버전으로, 자산에 복사할 수 있는 기능적인 방법 설계입니다.도우미 클래스(예: )

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

@DannyA가 이 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/main/assets이 이이있폴인 fold

사용.

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

외부 디렉토리로 이동하여 폴더 자산 내에 있는 모든 파일 및 디렉토리를 찾습니다.

하여, 저는 이질에대답있에개중사일여용하저, 같작다니성습했수업을은라는 을 했습니다.AssetCopier/assets/간단하죠.github에서 사용할 수 있으며 jitpack으로 접근할 수 있습니다.io:

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

자세한 내용은 https://github.com/flipagram/android-assetcopier 을 참조하십시오.

자산의 모든 파일과 디렉터리를 폴더에 복사합니다!

더 나은 복사를 위해 아파치 커먼시오를 사용합니다.

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

Rohith Nandakumar의 솔루션을 기반으로 자산의 하위 폴더(예: "자산/ 폴더")에서 파일을 복사했습니다.또한 다시 복사하기 전에 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);
    }
}

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

Yoram Cohen 답변을 기반으로 정적인 대상 디렉터리를 지원하는 버전이 있습니다.

송장리로 송장 :copyFileOrDir(getDataDir(), "")내부 앱 저장소 폴더에 쓰기 /data/data/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());
    }
    
    }
    

기본적으로 두 가지 방법이 있습니다.

먼저 AssetManager.open을 사용하고 Rohith Nandakumar에서 설명한 대로 입력 스트림을 통해 반복할 수 있습니다.

둘째, AssetManager.openFd를 사용하면 파일 채널(transferTotransferFrom 메서드 포함)을 사용할 수 있으므로 직접 입력 스트림을 루프할 필요가 없습니다.

여기서 openFd 방법에 대해 설명하겠습니다.

압축

먼저 파일을 압축하지 않고 저장해야 합니다.패키지 시스템은 noCompress로 표시되지 않은 확장자의 파일을 압축할 수 있으며 압축된 파일은 메모리 매핑이 불가능하므로 AssetManager.open을 사용해야 합니다.

압축되지 않도록 파일에 '.mp3' 확장자를 추가할 수 있지만, 적절한 해결책은 app/build.gradle 파일을 수정하고 다음 행을 추가하는 것입니다(PDF 파일 압축 사용 안 함).

aaptOptions {
    noCompress 'pdf'
}

파일 패킹

패키지 관리자는 여러 개의 파일을 하나로 포장할 수 있으므로 자산 관리자가 제공하는 전체 파일을 읽기만 하면 안 됩니다.자산 파일 설명자에게 필요한 부품을 문의해야 합니다.

포장된 파일의 올바른 부분 찾기

파일을 압축하지 않고 저장했으면 AssetManager.openFd 메서드를 사용하여 파일 채널이 포함된 FileInputStream(InputStream을 반환하는 AssetManager.open과 달리)을 가져오는 데 사용할 수 있는 AssetFileDescriptor를 가져올 수 있습니다.또한 파일의 올바른 부분을 얻기 위해 필요한 시작 오프셋(getStartOffset)과 크기(getLength)도 포함되어 있습니다.

실행

구현의 예는 다음과 같습니다.

private void copyFileFromAssets(String in_filename, File out_file){
    Log.d("copyFileFromAssets", "Copying file '"+in_filename+"' to '"+out_file.toString()+"'");
    AssetManager assetManager = getApplicationContext().getAssets();
    FileChannel in_chan = null, out_chan = null;
    try {
        AssetFileDescriptor in_afd = assetManager.openFd(in_filename);
        FileInputStream in_stream = in_afd.createInputStream();
        in_chan = in_stream.getChannel();
        Log.d("copyFileFromAssets", "Asset space in file: start = "+in_afd.getStartOffset()+", length = "+in_afd.getLength());
        FileOutputStream out_stream = new FileOutputStream(out_file);
        out_chan = out_stream.getChannel();
        in_chan.transferTo(in_afd.getStartOffset(), in_afd.getLength(), out_chan);
    } catch (IOException ioe){
        Log.w("copyFileFromAssets", "Failed to copy file '"+in_filename+"' to external storage:"+ioe.toString());
    } finally {
        try {
            if (in_chan != null) {
                in_chan.close();
            }
            if (out_chan != null) {
                out_chan.close();
            }
        } catch (IOException ioe){}
    }
}

JPM의 답변을 바탕으로 한 답변입니다.

import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Environment;
import android.os.Bundle;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        copyReadAssets();
    }


    private void copyReadAssets()
    {
        AssetManager assetManager = getAssets();

        InputStream in = null;
        OutputStream out = null;

        String strDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+ File.separator + "Pdfs";
        File fileDir = new File(strDir);
        fileDir.mkdirs();   // crear la ruta si no existe
        File file = new File(fileDir, "example2.pdf");



        try
        {

            in = assetManager.open("example.pdf");  //leer el archivo de assets
            out = new BufferedOutputStream(new FileOutputStream(file)); //crear el archivo


            copyFile(in, out);
            in.close();
            in = null;
            out.flush();
            out.close();
            out = null;
        } catch (Exception e)
        {
            Log.e("tag", e.getMessage());
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.parse("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "Pdfs" + "/example2.pdf"), "application/pdf");
        startActivity(intent);
    }

    private void copyFile(InputStream in, OutputStream out) throws IOException
    {
        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1)
        {
            out.write(buffer, 0, read);
        }
    }
}

다음과 같은 코드 부분을 변경합니다.

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

앞의 예는 Pdfs용입니다(예: .txt).

FileOutputStream fos = new FileOutputStream(file);

안녕 얘들아 나는 이런 것을 했습니다.복사할 N번째 깊이 복사 폴더 및 파일입니다.Android Asset Manager에서 복사할 모든 디렉토리 구조를 복사할 수 있습니다 :)

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

폴더를 재귀적으로 복사하고 사용자 지정 대상을 수용하기 위해 위 답변을 약간 수정했습니다.

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

Kotlin으로 업데이트하는 사용자:

다음 단계를 수행하여 방지FileUriExposedExceptions사용자가 승인한 경우WRITE_EXTERNAL_STORAGE권한 및 파일이 있는 경우assets/pdfs/mypdf.pdf.

private fun openFile() {
    var inputStream: InputStream? = null
    var outputStream: OutputStream? = null
    try {
        val file = File("${activity.getExternalFilesDir(null)}/$PDF_FILE_NAME")
        if (!file.exists()) {
            inputStream = activity.assets.open("$PDF_ASSETS_PATH/$PDF_FILE_NAME")
            outputStream = FileOutputStream(file)
            copyFile(inputStream, outputStream)
        }

        val uri = FileProvider.getUriForFile(
            activity,
            "${BuildConfig.APPLICATION_ID}.provider.GenericFileProvider",
            file
        )
        val intent = Intent(Intent.ACTION_VIEW).apply {
            setDataAndType(uri, "application/pdf")
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
        }
        activity.startActivity(intent)
    } catch (ex: IOException) {
        ex.printStackTrace()
    } catch (ex: ActivityNotFoundException) {
        ex.printStackTrace()
    } finally {
        inputStream?.close()
        outputStream?.flush()
        outputStream?.close()
    }
}

@Throws(IOException::class)
private fun copyFile(input: InputStream, output: OutputStream) {
    val buffer = ByteArray(1024)
    var read: Int = input.read(buffer)
    while (read != -1) {
        output.write(buffer, 0, read)
        read = input.read(buffer)
    }
}

companion object {
    private const val PDF_ASSETS_PATH = "pdfs"
    private const val PDF_FILE_NAME = "mypdf.pdf"
}

그것은 저의 개인 맞춤형 텍스트 추출기 수업입니다, 유용하기를 바랍니다.

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

이를 사용하려면 훈련된 데이터 파일이 필요합니다. 링크에서 traindata 파일을 다운로드할 수 있습니다.

원하는 훈련된 데이터 파일을 다운로드한 후에는 Android 프로젝트에 자산이라는 Android Resource 디렉토리를 만들어야 합니다.새로 생성된 자산 폴더에서 훈련된 데이터 파일을 저장할 수 있는 "tessdata"라는 이름의 일반 디렉터리를 만들어야 합니다.마지막으로 기본 활동에서 "텍스트 추출기" 클래스를 시작해야 합니다.

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

첫 번째 매개 변수는 컨텍스트이고, 두 번째 매개 변수는 방금 만든 디렉터리 이름이며, 마지막 매개 변수는 방금 다운로드한 훈련된 데이터의 언어입니다.

텍스트를 추출하려면 "extractText" 메서드를 호출해야 합니다.

final String text = textExtractor.extractText(imageWithText);

추출물을 참고하십시오.텍스트가 작동하려면 비트맵 이미지가 필요합니다!!다음 선을 사용하여 그릴 수 있는 파일에서 비트맵 이미지를 만들 수 있습니다.

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

더 많은 지원이 필요한 경우 다음 유용한 가이드를 따르십시오. https://github.com/SamVanRoy/Android_OCR_App

코틀린에서는 한 줄로 할 수 있습니다!

InputStream에 확장 기능 추가

fun InputStream.toFile(to: File){
    this.use { input->
        to.outputStream().use { out->
            input.copyTo(out)
        }
    }
}

그럼 쓰세요.

기본 활동.kt

assets.open("test.zip").toFile(File(filesDir,"test.zip"))

이것이 제가 인터넷에서 찾을 수 있는 가장 좋은 해결책입니다.다음 링크를 사용했습니다. https://gist.github.com/mhasby/026f02b33fcc4207b302a60645f6e217,
하지만 제가 수정한 단 하나의 오류가 있었고 그것은 매력적으로 작동합니다.여기 제 코드가 있습니다.독립된 자바 클래스이기 때문에 쉽게 사용할 수 있습니다.

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

처럼, ▁of▁instance▁create▁an다만의 인스턴스를 만들어 보세요.CopyAssets활동이 있는 당신의 자바 클래스에서. 이 제 중요한 부분입니다. 제가 인터넷에서 테스트하고 연구하는 한,You cannot use AssetManager if the class has no activity자바 클래스의 컨텍스트와 관련이 있습니다.
이, 제.c.copyAssets(getApplicationContext())메소드에 액세스할 수 입니다.c의 및 CopyAssetsclass.요구사항에 , 저는 이 제 을 복사할 수 하였습니다.asset에서 에대폴로 이동/www/resources/내 내부 디렉토리에 있습니다.
사용자가 사용하는 대로 디렉토리를 변경해야 하는 부분을 쉽게 찾을 수 있습니다.도움이 필요하면 언제든지 전화하세요.

또를 Guava의 용할수있습다니사한을 할 수 .ByteStream자산 폴더에서 SD 카드로 파일을 복사합니다.이것이 바로 자산 폴더에서 SD 카드로 파일을 재귀적으로 복사하는 솔루션입니다.

/**
 * Copies all assets in an assets directory to the SD file system.
 */
public class CopyAssetsToSDHelper {

    public static void copyAssets(String assetDir, String targetDir, Context context) 
        throws IOException {
        AssetManager assets = context.getAssets();
        String[] list = assets.list(assetDir);
        for (String f : Objects.requireNonNull(list)) {
            if (f.indexOf(".") > 1) { // check, if this is a file
                File outFile = new File(context.getExternalFilesDir(null), 
                    String.format("%s/%s", targetDir, f));
                File parentFile = outFile.getParentFile();
                if (!Objects.requireNonNull(parentFile).exists()) {
                    if (!parentFile.mkdirs()) {
                        throw new IOException(String.format("Could not create directory %s.", 
                            parentFile));
                    }
                }
                try (InputStream fin = assets.open(String.format("%s/%s", assetDir, f));
                     OutputStream fout = new FileOutputStream(outFile)) {
                    ByteStreams.copy(fin, fout);
                }
            } else { // This is a directory
                copyAssets(String.format("%s/%s", assetDir, f), String.format("%s/%s", targetDir, f), 
                    context);
            }
        }
    }

}

자산 관리자를 사용하면 자산의 파일을 읽을 수 있습니다.그런 다음 일반 Java IO를 사용하여 sdcard에 파일을 씁니다.

구글은 당신의 친구입니다. 예를 들어보세요.

언급URL : https://stackoverflow.com/questions/4447477/how-to-copy-files-from-assets-folder-to-sdcard

반응형