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


251

assets폴더에 파일이 몇 개 있습니다 . / sdcard / folder 폴더에 모든 파일을 복사해야합니다. 스레드 내 에서이 작업을 수행하고 싶습니다. 어떻게합니까?



2
(! 좋은) 파일을 복사하기 전에 / 한 줄의 코드에서 그것을 할이 라이브러리를 사용하는 것이 좋습니다 아래의 해결 방법 중 하나를 붙여 넣습니다 stackoverflow.com/a/41970539/9648
JohnnyLambada

답변:


346

다른 사람이 같은 문제를 겪고 있다면 이것이 내가 한 일입니다.

private void copyAssets() {
    AssetManager assetManager = getAssets();
    String[] files = null;
    try {
        files = assetManager.list("");
    } catch (IOException e) {
        Log.e("tag", "Failed to get asset file list.", e);
    }
    if (files != null) for (String filename : files) {
        InputStream in = null;
        OutputStream out = null;
        try {
          in = assetManager.open(filename);
          File outFile = new File(getExternalFilesDir(null), filename);
          out = new FileOutputStream(outFile);
          copyFile(in, out);
        } catch(IOException e) {
            Log.e("tag", "Failed to copy asset file: " + filename, e);
        }     
        finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    // NOOP
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    // NOOP
                }
            }
        }  
    }
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int read;
    while((read = in.read(buffer)) != -1){
      out.write(buffer, 0, read);
    }
}

참조 : Java를 사용하여 파일 이동


28
sdcard에 파일을 쓰려면 <uses-permission android : name = "android.permission.WRITE_EXTERNAL_STORAGE"/>
IronBlossom

22
나는 또한에 / sdcard에 위치하는 SDCARD에 의존하지만, Environment.getExternalStorageDirectory ()와 경로를 검색 할 것
Axarydax

2
16 * 1024 (16kb)를 사용해야합니까? 16K 또는 32K를 메모리 사용과 성능 사이의 균형으로 선택하는 경향이 있습니다.
Nam Vu

3
@rciovati이 런타임 오류가 발생했습니다Failed to copy asset file: myfile.txt java.io.FileNotFoundException: myfile.txt at android.content.res.AssetManager.openAsset(Native Method)
likejudo

7
나를 위해이 코드는 다음을 추가하는 경우에만 작동합니다. in = assetManager.open("images-wall/"+filename);여기서 "images-wall"은 자산 내의 폴더입니다.
Ultimo_m

62

귀하의 솔루션을 바탕으로 하위 폴더를 허용하기 위해 내 자신의 일을했습니다. 누군가 이것이 도움이 될 수 있습니다.

...

copyFileOrDir("myrootdir");

...

private void copyFileOrDir(String path) {
    AssetManager assetManager = this.getAssets();
    String assets[] = null;
    try {
        assets = assetManager.list(path);
        if (assets.length == 0) {
            copyFile(path);
        } else {
            String fullPath = "/data/data/" + this.getPackageName() + "/" + path;
            File dir = new File(fullPath);
            if (!dir.exists())
                dir.mkdir();
            for (int i = 0; i < assets.length; ++i) {
                copyFileOrDir(path + "/" + assets[i]);
            }
        }
    } catch (IOException ex) {
        Log.e("tag", "I/O Exception", ex);
    }
}

private void copyFile(String filename) {
    AssetManager assetManager = this.getAssets();

    InputStream in = null;
    OutputStream out = null;
    try {
        in = assetManager.open(filename);
        String newFileName = "/data/data/" + this.getPackageName() + "/" + filename;
        out = new FileOutputStream(newFileName);

        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
    } catch (Exception e) {
        Log.e("tag", e.getMessage());
    }

}

1
assetManager.list(path)이 스 니펫은 assetsdir 에서 사용될 수 있습니다 .find . -name "*" -type f -exec ls -l {} \; | awk '{print substr($9,3)}' >> assets.list
alexkasko

