| page.title=Сохранение файлов |
| page.tags=хранение данных |
| helpoutsWidget=true |
| |
| trainingnavtop=true |
| |
| @jd:body |
| |
| |
| <div id="tb-wrapper"> |
| <div id="tb"> |
| |
| <h2>Содержание этого урока</h2> |
| <ol> |
| <li><a href="#InternalVsExternalStorage">Выбор внутреннего или внешнего хранилища</a></li> |
| <li><a href="#GetWritePermission">Получение разрешений на доступ к внешнему хранилищу</a></li> |
| <li><a href="#WriteInternalStorage">Сохранение файла во внутреннем хранилище</a></li> |
| <li><a href="#WriteExternalStorage">Сохранение файла во внешнем хранилище</a></li> |
| <li><a href="#GetFreeSpace">Запрос свободного пространства</a></li> |
| <li><a href="#DeleteFile">Удаление файла</a></li> |
| </ol> |
| |
| <h2>См. также:</h2> |
| <ul> |
| <li><a href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">Использование внутреннего |
| хранилища</a></li> |
| <li><a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">Использование внешнего |
| хранилища</a></li> |
| </ul> |
| |
| </div> |
| </div> |
| |
| <p>Операционная система Android использует файловую систему, |
| похожую на дисковые файловые системы других платформ. В этом уроке рассказывается, |
| как работать с файловой системой Android для чтения и записи файлов в {@link java.io.File} |
| API-интерфейсах.</p> |
| |
| <p>Объект {@link java.io.File} подходит для чтения или записи больших объемов данных в порядке |
| от начала к концу без пропусков. Например, этот способ оптимален для изображений или |
| любых других файлов, передаваемых по сети.</p> |
| |
| <p>В этом уроке вы узнаете, как выполнять в приложении базовые задачи, связанные с файлами. |
| Для прохождения урока вы должны быть знакомы с основами файловой системы Linux |
| и стандартными файловыми API-интерфейсами ввода/вывода в {@link java.io}.</p> |
| |
| |
| <h2 id="InternalVsExternalStorage">Выбор внутреннего или внешнего хранилища</h2> |
| |
| <p>Все устройства Android имеют две области хранения файлов: внутренняя память и внешние хранилища. Эти области |
| появились в первые годы существования Android, когда на большинстве устройств имелись встроенная память |
| (внутреннее хранилище) и карты памяти (например micro SD, внешнее хранилище). |
| Некоторые устройства делят встроенную память на внутренний и внешний разделы, |
| так что даже без съемных носителей в системе две области хранения файлов, |
| и API-интерфейс работает одинаково вне зависимости от типа внешнего хранилища. |
| Ниже подробно описаны обе области хранения файлов.</p> |
| |
| <div class="col-5" style="margin-left:0"> |
| <p><b>Внутренняя память</b></p> |
| <ul> |
| <li>Всегда доступна.</li> |
| <li>Сохраненные здесь файлы по умолчанию доступны только вашему приложению.</li> |
| <li>При удалении пользователем вашего приложения система Android удаляет из внутренней памяти |
| все файлы этого приложения.</li> |
| </ul> |
| <p>Внутренняя память лучше всего подходит для ситуаций, когда вы хотите быть уверены, что ни пользователь, ни другие приложения не смогут получить |
| доступ к вашим файлам.</p> |
| </div> |
| |
| <div class="col-7" style="margin-right:0"> |
| <p><b>Внешнее хранилище</b></p> |
| <ul> |
| <li>Доступно не всегда, потому что пользователь может в любое время подключать и отключать такие |
| хранилища, например, USB-накопители.</li> |
| <li>Такие хранилища доступны для чтения везде, |
| поэтому вы не контролируете чтение сохраненных в них данных.</li> |
| <li>При удалении пользователем вашего приложения система Android удаляет из внешних хранилищ |
| файлы этого приложения, только если они сохраняются в директории из {@link android.content.Context#getExternalFilesDir |
| getExternalFilesDir()}.</li> |
| </ul> |
| <p>Внешнее хранилище лучше всего |
| подходит для файлов без ограничений доступа и для файлов, которые вы хотите сделать |
| доступными другим приложениям или пользователю через компьютер.</p> |
| </div> |
| |
| |
| <p class="note" style="clear:both"> |
| <strong>Совет.</strong> Хотя по умолчанию приложения устанавливаются во внутреннюю память, |
| вы можете указать в манифесте атрибут <a href="{@docRoot}guide/topics/manifest/manifest-element.html#install">{@code |
| android:installLocation}</a>, чтобы приложение можно |
| было установить во внешнее хранилище. Этот вариант будет полезен пользователям при большом размере файла APK, либо если у них есть доступ |
| к внешнему хранилищу, объем которого превышает внутреннюю память. Дополнительную информацию |
| см. в разделе <a href="{@docRoot}guide/topics/data/install-location.html">Место установки приложения</a>.</p> |
| |
| |
| <h2 id="GetWritePermission">Получение разрешений доступа к внешнему хранилищу</h2> |
| |
| <p>Для записи во внешнее хранилище следует указать запрос |
| разрешения {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} в <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">файле манифеста</a>:</p> |
| |
| <pre> |
| <manifest ...> |
| <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
| ... |
| </manifest> |
| </pre> |
| |
| <div class="caution"><p><strong>Внимание!</strong> |
| В настоящее время все приложения могут считывать данные из внешних |
| хранилищ без специального разрешения. Однако в новой версии эта ситуация будет изменена. Если вашему приложению потребуется |
| считать данные из внешнего хранилища (но не записать туда данные), вам необходимо будет декларировать разрешение {@link |
| android.Manifest.permission#READ_EXTERNAL_STORAGE}. Чтобы обеспечить дальнейшую работу вашего приложения |
| ожидаемым образом, вы должны сразу декларировать это разрешение до того, как изменения вступят в силу.</p> |
| <pre> |
| <manifest ...> |
| <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
| ... |
| </manifest> |
| </pre> |
| <p>Однако если ваше приложение использует разрешение {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}, |
| оно косвенно получает разрешение на чтение данных из внешнего хранилища.</p> |
| </div> |
| |
| <p>Для сохранения файлов во внутреннем хранилище |
| не требуется никаких разрешений. У вашего приложения всегда будет разрешение на чтение и запись |
| файлов в его каталог внутренней памяти.</p> |
| |
| |
| |
| |
| |
| <h2 id="WriteInternalStorage">Сохранение файла во внутренней памяти</h2> |
| |
| <p>При сохранении файла во внутреннюю память вы можете получить соответствующую директорию в виде |
| {@link java.io.File}, вызвав один из двух методов:</p> |
| |
| <dl> |
| <dt>{@link android.content.Context#getFilesDir}</dt> |
| <dd>Возвращает {@link java.io.File}, соответствующий внутренней директории приложения.</dd> |
| <dt>{@link android.content.Context#getCacheDir}</dt> |
| <dd>Возвращает {@link java.io.File}, соответствующий внутренней директории файлов временной |
| кэш-памяти приложения. Обязательно удаляйте каждый файл, когда он перестанет |
| быть нужным, и устанавливайте разумное ограничение размера памяти, используемой в каждый момент времени, |
| например, 1 МБ. Если системе будет не хватать места в хранилище, она может удалять файлы |
| из кэш-памяти без уведомления.</dd> |
| </dl> |
| |
| <p>Для создания файла в одной из этих директорий можно использовать конструктор {@link |
| java.io.File#File(File,String) File()}, который передает элемент {@link java.io.File}, предоставляемый одним из вышеприведенных |
| методов, с помощью которого указывается директория во внутренней памяти. Например:</p> |
| |
| <pre> |
| File file = new File(context.getFilesDir(), filename); |
| </pre> |
| |
| <p>Кроме того, можно вызвать метод {@link |
| android.content.Context#openFileOutput openFileOutput()} для получения объекта {@link java.io.FileOutputStream} |
| , производящего запись в файл во внутренней памяти. Вот пример |
| записи текста в файл:</p> |
| |
| <pre> |
| String filename = "myfile"; |
| String string = "Hello world!"; |
| FileOutputStream outputStream; |
| |
| try { |
| outputStream = openFileOutput(filename, Context.MODE_PRIVATE); |
| outputStream.write(string.getBytes()); |
| outputStream.close(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| </pre> |
| |
| <p>Если вам потребуется кэшировать какие-то файлы, используйте {@link |
| java.io.File#createTempFile createTempFile()}. Например, следующий метод извлекает |
| имя файла из {@link java.net.URL} и создает файл с этим именем |
| в каталоге внутренней кэш-памяти вашего приложения:</p> |
| |
| <pre> |
| public File getTempFile(Context context, String url) { |
| File file; |
| try { |
| String fileName = Uri.parse(url).getLastPathSegment(); |
| file = File.createTempFile(fileName, null, context.getCacheDir()); |
| catch (IOException e) { |
| // Error while creating file |
| } |
| return file; |
| } |
| </pre> |
| |
| <p class="note"><strong>Примечание.</strong> |
| Каталог вашего приложения во внутренней памяти указывается |
| с использованием имени пакета приложения в определенном месте файловой системы Android. |
| Технически другое приложение может прочитать ваши файлы во внутренней памяти, если вы установите для файлов |
| режим Readable (доступно для чтения). Однако для этого другому приложению должны быть известны имя пакета вашего |
| приложения и имена файлов. Другие приложения не могут просматривать внутренние каталоги вашего приложения и не имеют разрешений на |
| чтение или запись, если вы специально не установите для своих файлов режим Readable (доступно для чтения) или Writable (доступно для записи). Следовательно, пока |
| вы будете использовать режим {@link android.content.Context#MODE_PRIVATE} для своих файлов во внутренней памяти, |
| они будут недоступны другим приложениям.</p> |
| |
| |
| |
| |
| |
| <h2 id="WriteExternalStorage">Сохранение файла во внешнем хранилище</h2> |
| |
| <p>Поскольку внешнее хранилище может быть недоступно— например, если пользователь установил |
| хранилище в гнездо на компьютере или извлек из устройства SD-карту, — перед доступом к тому всегда следует |
| проверять его доступность. Состояние внешнего |
| хранилища можно узнать, если вызвать {@link android.os.Environment#getExternalStorageState}. Если возвращаемое состояние |
| равнозначно {@link android.os.Environment#MEDIA_MOUNTED}, вы сможете выполнять с файлами операции чтения и |
| записи. Например, следующие методы будут полезными для определения доступности |
| хранилища данных:</p> |
| |
| <pre> |
| /* Checks if external storage is available for read and write */ |
| public boolean isExternalStorageWritable() { |
| String state = Environment.getExternalStorageState(); |
| if (Environment.MEDIA_MOUNTED.equals(state)) { |
| return true; |
| } |
| return false; |
| } |
| |
| /* Checks if external storage is available to at least read */ |
| public boolean isExternalStorageReadable() { |
| String state = Environment.getExternalStorageState(); |
| if (Environment.MEDIA_MOUNTED.equals(state) || |
| Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { |
| return true; |
| } |
| return false; |
| } |
| </pre> |
| |
| <p>Хотя внешнее хранилище может быть изменено пользователем и другими приложениями, существует две |
| категории файлов, которые в нем можно сохранять:</p> |
| |
| <dl> |
| <dt>Общедоступные файлы</dt> |
| <dd>Файлы, которые |
| должны быть доступны другим приложениям и пользователю. Когда пользователь удаляет ваше приложение, |
| эти файлы должны оставаться доступны пользователю. |
| <p>Например, в эту категорию входят снимки, сделанные с помощью вашего приложения, а также другие загружаемые файлы.</p> |
| </dd> |
| <dt>Личные файлы</dt> |
| <dd>Это файлы, принадлежащие вашему приложению. Они должны удаляться при удалении |
| вашего приложения пользователем. Хотя технически эти файлы доступны для пользователя и других приложений, поскольку находятся |
| во внешнем хранилище, они не имеют никакой ценности для пользователей |
| вне вашего приложения. Когда пользователь удаляет ваше приложение, система удаляет |
| все файлы из каталога закрытых файлов вашего приложения во внешнем хранилище. |
| <p>Например, к этой категории относятся дополнительные ресурсы, загруженные приложением, и временные мультимедийные файлы.</p> |
| </dd> |
| </dl> |
| |
| <p>Если вы хотите сохранить публичные файлы во внешнем хранилище, используйте методы |
| {@link android.os.Environment#getExternalStoragePublicDirectory |
| getExternalStoragePublicDirectory()} для получения {@link java.io.File}, отражающего |
| соответствующий каталог во внешнем хранилище. Этот метод принимает аргумент, указывающий |
| тип сохраняемого файла и позволяющий включить его в логическую структуру |
| с другими публичными файлами, например, {@link android.os.Environment#DIRECTORY_MUSIC} или {@link |
| android.os.Environment#DIRECTORY_PICTURES}. Например:</p> |
| |
| <pre> |
| public File getAlbumStorageDir(String albumName) { |
| // Get the directory for the user's public pictures directory. |
| File file = new File(Environment.getExternalStoragePublicDirectory( |
| Environment.DIRECTORY_PICTURES), albumName); |
| if (!file.mkdirs()) { |
| Log.e(LOG_TAG, "Directory not created"); |
| } |
| return file; |
| } |
| </pre> |
| |
| |
| <p>Если вы хотите сохранить личные файлы вашего приложения, вы можете получить |
| соответствующий каталог посредством, вызвав метод {@link |
| android.content.Context#getExternalFilesDir getExternalFilesDir()} и предоставив ему имя с указанием |
| желаемого типа каталога. Каждый каталог, создаваемый таким способом, добавляется в родительский |
| каталог, в котором объединены все файлы вашего приложения во внешнем хранилище. При удалении вашего приложения |
| пользователем система удаляет этот каталог.</p> |
| |
| <p>Например, следующий метод позволит вам создать каталог для персонального фотоальбома:</p> |
| |
| <pre> |
| public File getAlbumStorageDir(Context context, String albumName) { |
| // Get the directory for the app's private pictures directory. |
| File file = new File(context.getExternalFilesDir( |
| Environment.DIRECTORY_PICTURES), albumName); |
| if (!file.mkdirs()) { |
| Log.e(LOG_TAG, "Directory not created"); |
| } |
| return file; |
| } |
| </pre> |
| |
| <p>Если ни одно из готовых имен подкаталогов не подходит для ваших файлов, вы можете вызвать {@link |
| android.content.Context#getExternalFilesDir getExternalFilesDir()} и передать аргумент {@code null}. При этом |
| будет возвращен корневой каталог закрытого каталога вашего приложения во внешнем хранилище.</p> |
| |
| <p>Следует помнить, что {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} |
| создает каталог внутри каталога, который удаляется при удалении вашего приложения пользователем. |
| Если сохраняемые вами файлы должны оставаться доступными после удаления вашего |
| приложения пользователем — например, если ваше приложение работает с камерой, а пользователь хочет сохранить снимки, — вам |
| следует использовать {@link android.os.Environment#getExternalStoragePublicDirectory |
| getExternalStoragePublicDirectory()}.</p> |
| |
| |
| <p>Вне зависимости от того, используете ли вы {@link |
| android.os.Environment#getExternalStoragePublicDirectory |
| getExternalStoragePublicDirectory()} для общих файлов или |
| link android.content.Context#getExternalFilesDir |
| getExternalFilesDir()} для собственных файлов приложения, вы должны использовать имена каталогов, предоставляемые |
| постоянными значениями API-интерфейсов, например, |
| {@link android.os.Environment#DIRECTORY_PICTURES}. Эти имена каталогов обеспечивают |
| правильную обработку файлов системой. Например, сохраненные в {@link |
| android.os.Environment#DIRECTORY_RINGTONES} файлы относятся медиа-сканером системы в категорию рингтонов, |
| а не музыки.</p> |
| |
| |
| |
| |
| <h2 id="GetFreeSpace">Запрос доступного пространства</h2> |
| |
| <p>Если вам заранее известен объем сохраняемых данных, вы можете |
| определить наличие достаточного пространства без исключения {@link |
| java.io.IOException}, вызвав метод {@link java.io.File#getFreeSpace} или {@link |
| java.io.File#getTotalSpace}. Эти методы позволяют узнать текущее доступное пространство и |
| общее пространство в хранилище. Эта информация также позволять |
| избежать переполнения объема хранилища сверх определенного уровня.</p> |
| |
| <p>Однако система не гарантирует возможность записи такого же количества байт, как указано |
| в {@link java.io.File#getFreeSpace}. Если выводимое число на |
| несколько мегабайт превышает размер данных, которые вы хотите сохранить, или если файловая система заполнена |
| менее, чем на 90%, дальше можно действовать спокойно. |
| В противном случае запись в хранилище осуществлять нежелательно.</p> |
| |
| <p class="note"><strong>Примечание.</strong> Вам необязательно проверять объем доступного места |
| перед сохранением файла. Вы можете попробовать сразу записать файл, а затем |
| определить событие {@link java.io.IOException}, если оно возникнет. Это может потребоваться, |
| если вы точно не знаете, сколько нужно свободного места. Например, если вы |
| меняете кодировку файла перед сохранением при конвертации изображения PNG в формат |
| JPEG, вы не будете знать размер файла заранее.</p> |
| |
| |
| |
| |
| <h2 id="DeleteFile">Удаление файла</h2> |
| |
| <p>Ненужные файлы всегда следует удалять. Наиболее простой способ удалить |
| файл – вызвать в открытом файле ссылку {@link java.io.File#delete} на сам этот файл.</p> |
| |
| <pre> |
| myFile.delete(); |
| </pre> |
| |
| <p>Если файл сохранен во внутреннем хранилище, вы также можете запросить {@link android.content.Context}, чтобы найти и |
| удалить файл посредством вызова {@link android.content.Context#deleteFile deleteFile()}:</p> |
| |
| <pre> |
| myContext.deleteFile(fileName); |
| </pre> |
| |
| <div class="note"> |
| <p><strong>Примечание.</strong> При удалении пользователем вашего приложения система Android удаляет |
| следующие элементы:</p> |
| <ul> |
| <li>Все файлы, сохраненные во внутреннем хранилище</li> |
| <li>Все файлы, сохраненные во внешнем хранилище с использованием {@link |
| android.content.Context#getExternalFilesDir getExternalFilesDir()}.</li> |
| </ul> |
| <p>Однако вам следует регулярно вручную очищать кэш-память, чтобы удалить файлы, созданные с помощью |
| {@link android.content.Context#getCacheDir()}, а также удалять любые |
| другие ненужные файлы.</p> |
| </div> |
| |