У меня есть несколько файлов в assetsпапке. Мне нужно скопировать их все в папку скажем / SDCard / папку. Я хочу сделать это изнутри. Как мне это сделать?
Прежде чем копировать / вставлять одно из (замечательных!) Решений ниже, рассмотрите возможность использования этой библиотеки в одной строке кода: stackoverflow.com/a/41970539/9648
JohnnyLambada
Ответы:
345
Если у кого-то есть такая же проблема, я так и сделал
для записи файлов в SD-карту вы должны дать разрешение на манифест, например, <использует-разрешение android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
IronBlossom
22
Я бы также не полагался на то, что sdcard находится в / sdcard, но извлекаю путь с помощью Environment.getExternalStorageDirectory ()
Axarydax
2
Должен ли я использовать: 16 * 1024 (16 КБ) Я предпочитаю выбирать 16 КБ или 32 КБ в качестве хорошего баланса между использованием памяти и производительностью.
Нам Ву
3
@rciovati получил эту ошибку во время выполненияFailed to copy asset file: myfile.txt java.io.FileNotFoundException: myfile.txt at android.content.res.AssetManager.openAsset(Native Method)
как
7
Для меня этот код работает, только если я добавлю это: in = assetManager.open("images-wall/"+filename);где «images-wall» - это моя папка внутри ресурсов
Ultimo_m
62
Основываясь на вашем решении, я сделал что-то свое, чтобы разрешить подпапки. Кто-то может найти это полезным:
assetManager.list(path)может быть медленным на устройстве, для предварительного создания списка путей к активам этот фрагмент может быть использован из assetsdir:find . -name "*" -type f -exec ls -l {} \; | awk '{print substr($9,3)}' >> assets.list
alexkasko
3
Отличное решение! Единственное необходимое исправление - обрезать ведущие разделители в начале copyFileOrDir (): path = path.startsWith ("/")? путь подстрока (1): путь;
Cross_
Этот стекопоток на некоторых устройствах, например: S5
behelit
2
замените "/ data / data /" + this.getPackageName () на this.getFilesDir (). getAbsolutePath ()
ibrahimyilmaz
1
... и закрыть потоки в finallyблоке))
Mixaz
48
Решение выше не сработало из-за некоторых ошибок:
создание каталога не работает
активы, возвращаемые Android, также содержат три папки: изображения, звуки и веб-набор
Добавлен способ работы с большими файлами: добавьте расширение .mp3 к файлу в папке ресурсов в вашем проекте, и во время копирования целевой файл будет без расширения .mp3
Вот код (я оставил операторы Log, но вы можете удалить их сейчас):
finalstaticString TARGET_BASE_PATH ="/sdcard/appname/voices/";privatevoid copyFilesToSdCard(){
copyFileOrDir("");// copy all files in assets folder in my project}privatevoid 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 =newFile(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);}}privatevoid copyFile(String filename){AssetManager assetManager =this.getAssets();InputStreamin=null;OutputStreamout=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=newFileOutputStream(newFileName);byte[] buffer =newbyte[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());}}
РЕДАКТИРОВАТЬ: исправлено неуместное ";" это приводило к систематической ошибке «не удалось создать каталог».
ПРИМЕЧАНИЕ: Log.i («tag», «не удалось создать каталог» + fullPath); всегда происходит как; неуместно, если.
RoundSparrow Hilltx
отличный способ! Большое спасибо! Но почему вы проверяете файл jpg?
Phuong
32
Я знаю, что на это ответили, но у меня есть немного более элегантный способ скопировать из каталога ресурсов в файл на SD-карте. Он не требует цикла «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 =newFile(Environment.getExternalStorageDirectory()+ java.io.File.separator +"NewFile.dat");
file.createNewFile();
copyFdToFile(afd.getFileDescriptor(), file);}catch(IOException e){
e.printStackTrace();}
Способ скопировать файл без необходимости проходить через него.
Понравилось это над другими решениями, немного аккуратнее. Небольшая модификация на моем, которая включает создание отсутствующих файловых папок. ура!
Chris.Jenkins
3
Это не сработает после файлового дескриптора This file can not be opened as a file descriptor; it is probably compressed- это файл PDF. Знаете, как это исправить?
Gaʀʀʏ
1
Это предполагает, что inChannel.size () возвращает размер размера файла. Это не дает такой гарантии . Я получаю 2,5 МиБ за 2 файла по 450 КиБ каждый.
AI0867
1
Я только что обнаружил, что AssetFileDescriptor.getLength () вернет правильный размер файла.
AI0867
1
В дополнение к вышесказанному ресурс может не начинаться с местоположения 0 в дескрипторе файла. AssetFileDescriptor.getStartOffset () вернет начальное смещение.
AI0867
5
попробуйте это намного проще, это поможет вам:
// Open your local db as the input streamInputStream myInput = _context.getAssets().open(YOUR FILE NAME);// Path to the just created empty dbString outFileName =SDCARD PATH + YOUR FILE NAME;// Open the empty db as the output streamOutputStream myOutput =newFileOutputStream(outFileName);// transfer bytes from the inputfile to the outputfilebyte[] buffer =newbyte[1024];int length;while((length = myInput.read(buffer))>0){
myOutput.write(buffer,0, length);}// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
list (assetPath) ?. let {...}, на самом деле. Это Nullable.
Габор
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)publicstaticboolean copyAssets(AssetManager assetManager,File targetFolder)throwsException{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
*/publicstaticboolean copyAssets(AssetManager assetManager,String path,File targetFolder)throwsException{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);returnfalse;}File targetDir =newFile(targetFolder, path);
targetDir.mkdirs();for(String source : sources){String fullSourcePath = path.equals("")? source :(path
+File.separator + source);
copyAssets(assetManager, fullSourcePath, targetFolder);}}returntrue;}privatestaticvoid copyAssetFileToFolder(AssetManager assetManager,String fullAssetPath,File targetBasePath)throwsIOException{InputStreamin= assetManager.open(fullAssetPath);OutputStreamout=newFileOutputStream(newFile(targetBasePath,
fullAssetPath));byte[] buffer =newbyte[16*1024];int read;while((read =in.read(buffer))!=-1){out.write(buffer,0, read);}in.close();out.flush();out.close();}
Используя некоторые концепции в ответах на этот вопрос, я написал класс, призванный AssetCopierупростить копирование /assets/. Он доступен на github и доступен с помощью jitpack.io :
Сначала вам нужно убедиться, что файл хранится без сжатия. Система упаковки может выбрать сжатие любого файла с расширением, которое не помечено как noCompress , и сжатые файлы не могут быть отображены в памяти, поэтому вам придется полагаться на AssetManager.open в этом случае .
Вы можете добавить расширение «.mp3» к своему файлу, чтобы предотвратить его сжатие, но правильное решение - изменить файл app / build.gradle и добавить следующие строки (чтобы отключить сжатие файлов PDF)
aaptOptions {
noCompress 'pdf'}
Упаковка файлов
Обратите внимание, что упаковщик все еще может упаковать несколько файлов в один, поэтому вы не можете просто прочитать весь файл, который вам дает AssetManager . Вам нужно спросить AssetFileDescriptor какие части вам нужны.
Нахождение правильной части упакованного файла
Убедившись, что ваш файл хранится в несжатом виде, вы можете использовать метод AssetManager.openFd для получения AssetFileDescriptor , который можно использовать для получения FileInputStream (в отличие от AssetManager.open , который возвращает InputStream ), который содержит FileChannel . Он также содержит начальное смещение (getStartOffset) и размер (getLength) , которые необходимы для получения правильной части файла.
Привет, ребята, я сделал что-то вроде этого. Для N-й глубины копировать папку и файлы для копирования. Что позволяет скопировать всю структуру каталогов для копирования из Android AssetManager :)
privatevoid manageAssetFolderToSDcard(){try{String arg_assetDir = getApplicationContext().getPackageName();String arg_destinationDir =FRConstants.ANDROID_DATA + arg_assetDir;FileFolderInCache=newFile(arg_destinationDir);if(!FolderInCache.exists()){
copyDirorfileFromAssetManager(arg_assetDir, arg_destinationDir);}}catch(IOException e1){
e1.printStackTrace();}}publicString copyDirorfileFromAssetManager(String arg_assetDir,String arg_destinationDir)throwsIOException{File sd_path =Environment.getExternalStorageDirectory();String dest_dir_path = sd_path + addLeadingSlash(arg_destinationDir);File dest_dir =newFile(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 fileString 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;}publicvoid copyAssetFile(String assetFilePath,String destinationFilePath)throwsIOException{InputStreamin= getApplicationContext().getAssets().open(assetFilePath);OutputStreamout=newFileOutputStream(destinationFilePath);byte[] buf =newbyte[1024];int len;while((len =in.read(buf))>0)out.write(buf,0, len);in.close();out.close();}publicString addTrailingSlash(String path){if(path.charAt(path.length()-1)!='/'){
path +="/";}return path;}publicString addLeadingSlash(String path){if(path.charAt(0)!='/'){
path ="/"+ path;}return path;}publicvoid createDir(File dir)throwsIOException{if(dir.exists()){if(!dir.isDirectory()){thrownewIOException("Can't create directory, a file is in the way");}}else{
dir.mkdirs();if(!dir.isDirectory()){thrownewIOException("Unable to create directory");}}}
Основываясь на решении Рохита Нандакумара, я сделал что-то свое, чтобы скопировать файлы из подпапки активов (например, «assets / MyFolder »). Кроме того, я проверяю, существует ли файл в SDCard, прежде чем пытаться копировать снова.
privatevoid 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){InputStreamin=null;OutputStreamout=null;try{in= assetManager.open("MyFolder/"+filename);File outFile =newFile(getExternalFilesDir(null), filename);if(!(outFile.exists())){// File does not exist...out=newFileOutputStream(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}}}}}privatevoid copyFile(InputStreamin,OutputStreamout)throwsIOException{byte[] buffer =newbyte[1024];int read;while((read =in.read(buffer))!=-1){out.write(buffer,0, read);}}
На сегодняшний день это лучшее решение, которое мне удалось найти в Интернете. Я использовал следующую ссылку https://gist.github.com/mhasby/026f02b33fcc4207b302a60645f6e217 , но там была одна ошибка, которую я исправил, а затем она работает как чудо-кнопка. Вот мой код Вы можете легко использовать его, поскольку это независимый класс Java.
Как вы можете видеть, просто создайте CopyAssetsв своем java-классе экземпляр с активностью. Теперь эта часть важна, насколько я тестирую и исследую интернет You cannot use AssetManager if the class has no activity. Это как-то связано с контекстом Java-класса.
Теперь, c.copyAssets(getApplicationContext())это простой способ получить доступ к методу, где cесть и экземпляр CopyAssetsкласса. Согласно моему требованию, я позволил программе скопировать все мои файлы ресурсов из assetпапки в /www/resources/мой внутренний каталог.
Вы можете легко найти ту часть, где вам нужно внести изменения в каталог в соответствии с вашим использованием. Не стесняйтесь пинговать меня, если вам нужна помощь.
После этой меры , чтобы избежать FileUriExposedExceptions, если предположить , пользователь предоставил WRITE_EXTERNAL_STORAGEразрешение и ваш файл находится в assets/pdfs/mypdf.pdf.
private fun openFile(){var inputStream:InputStream?=nullvar outputStream:OutputStream?=nulltry{
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{privateconst val PDF_ASSETS_PATH ="pdfs"privateconst val PDF_FILE_NAME ="mypdf.pdf"}
Ответы:
Если у кого-то есть такая же проблема, я так и сделал
Ссылка: Переместить файл с помощью Java
источник
Failed to copy asset file: myfile.txt java.io.FileNotFoundException: myfile.txt at android.content.res.AssetManager.openAsset(Native Method)
in = assetManager.open("images-wall/"+filename);
где «images-wall» - это моя папка внутри ресурсовОсновываясь на вашем решении, я сделал что-то свое, чтобы разрешить подпапки. Кто-то может найти это полезным:
...
...
источник
assetManager.list(path)
может быть медленным на устройстве, для предварительного создания списка путей к активам этот фрагмент может быть использован изassets
dir:find . -name "*" -type f -exec ls -l {} \; | awk '{print substr($9,3)}' >> assets.list
finally
блоке))Решение выше не сработало из-за некоторых ошибок:
Вот код (я оставил операторы Log, но вы можете удалить их сейчас):
РЕДАКТИРОВАТЬ: исправлено неуместное ";" это приводило к систематической ошибке «не удалось создать каталог».
источник
Я знаю, что на это ответили, но у меня есть немного более элегантный способ скопировать из каталога ресурсов в файл на SD-карте. Он не требует цикла «for», но вместо этого использует файловые потоки и каналы для выполнения работы.
(Примечание. При использовании любого типа сжатого файла, APK, PDF, ... вы можете переименовать расширение файла перед вставкой в ресурс, а затем переименовать после копирования на SD-карту)
Способ скопировать файл без необходимости проходить через него.
источник
This file can not be opened as a file descriptor; it is probably compressed
- это файл PDF. Знаете, как это исправить?попробуйте это намного проще, это поможет вам:
источник
Это было бы кратким способом в Котлине.
источник
Вот очищенная версия для текущих устройств Android, дизайн функциональных методов, так что вы можете скопировать ее в класс AssetsHelper, например;)
источник
Модифицировал этот SO ответ @DannyA
Препараты
в
src/main/assets
добавить папку с именемfold
использование
Во внешнем каталоге найдите все файлы и каталоги, которые находятся в активах сгиба
источник
Скопируйте все файлы и каталоги из ресурсов в вашу папку!
для копирования лучше использовать Apache Commons IO
// ЭТО ОСНОВНОЙ МЕТОД ДЛЯ КОПИРОВАНИЯ
источник
Основываясь на ответе Йорама Коэна, вот версия, которая поддерживает нестатический целевой каталог.
Invoque с
copyFileOrDir(getDataDir(), "")
записью во внутреннюю папку хранилища приложения / data / data / pkg_name /Избегает копирования "изображений" и т. Д. Фальшивых папок активов
источник
Используя некоторые концепции в ответах на этот вопрос, я написал класс, призванный
AssetCopier
упростить копирование/assets/
. Он доступен на github и доступен с помощью jitpack.io :См. Https://github.com/flipagram/android-assetcopier для получения более подробной информации.
источник
Есть два основных способа сделать это.
Во-первых, вы можете использовать AssetManager.open и, как описано Rohith Nandakumar, и перебирать входные потоки .
Во-вторых, вы можете использовать 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)
Упаковка файлов
Обратите внимание, что упаковщик все еще может упаковать несколько файлов в один, поэтому вы не можете просто прочитать весь файл, который вам дает AssetManager . Вам нужно спросить AssetFileDescriptor какие части вам нужны.
Нахождение правильной части упакованного файла
Убедившись, что ваш файл хранится в несжатом виде, вы можете использовать метод AssetManager.openFd для получения AssetFileDescriptor , который можно использовать для получения FileInputStream (в отличие от AssetManager.open , который возвращает InputStream ), который содержит FileChannel . Он также содержит начальное смещение (getStartOffset) и размер (getLength) , которые необходимы для получения правильной части файла.
Реализация
Пример реализации приведен ниже:
Этот ответ основан на ответе JPM .
источник
изменить части кода следующим образом:
предыдущий пример для Pdf, в случае с примером .txt
источник
Используйте AssetManager , он позволяет читать файлы в активах. Затем используйте обычный ввод-вывод Java для записи файлов в SDCard.
Google твой друг, ищи пример.
источник
Привет, ребята, я сделал что-то вроде этого. Для N-й глубины копировать папку и файлы для копирования. Что позволяет скопировать всю структуру каталогов для копирования из Android AssetManager :)
В конце создайте Asynctask:
позвони из своей деятельности:
источник
Небольшая модификация приведенного выше ответа для рекурсивного копирования папки и размещения пользовательского места назначения.
источник
Основываясь на решении Рохита Нандакумара, я сделал что-то свое, чтобы скопировать файлы из подпапки активов (например, «assets / MyFolder »). Кроме того, я проверяю, существует ли файл в SDCard, прежде чем пытаться копировать снова.
источник
На сегодняшний день это лучшее решение, которое мне удалось найти в Интернете. Я использовал следующую ссылку https://gist.github.com/mhasby/026f02b33fcc4207b302a60645f6e217 ,
но там была одна ошибка, которую я исправил, а затем она работает как чудо-кнопка. Вот мой код Вы можете легко использовать его, поскольку это независимый класс Java.
Как вы можете видеть, просто создайте
CopyAssets
в своем java-классе экземпляр с активностью. Теперь эта часть важна, насколько я тестирую и исследую интернетYou cannot use AssetManager if the class has no activity
. Это как-то связано с контекстом Java-класса.Теперь,
c.copyAssets(getApplicationContext())
это простой способ получить доступ к методу, гдеc
есть и экземплярCopyAssets
класса. Согласно моему требованию, я позволил программе скопировать все мои файлы ресурсов изasset
папки в/www/resources/
мой внутренний каталог.Вы можете легко найти ту часть, где вам нужно внести изменения в каталог в соответствии с вашим использованием. Не стесняйтесь пинговать меня, если вам нужна помощь.
источник
Для тех, кто обновляется до Kotlin:
После этой меры , чтобы избежать
FileUriExposedExceptions
, если предположить , пользователь предоставилWRITE_EXTERNAL_STORAGE
разрешение и ваш файл находится вassets/pdfs/mypdf.pdf
.источник