3
좋은 해결책! 필요한 유일한 수정은 copyFileOrDir ()의 시작 부분에서 선행 구분 기호를 잘라내는 것입니다. path = path.startsWith ( "/")? path.substring (1) : 경로;
Cross_


2
대신 "/ 데이터 / 데이터 /"+ this.getFilesDir ()와 this.getPackageName () getAbsolutePath ().
ibrahimyilmaz

1
... 및 finally블록 에서 스트림을 닫습니다 ))
Mixaz

48

일부 오류로 인해 위의 솔루션이 작동하지 않았습니다.

  • 디렉토리 생성이 작동하지 않았습니다
  • 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());
    }

}

편집 : 잘못 배치 된 ";"수정 그것은 체계적인 "dir을 만들 수 없습니다"오류를 던졌습니다.


4
이것이 해결책이되어야합니다!
Massimo Variolo

1
참고 : Log.i ( "tag", "dir"+ fullPath를 만들 수 없습니다 "; 항상 다음과 같이 발생합니다. if에 잘못 배치되었습니다.
RoundSparrow hilltx

굉장한 방법! 너무 감사합니다! 그러나 왜 jpg 파일을 확인합니까?
Phuong

32

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

(주) 압축 파일, APK, PDF 등을 사용하는 경우 자산에 삽입하기 전에 파일 확장자의 이름을 바꾸고 SD 카드에 복사 한 후에 이름을 바꿀 수 있습니다.

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

다른 솔루션보다 조금 더 깔끔했습니다. 누락 된 fileFolders 작성을 포함하여 광산에서 약간 수정되었습니다. 건배!
Chris.Jenkins

3
이것은 나를 위해 파일 디스크립터를 지나서 작동하지 않을 This file can not be opened as a file descriptor; it is probably compressed것입니다 .pdf 파일입니다. 그 문제를 해결하는 방법을 알고 있습니까?
Gaʀʀʏ

1
이것은 inChannel.size ()가 파일 크기의 크기를 리턴한다고 가정합니다. 그런 보장없습니다 . 각각 450 KiB 인 2 개의 파일에 대해 2.5MiB가 표시됩니다.
AI0867

1
방금 AssetFileDescriptor.getLength ()가 올바른 파일 크기를 반환한다는 것을 알았습니다.
AI0867

1
위의 내용 외에도 파일 디스크립터의 위치 0에서 자산이 시작되지 않을 수 있습니다. AssetFileDescriptor.getStartOffset ()은 시작 오프셋을 반환합니다.
AI0867

5

이것을 훨씬 더 간단하게 시도하십시오. 이것은 u를 도울 것입니다.

// Open your local db as the input stream
    InputStream myInput = _context.getAssets().open(YOUR FILE NAME);

    // Path to the just created empty db
    String outFileName =SDCARD PATH + YOUR FILE NAME;

    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    // transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }
    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();

5

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

    fun AssetManager.copyRecursively(assetPath: String, targetFile: File) {
        val list = list(assetPath)
        if (list.isEmpty()) { // assetPath is file
            open(assetPath).use { input ->
                FileOutputStream(targetFile.absolutePath).use { output ->
                    input.copyTo(output)
                    output.flush()
                }
            }

        } else { // assetPath is folder
            targetFile.delete()
            targetFile.mkdir()

            list.forEach {
                copyRecursively("$assetPath/$it", File(targetFile, it))
            }
        }
    }

list (assetPath) ?. let {...}, 실제로. Nullable입니다.
Gábor

4

다음은 현재 Android 기기를위한 정리 된 버전입니다. 기능적 메소드 디자인으로 AssetsHelper 클래스에 복사 할 수 있습니다 (예 :;)

/**
 * 
 * Info: prior to Android 2.3, any compressed asset file with an
 * uncompressed size of over 1 MB cannot be read from the APK. So this
 * should only be used if the device has android 2.3 or later running!
 * 
 * @param c
 * @param targetFolder
 *            e.g. {@link Environment#getExternalStorageDirectory()}
 * @throws Exception
 */
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public static boolean copyAssets(AssetManager assetManager,
        File targetFolder) throws Exception {
    Log.i(LOG_TAG, "Copying files from assets to folder " + targetFolder);
    return copyAssets(assetManager, "", targetFolder);
}

/**
 * The files will be copied at the location targetFolder+path so if you
 * enter path="abc" and targetfolder="sdcard" the files will be located in
 * "sdcard/abc"
 * 
 * @param assetManager
 * @param path
 * @param targetFolder
 * @return
 * @throws Exception
 */
public static boolean copyAssets(AssetManager assetManager, String path,
        File targetFolder) throws Exception {
    Log.i(LOG_TAG, "Copying " + path + " to " + targetFolder);
    String sources[] = assetManager.list(path);
    if (sources.length == 0) { // its not a folder, so its a file:
        copyAssetFileToFolder(assetManager, path, targetFolder);
    } else { // its a folder:
        if (path.startsWith("images") || path.startsWith("sounds")
                || path.startsWith("webkit")) {
            Log.i(LOG_TAG, "  > Skipping " + path);
            return false;
        }
        File targetDir = new File(targetFolder, path);
        targetDir.mkdirs();
        for (String source : sources) {
            String fullSourcePath = path.equals("") ? source : (path
                    + File.separator + source);
            copyAssets(assetManager, fullSourcePath, targetFolder);
        }
    }
    return true;
}

private static void copyAssetFileToFolder(AssetManager assetManager,
        String fullAssetPath, File targetBasePath) throws IOException {
    InputStream in = assetManager.open(fullAssetPath);
    OutputStream out = new FileOutputStream(new File(targetBasePath,
            fullAssetPath));
    byte[] buffer = new byte[16 * 1024];
    int read;
    while ((read = in.read(buffer)) != -1) {
        out.write(buffer, 0, read);
    }
    in.close();
    out.flush();
    out.close();
}

4

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

외부 디렉토리에서 폴더 자산 내에있는 모든 파일 및 디렉토리를 찾으십시오.


3

에셋의 모든 파일과 디렉토리를 폴더로 복사하십시오!

더 나은 사용을 위해 아파치 커먼즈 io

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

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

}

