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




read file (16)

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


Answers

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

먼저 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의 답변을 기반으로합니다.


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

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

이것은 내가 인터넷에서 찾을 수있는 최고의 솔루션입니다. 다음 링크를 사용했습니다 : 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/ 로 복사 할 수있었습니다.
귀하의 용도에 따라 디렉토리를 변경해야하는 부분을 쉽게 찾을 수 있습니다. 도움이 필요하시면 언제든지 저를 핑하십시오.


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

  • 디렉토리 생성이 작동하지 않았다.
  • 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"오류가 발생했습니다.


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

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


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

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

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

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

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


Yoram Cohen의 대답에 기반하여, 여기에 정적이 아닌 대상 디렉토리를 지원하는 버전이 있습니다.

copyFileOrDir copyFileOrDir(getDataDir(), "") 으로 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());
    }
    
    }
    

Rohith Nandakumar의 솔루션을 기반으로, 나는 자산의 하위 폴더 (즉, "assets / 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);
    }
}

안녕 얘들 아 나는 이런 걸했다. N 번째 깊이 복사 폴더 및 파일을 복사하십시오. 어느 당신이 안드로이드 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");
            }
        }
    }

결국 Asynctask를 만듭니다.

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

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

    }

그것을 당신의 활동에서 불러내십시오 :

    new ManageAssetFolders().execute();

이것을 시도하면 훨씬 간단 해 지는데 도움이 될 것입니다.

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

귀하의 솔루션을 기반으로, 나는 하위 폴더를 허용하기 위해 내 자신의 뭔가를했습니다. 누군가 도움이 될 수 있습니다.

...

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

}

이 답변을 알고 있지만 자산 디렉토리에서 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();
    }
}

@이 대변인에 의해 수정 된 @ Dananya

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/assetsfold 라는 이름의 폴더 추가

용법

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

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


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

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

파이썬에서리스트를 복제하거나 복사하는 옵션은 무엇입니까?

Python 3에서는 다음과 같이 얕은 복사본을 만들 수 있습니다.

a_copy = a_list.copy()

파이썬 2와 3에서는 원본의 전체 슬라이스로 얕은 복사본을 얻을 수 있습니다 :

a_copy = a_list[:]

설명

목록을 복사하는 의미 론적 방법은 두 가지가 있습니다. 얕은 복사본은 동일한 개체의 새 목록을 만들고 딥 복사본은 새로운 동일한 개체가 포함 된 새 목록을 만듭니다.

얕은 목록 복사

얕은 복사본은 목록의 개체에 대한 참조의 컨테이너 인 목록 자체 만 복사합니다. 포함 된 오브젝트가 변경 가능하고 하나가 변경된 경우, 변경 사항은 두리스트 모두에 반영됩니다.

파이썬 2와 파이썬 3에서 다른 방법이 있습니다. 파이썬 2 웨이는 파이썬 3에서도 작동합니다.

파이썬 2

파이썬 2에서리스트의 얕은 사본을 만드는 관용적 인 방법은 원본의 완전한 슬라이스를 사용하는 것입니다 :

a_copy = a_list[:]

목록 생성자를 통해 목록을 전달하여 동일한 작업을 수행 할 수도 있습니다.

a_copy = list(a_list)

그러나 생성자를 사용하는 것은 덜 효율적입니다.

>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844

파이썬 3

Python 3에서 list는 list.copy 메소드를 얻는다.

a_copy = a_list.copy()

파이썬 3.5에서 :

>>> import timeit
>>> l = list(range(20))
>>> min(timeit.repeat(lambda: l[:]))
0.38448613602668047
>>> min(timeit.repeat(lambda: list(l)))
0.6309100328944623
>>> min(timeit.repeat(lambda: l.copy()))
0.38122922903858125

다른 포인터를 만드는 것은 복사본을 만들지 않습니다.

new_list = my_list를 사용하면 my_list가 변경 될 때마다 new_list가 수정됩니다. 왜 이런거야?

my_list 는 메모리의 실제 목록을 가리키는 이름입니다. 복사본을 만들지 않은 new_list = my_list 라고 말하면 메모리의 원래 목록을 가리키는 다른 이름을 추가하기 만하면됩니다. 목록을 복사 할 때 비슷한 문제가 발생할 수 있습니다.

>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]

목록은 내용에 대한 포인터의 배열이므로 얕은 사본은 포인터 만 복사하기 때문에 두 개의 다른 목록이 있지만 내용은 동일합니다. 내용을 복사하려면 깊은 사본이 필요합니다.

딥 카피

파이썬 2 또는 3에서 목록의 전체 복사본 을 만들려면 copy 모듈에서 deepcopy 를 사용하십시오 .

import copy
a_deep_copy = copy.deepcopy(a_list)

이것이 새로운 하위 목록을 만드는 방법을 보여주기 위해 :

>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]

그래서 우리는 깊은 복사 목록이 원본과 완전히 다른 목록이라는 것을 알 수 있습니다. 당신은 자신의 기능을 굴릴 수는 있지만 그렇게하지는 마십시오. 표준 라이브러리의 deepcopy 기능을 사용하지 않으면 얻을 수없는 버그를 만들 수 있습니다.

eval 사용하지 마십시오.

이것을 딥 카피하는 방법으로 사용하는 것을 볼 수는 있지만 그렇게하지는 마십시오 :

problematic_deep_copy = eval(repr(a_list))
  1. 위험합니다. 특히 신뢰하지 않는 출처에서 무언가를 평가하는 경우 더욱 그렇습니다.
  2. 복사하는 하위 요소에 동등한 요소를 재생산 할 수있는 표현이 없으면 신뢰할 수 없습니다.
  3. 그것은 또한 덜 performant입니다.

64 비트 Python 2.7 :

>>> import timeit
>>> import copy
>>> l = range(10)
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
27.55826997756958
>>> min(timeit.repeat(lambda: eval(repr(l))))
29.04534101486206

64 비트 Python 3.5 :

>>> import timeit
>>> import copy
>>> l = list(range(10))
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
16.84255409205798
>>> min(timeit.repeat(lambda: eval(repr(l))))
34.813894678023644




android copy assets