Работа с USB накопителями в Delphi для Android: создание подпапок и запись файлов
Введение
В современных Android приложениях часто возникает необходимость работы с внешними накопителями, такими как USB флешки. Однако, в отличие от Windows, в Android эта задача не так тривиальна из-за системы разрешений и Storage Access Framework (SAF). В этой статье я расскажу, как реализовать создание подпапки и запись файлов на USB накопитель в Delphi-приложении для Android.
Проблема
Как отметил пользователь steve.b на форуме, основная сложность заключается в:
1. Получении URI для корня USB накопителя
2. Создании подпапки по указанному URI
3. Записи файлов в созданную подпапку
В Windows это делается простыми функциями работы с файлами, но в Android требуется использовать специальные API.
Решение
1. Подготовка проекта
Сначала убедитесь, что в вашем проекте включены необходимые разрешения. В файле AndroidManifest.xml добавьте:
Вы уже получили URI вида "content://com.android.externalstorage.documents/tree/A8AC-5853%3A". Это хорошая отправная точка.
3. Создание подпапки
Для работы с SAF в Delphi мы будем использовать JNI (Java Native Interface). Вот функция для создания подпапки:
uses
Androidapi.JNI.GraphicsContentViewText,
Androidapi.JNI.Net,
Androidapi.JNI.JavaTypes,
Androidapi.Helpers,
Androidapi.JNIBridge;
function CreateSubfolderInUSB(RootUri: JString; SubfolderName: JString): JString;
var
DocumentsContract: JDocumentsContract;
ContentResolver: JContentResolver;
DocumentFile: JDocumentFile;
NewFolderUri: Jnet_Uri;
begin
DocumentsContract := TJDocumentsContract.JavaClass;
ContentResolver := TAndroidHelper.Context.getContentResolver;
// Получаем DocumentFile для корневого URI
DocumentFile := TJDocumentFile.JavaClass.fromTreeUri(
TAndroidHelper.Context,
TJnet_Uri.JavaClass.parse(RootUri)
);
// Создаем подпапку
NewFolderUri := DocumentsContract.createDocument(
ContentResolver,
DocumentFile.getUri,
TJDocumentsContract.JavaClass.Document.MIME_TYPE_DIR,
SubfolderName
);
if NewFolderUri <> nil then
Result := NewFolderUri.toString
else
Result := '';
end;
4. Запись файлов в подпапку
После создания подпапки можно записывать в нее файлы. Вот пример для XML-файла:
procedure WriteXmlToSubfolder(SubfolderUri: JString; FileName: JString; XmlContent: JString);
var
ContentResolver: JContentResolver;
DocumentFile: JDocumentFile;
OutputStream: JOutputStream;
Pfd: JParcelFileDescriptor;
Uri: Jnet_Uri;
begin
Uri := TJnet_Uri.JavaClass.parse(SubfolderUri);
DocumentFile := TJDocumentFile.JavaClass.fromTreeUri(TAndroidHelper.Context, Uri);
// Создаем файл в подпапке
Uri := TJDocumentsContract.JavaClass.createDocument(
TAndroidHelper.Context.getContentResolver,
DocumentFile.getUri,
'text/xml',
FileName
);
if Uri <> nil then
begin
try
ContentResolver := TAndroidHelper.Context.getContentResolver;
Pfd := ContentResolver.openFileDescriptor(Uri, 'w');
OutputStream := TJFileOutputStream.JavaClass.init(Pfd.getFileDescriptor);
OutputStream.write(StringToJByteArray(XmlContent));
OutputStream.close;
except
on E: Exception do
Log.d('Error writing file: ' + E.Message);
end;
end;
end;
5. Пример использования
var
RootUri, SubfolderUri: JString;
ConfigXml, SettingsXml: JString;
begin
// URI корня USB накопителя (полученный ранее)
RootUri := StringToJString('content://com.android.externalstorage.documents/tree/A8AC-5853%3A');
// Создаем подпапку "MyAppConfig"
SubfolderUri := CreateSubfolderInUSB(RootUri, StringToJString('MyAppConfig'));
if SubfolderUri <> '' then
begin
// Подготавливаем XML-содержимое
ConfigXml := StringToJString('<?xml version="1.0"?><config><param1>value1</param1></config>');
SettingsXml := StringToJString('<?xml version="1.0"?><settings><option>enabled</option></settings>');
// Записываем файлы
WriteXmlToSubfolder(SubfolderUri, StringToJString('config.xml'), ConfigXml);
WriteXmlToSubfolder(SubfolderUri, StringToJString('settings.xml'), SettingsXml);
end;
end;
Альтернативное решение
Если вам нужно более простое решение и ваше приложение ориентировано только на устройства с API < 29, можно использовать традиционный доступ к файловой системе:
Однако это решение не будет работать на новых версиях Android из-за ограничений доступа к внешнему хранилищу.
Заключение
Работа с USB накопителями в Android через Storage Access Framework действительно сложнее, чем в Windows, но вполне реализуема в Delphi. Представленные примеры кода помогут вам:
1. Создавать подпапки на USB накопителе
2. Записывать XML-файлы с конфигурацией
3. Обрабатывать возможные ошибки
Для более сложных сценариев рекомендуется изучить официальную документацию Android по Storage Access Framework и дополнительные примеры работы с JNI в Delphi.
Статья описывает реализацию работы с USB-накопителями в Delphi для Android, включая создание подпапок и запись файлов с использованием Storage Access Framework.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.