// 이것은 복사의 주요 방법입니다

private void doCopy(String dirName, String outPath) throws IOException {

    String[] srcFiles = assets.list(dirName);//for directory
    for (String srcFileName : srcFiles) {
        String outFileName = outPath + File.separator + srcFileName;
        String inFileName = dirName + File.separator + srcFileName;
        if (dirName.equals("")) {// for first time
            inFileName = srcFileName;
        }
        try {
            InputStream inputStream = assets.open(inFileName);
            copyAndClose(inputStream, new FileOutputStream(outFileName));
        } catch (IOException e) {//if directory fails exception
            new File(outFileName).mkdir();
            doCopy(inFileName, outFileName);
        }

    }
}

public static void closeQuietly(AutoCloseable autoCloseable) {
    try {
        if(autoCloseable != null) {
            autoCloseable.close();
        }
    } catch(IOException ioe) {
        //skip
    }
}

public static void copyAndClose(InputStream input, OutputStream output) throws IOException {
    copy(input, output);
    closeQuietly(input);
    closeQuietly(output);
}

public static void copy(InputStream input, OutputStream output) throws IOException {
    byte[] buffer = new byte[1024];
    int n = 0;
    while(-1 != (n = input.read(buffer))) {
        output.write(buffer, 0, n);
    }
}

2

Yoram Cohen의 답변을 바탕으로 정적이 아닌 대상 디렉토리를 지원하는 버전이 있습니다.

