android 열기 - 'assets'폴더에서 sdcard로 파일을 복사하는 방법은 무엇입니까?




9 Answers

다른 사람이 같은 문제를 겪고 있다면, 이것이 내가 어떻게했는지입니다.

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

read file

assets 폴더에 파일이 몇 개 있습니다. 나는 그들 모두를 폴더 say / sdcard / 폴더에 복사해야합니다. 나는 스레드 내에서이 작업을 수행하려고합니다. 어떻게해야합니까?




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

  • 디렉토리 생성이 작동하지 않았다.
  • Android에서 반환하는 애셋에는 이미지, 사운드 및 웹킷이라는 세 개의 폴더도 포함됩니다.
  • 대용량 파일 처리 방법 추가 : 프로젝트의 assets 폴더에있는 파일에 .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 not create dir"오류가 발생했습니다.




좋은 예. 애셋 폴더의 파일에 액세스하는 방법에 대한 내 질문에 답변했습니다.

내가 제안 할 변경 사항은 for 루프에 있습니다. 다음 형식도 효과가 있으며 선호됩니다.

    for(String filename : files) {
        InputStream in = null;
        OutputStream out = null;
        try {
          in = assetManager.open(filename);
          out = new FileOutputStream("/sdcard/" + filename);
        ...
    }



현재 안드로이드 장치를위한 정리 된 버전입니다. 예를 들어 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();
}



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

더 나은 사용을 위해 복사 아파치 커먼즈 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);
    }
}



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

먼저 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 메서드를 사용하여 AssetFileDescriptor 를 가져올 수 있습니다. AssetFileDescriptorFileChannel 이 포함 된 FileInputStream ( AssetManager.open 과 달리 InputStream 을 반환 함)을 가져 오는 데 사용할 수 있습니다. 또한 파일의 올바른 부분을 가져 오는 데 필요한 시작 오프셋 (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의 답변을 기반으로합니다.




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

Google은 귀하의 친구이며, 모범을 찾고 있습니다.




위의 답변을 약간 수정하여 폴더를 반복적으로 복사하고 사용자 지정 대상을 수용합니다.

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



이것은 내가 인터넷에서 찾을 수있는 최고의 솔루션입니다. 다음 링크를 사용했습니다 : 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);
    }
}}

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




Related