내부 앱 스토리지 폴더 / data / data / pkg_name / copyFileOrDir(getDataDir(), "")에 쓰기로 호출

  • 하위 폴더를 지원합니다.
  • 사용자 정의 및 비 정적 대상 디렉토리 지원
  • "이미지"등의 가짜 자산 폴더 복사 방지

    private void copyFileOrDir(String TARGET_BASE_PATH, String path) {
    AssetManager assetManager = this.getAssets();
    String assets[] = null;
    try {
        Log.i("tag", "copyFileOrDir() "+path);
        assets = assetManager.list(path);
        if (assets.length == 0) {
            copyFile(TARGET_BASE_PATH, path);
        } else {
            String fullPath =  TARGET_BASE_PATH + "/" + path;
            Log.i("tag", "path="+fullPath);
            File dir = new File(fullPath);
            if (!dir.exists() && !path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit"))
                if (!dir.mkdirs())
                    Log.i("tag", "could not create dir "+fullPath);
            for (int i = 0; i < assets.length; ++i) {
                String p;
                if (path.equals(""))
                    p = "";
                else 
                    p = path + "/";
    
                if (!path.startsWith("images") && !path.startsWith("sounds") && !path.startsWith("webkit"))
                    copyFileOrDir(TARGET_BASE_PATH, p + assets[i]);
            }
        }
    } catch (IOException ex) {
        Log.e("tag", "I/O Exception", ex);
    }
    }
    
    private void copyFile(String TARGET_BASE_PATH, String filename) {
    AssetManager assetManager = this.getAssets();
    
    InputStream in = null;
    OutputStream out = null;
    String newFileName = null;
    try {
        Log.i("tag", "copyFile() "+filename);
        in = assetManager.open(filename);
        if (filename.endsWith(".jpg")) // extension was added to avoid compression on APK file
            newFileName = TARGET_BASE_PATH + "/" + filename.substring(0, filename.length()-4);
        else
            newFileName = TARGET_BASE_PATH + "/" + filename;
        out = new FileOutputStream(newFileName);
    
        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
    } catch (Exception e) {
        Log.e("tag", "Exception in copyFile() of "+newFileName);
        Log.e("tag", "Exception in copyFile() "+e.toString());
    }
    
    }

2

이 질문에 대한 답변의 개념 중 일부를 사용하여 AssetCopier복사를 /assets/간단하게 하기 위해 클래스를 작성했습니다 . github 에서 사용할 수 있으며 jitpack.io 로 액세스 할 수 있습니다 :

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

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


2

이를 수행하는 데는 본질적으로 두 가지 방법이 있습니다.

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

둘째, AssetManager.openFd 를 사용하면 FileChannel ([transferTo] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferTo(long , long, java.nio.channels.WritableByteChannel)) 및 [transferFrom] ( https://developer.android.com/reference/java/nio/channels/FileChannel.html#transferFrom(java.nio.channels.ReadableByteChannel , long, long)) 메소드)를 사용하므로 입력 스트림을 직접 반복 할 필요가 없습니다.

여기서는 openFd 메소드에 대해 설명하겠습니다.

압축

먼저 파일이 압축되지 않은 상태로 저장되어 있는지 확인해야합니다. 패키징 시스템은 noCompress 로 표시되지 않은 확장자를 가진 파일을 압축하도록 선택할 수 있으며 압축 된 파일은 메모리 맵핑 될 수 없으므로 AssetManager.open 에 의존해야합니다. 경우 .

파일에 '.mp3'확장자를 추가하여 파일 압축을 중지 할 수 있지만 적절한 해결책은 app / build.gradle 파일 을 수정 하고 다음 줄을 추가하는 것입니다 (PDF 파일 압축 비활성화)

aaptOptions {
    noCompress 'pdf'
}

파일 포장

패키저는 여전히 여러 파일을 하나로 묶을 수 있으므로 AssetManager가 제공 하는 전체 파일을 읽을 수는 없습니다 . AssetFileDescriptor 를 요청해야합니다 필요한 부분 해야합니다.

압축 파일의 올바른 부분 찾기

파일이 압축되지 않은 상태로 저장되면 AssetManager.openFd 메서드를 사용 하여 FileChannel 을 포함하는 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의 답변을 기반으로 합니다.


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


public class MainActivity extends Activity {

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

        copyReadAssets();
    }


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

        InputStream in = null;
        OutputStream out = null;

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



        try
        {

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


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

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

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

다음과 같이 코드 부분을 변경하십시오.

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

이전 예제는 .txt의 경우 PDF 용입니다.

FileOutputStream fos = new FileOutputStream(file);

1

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

Google은 친구입니다. 예를 찾으십시오.


1

안녕하세요 여러분 저는 이런 식으로 뭔가를했습니다. N 번째 깊이 복사 폴더 및 복사 할 파일의 경우. Android AssetManager에서 복사 할 모든 디렉토리 구조를 복사 할 수 있습니다. :)

    private void manageAssetFolderToSDcard()
    {

        try
        {
            String arg_assetDir = getApplicationContext().getPackageName();
            String arg_destinationDir = FRConstants.ANDROID_DATA + arg_assetDir;
            File FolderInCache = new File(arg_destinationDir);
            if (!FolderInCache.exists())
            {
                copyDirorfileFromAssetManager(arg_assetDir, arg_destinationDir);
            }
        } catch (IOException e1)
        {

            e1.printStackTrace();
        }

    }


    public String copyDirorfileFromAssetManager(String arg_assetDir, String arg_destinationDir) throws IOException
    {
        File sd_path = Environment.getExternalStorageDirectory(); 
        String dest_dir_path = sd_path + addLeadingSlash(arg_destinationDir);
        File dest_dir = new File(dest_dir_path);

        createDir(dest_dir);

        AssetManager asset_manager = getApplicationContext().getAssets();
        String[] files = asset_manager.list(arg_assetDir);

        for (int i = 0; i < files.length; i++)
        {

            String abs_asset_file_path = addTrailingSlash(arg_assetDir) + files[i];
            String sub_files[] = asset_manager.list(abs_asset_file_path);

            if (sub_files.length == 0)
            {
                // It is a file
                String dest_file_path = addTrailingSlash(dest_dir_path) + files[i];
                copyAssetFile(abs_asset_file_path, dest_file_path);
            } else
            {
                // It is a sub directory
                copyDirorfileFromAssetManager(abs_asset_file_path, addTrailingSlash(arg_destinationDir) + files[i]);
            }
        }

        return dest_dir_path;
    }


    public void copyAssetFile(String assetFilePath, String destinationFilePath) throws IOException
    {
        InputStream in = getApplicationContext().getAssets().open(assetFilePath);
        OutputStream out = new FileOutputStream(destinationFilePath);

        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0)
            out.write(buf, 0, len);
        in.close();
        out.close();
    }

    public String addTrailingSlash(String path)
    {
        if (path.charAt(path.length() - 1) != '/')
        {
            path += "/";
        }
        return path;
    }

    public String addLeadingSlash(String path)
    {
        if (path.charAt(0) != '/')
        {
            path = "/" + path;
        }
        return path;
    }

    public void createDir(File dir) throws IOException
    {
        if (dir.exists())
        {
            if (!dir.isDirectory())
            {
                throw new IOException("Can't create directory, a file is in the way");
            }
        } else
        {
            dir.mkdirs();
            if (!dir.isDirectory())
            {
                throw new IOException("Unable to create directory");
            }
        }
    }

결국 비동기 작업을 만듭니다.

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

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

    }

당신의 활동에서 전화 :

    new ManageAssetFolders().execute();

1

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

public void copyFileOrDir(String path, String destinationDir) {
    AssetManager assetManager = this.getAssets();
    String assets[] = null;
    try {
        assets = assetManager.list(path);
        if (assets.length == 0) {
            copyFile(path,destinationDir);
        } else {
            String fullPath = destinationDir + "/" + path;
            File dir = new File(fullPath);
            if (!dir.exists())
                dir.mkdir();
            for (int i = 0; i < assets.length; ++i) {
                copyFileOrDir(path + "/" + assets[i], destinationDir + path + "/" + assets[i]);
            }
        }
    } catch (IOException ex) {
        Log.e("tag", "I/O Exception", ex);
    }
}

private void copyFile(String filename, String destinationDir) {
    AssetManager assetManager = this.getAssets();
    String newFileName = destinationDir + "/" + filename;

    InputStream in = null;
    OutputStream out = null;
    try {
        in = assetManager.open(filename);
        out = new FileOutputStream(newFileName);

        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
    } catch (Exception e) {
        Log.e("tag", e.getMessage());
    }
    new File(newFileName).setExecutable(true, false);
}

1

Rohith Nandakumar의 솔루션을 기반으로 자산의 하위 폴더 (예 : "자산 / MyFolder ") 에서 파일을 복사하기 위해 자체 작업을 수행했습니다 . 또한 다시 복사하기 전에 파일이 이미 sdcard에 있는지 확인하고 있습니다.

private void copyAssets() {
    AssetManager assetManager = getAssets();
    String[] files = null;
    try {
        files = assetManager.list("MyFolder");
    } catch (IOException e) {
        Log.e("tag", "Failed to get asset file list.", e);
    }
    if (files != null) for (String filename : files) {
        InputStream in = null;
        OutputStream out = null;
        try {
          in = assetManager.open("MyFolder/"+filename);
          File outFile = new File(getExternalFilesDir(null), filename);
          if (!(outFile.exists())) {// File does not exist...
                out = new FileOutputStream(outFile);
                copyFile(in, out);
          }
        } catch(IOException e) {
            Log.e("tag", "Failed to copy asset file: " + filename, e);
        }     
        finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    // NOOP
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    // NOOP
                }
            }
        }  
    }
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int read;
    while((read = in.read(buffer)) != -1){
      out.write(buffer, 0, read);
    }
}

0

이것은 인터넷에서 찾을 수있는 최고의 솔루션입니다. 나는 다음과 같은 링크를 사용했습니다 https://gist.github.com/mhasby/026f02b33fcc4207b302a60645f6e217을 ,
하지만 내가 고정 된 하나의 오류가 발생한 후이 마법처럼 작동합니다. 여기 내 코드가 있습니다. 독립 Java 클래스이므로 쉽게 사용할 수 있습니다.

public class CopyAssets {
public static void copyAssets(Context context) {
    AssetManager assetManager = context.getAssets();
    String[] files = null;
    try {
        files = assetManager.list("");
    } catch (IOException e) {
        Log.e("tag", "Failed to get asset file list.", e);
    }
    if (files != null) for (String filename : files) {
        InputStream in = null;
        OutputStream out = null;
        try {
            in = assetManager.open(filename);

            out = new FileOutputStream(Environment.getExternalStorageDirectory()+"/www/resources/" + filename);
            copyFile(in, out);
        } catch(IOException e) {
            Log.e("tag", "Failed to copy asset file: " + filename, e);
        }
        finally {
            if (in != null) {
                try {
                    in.close();
                    in = null;
                } catch (IOException e) {

                }
            }
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                    out = null;
                } catch (IOException e) {

                }
            }
        }
    }
}

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

보시다시피 CopyAssets, 활동이있는 Java 클래스 의 인스턴스를 작성하십시오 . 이 부분은 인터넷에서 테스트하고 연구하는 한 중요 You cannot use AssetManager if the class has no activity합니다. Java 클래스의 컨텍스트와 관련이 있습니다.
이제는 클래스의 c.copyAssets(getApplicationContext())위치 c와 인스턴스에 메소드에 액세스하는 쉬운 방법 CopyAssets입니다. 필자의 요구 사항에 따라 프로그램이 asset폴더 내의 모든 리소스 파일을 /www/resources/내부 디렉토리 로 복사하는 것을 허용했습니다 .
사용에 따라 디렉토리를 변경해야하는 부분을 쉽게 찾을 수 있습니다. 도움이 필요하시면 언제든지 핑을 해주세요.


0

코 틀린으로 업데이트하는 사람들 :

다음 피하려면 단계를 FileUriExposedExceptions, 가정하여 사용자에게 부여한 WRITE_EXTERNAL_STORAGE권한과 파일에 있습니다 assets/pdfs/mypdf.pdf.

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

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

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

companion object {
    private const val PDF_ASSETS_PATH = "pdfs"
    private const val PDF_FILE_NAME = "mypdf.pdf"
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.