libGDX приложения работают на различных платформах: Desktop системах (Windows, Linux, Mac OS X), Android и на JavaScript/WebGL возможных браузерах. Каждая из этих платформ работает с файлами немного по-разному.
В libGDX Files (код) модуль предоставляет следующие возможности:
- Чтение из файла
- Запись в файл
- Копирование файла
- Перемещение файла
- Удаление файла
- Выдача списка файлов и директорий
- Проверка существования файла/директории
Прежде чем погрузиться в аспекты libGDX, мы должны сначала рассмотреть различные понятия файловых систем для всех поддерживаемых платформ.
Файловые системы платформ
Здесь мы рассмотрим обзор парадигм файловых систем платформ, поддерживающихся в libGDX.
Desktop (Windows, Linux, Mac OS X)
На Desktop ОС, файловая система является одним большим куском памяти. Файлы могут быть доступны по относительному пути к рабочей директории (директории в которой запущено приложение) или абсолютному пути. При этом игнорируются права доступа, файлы и директории всегда доступны на чтение и запись для всех приложений.
Android
На Android ситуация немного сложнее. Файлы можно хранить внутри APK приложения, либо как ресурсы или asset. Эти файлы доступны только для чтения. libGDX использует только asset механизм, так как он предоставляет прямой доступ к байтовым потокам и более напоминает традиционную файловую систему. Ресурсы отлично предоставляются для обычных Android приложений, но вызывают проблемы при использовании в играх. Android совершает манипуляции во время их загрузки, например, автоматически изменяет размер.
Asset хранятся в assets
директории Android проекта и затем автоматически упаковываются в ваш APK файл при развертывании приложения. Ни одно другое
приложение не может получить доступ к этим файлам.
Файлы также могут храниться во внутренней памяти, где они доступны для чтения и записи. Каждое установленное приложение имеет специальную выделенную внутреннею директорию для хранения. Эта директория тоже доступна только для этого приложения. Вы можете думать о таком хранилище как о частном рабочем пространстве приложения.
Наконец, файлы можно хранить на внешнем накопителе данных, таком как SD карта. Внешние накопители не всегда могут быть доступны, например пользователь может вытащить SD карту. Файлы в этом месте хранения следует считать не всегда доступными. Чтобы иметь возможность записи на внешние накопители, вам нужно будет добавить разрешения в AndroidManifest.xml файл, смотрите разрешения ниже.
iOS
На iOS доступны все типы файлов.
Javascript/WebGL
Обычное Javascript/WebGL приложение не имеет традиционной концепции файловой системы. Вместо этого, assets подобны изображениям, ссылающимся на URL адреса, которые указывают на конкретные фалы одного или нескольких серверов. Современные браузеры поддерживают локальное хранилище данных, которое приближается к традиционным файловым системам с чтением и записью.
libGDX предоставляет абстракцию файловой системы, доступной только для чтения.
Типы (хранения) файлов
Файл в libGDX представлен экземпляром FileHandle класса. FileHandle имеет тип, который определяет где находится файл. Следующая таблица иллюстрирует наличие и местоположение каждого типа файла для каждой платформы.
Тип | Описание, путь файла и особенности | Desktop | Android | HTML5 | iOS |
---|---|---|---|---|---|
Classpath | Classpath файлы хранятся непосредственно в директории исходников. Они упакованы вместе с jar файлами и всегда доступны только для чтения. Они имеют свое назначение, но по возможности нужно избегать их использования. | Да | Да | Нет | Нет |
Внутренний | Внутренние файлы относятся к корневой или рабочей директории приложения на Desktop, к assets директории на
Android, и к war/assets/ директории GWT проекта. Эти файлы доступны только для чтения. Если файл не может быть найдет во
внутреннем хранилище, то файловый модуль возвращается к поиску файла в classpath. Это необходимо, если в Eclipse используется механизм ссылки на
asset директорию, смотрите настройку проекта.
|
Да | Да | Да | Да |
Локальный | Локальные файлы хранятся относительно корневой или рабочей директории на Desktop и относятся к внутреннему (частному) хранилищу приложений на Android. Обратите внимание, что локальный и внутренний тип в основном одно и то же для Dekstop. | Да | Да | Нет | Да |
Внешний | Пути к внешним файлом являются относительными корня SD карты на Android и домашней директории текущего пользователя на Desktop системах. | Да | Да | Нет | Да |
Абсолютный | Абсолютные файлы должны иметь полностью указанный путь. Примечание: Ради портативности, эта опция должна использоваться только в случае крайней необходимости |
Да | Да | Нет | Да |
Абсолютные и classpath файлы в основном используются для таких инструментов, как редакторы на Desktop, которые имеют более сложные требования файлового ввода/вывода. Для игр их можно спокойно игнорировать. Порядок, в котором вы должны использовать типы файлов выглядит следующим образом:
-
Внутренние файлы: все assets (изображения, аудио файлы и так далее), которые упакованные вместе с приложением являются внутренними
файлами. Если вы используете Setup UI, просто положите их в
assets
директорию Android проекта. - Локальные файлы: Если необходимо записывать небольшие файлы, например, сохранить состояние игры, используйте локальные файлы. В общем, они имеют частный доступ для вашего приложения. Если вы хотите использовать ключ/значение хранилище, то вам следует посмотреть настройки предпочтения.
- Внешние файлы: Если необходимо записывать большие файлы, например снимки экрана или скачивать файлы из интернета, то следует использовать внешние накопители. Обратите внимание, что внешний накопитель является не всегда доступным, пользователь может вынуть его или удалить файлы, которые вы записали.
Проверка наличия хранилища и путей
Различные типы хранилищ могут быть недоступны в зависимости от платформы, на которой запущено приложение. Вы можете запросить такую информацию через Files
модуль:
boolean isExtAvailable = Gdx.files.isExternalStorageAvailable(); boolean isLocAvailable = Gdx.files.isLocalStorageAvailable();
Можно также запросить корневой путь для внешнего и локального хранилища:
String extRoot = Gdx.files.getExternalStoragePath(); String locRoot = Gdx.files.getLocalStoragePath();
Получение дескриптора файла (FileHandles)
Получение FileHandle
используется одним из вышеупомянутых типов напрямую из Files
модуля. Следующий код получает дескриптор для внутреннего
myfile.txt файла.
FileHandle handle = Gdx.files.internal("data/myfile.txt");
Если вы использовали Setup UI, то этот файл будет содержаться в asset директории Android проекта, если точно, то в $ANDROID_PROJECT/assets/data
.
Ваши Desktop и HTML проекты в Eclipse ссылаются на эту директорию, и автоматически имеют к ней доступ.
FileHandle handle = Gdx.files.classpath("myfile.txt");
Файл "Myfile.txt" находится в каталоге, там же где скомпилированные классы или включенные jar файлы.
FileHandle handle = Gdx.files.external("myfile.txt");
В этом случае необходимо чтобы myfile.txt файл был в домашней директории пользователя (/home/<пользователь>/myfile.txt
на Linux или
\Users\<пользователь>\myfile.txt
на Windows и Mac OS) на Desktop и в корне SD-карты на Android.
FileHandle handle = Gdx.files.absolute("/some_dir/subdir/myfile.txt");
В случае абсолютного дескриптора файла, файл должен быть именно там, куда указывает путь. В /некоторая_директория/поддиректория/ текущего диска в Windows или точный путь для Linux, Mac OS и Android.
Экземпляры FileHandle
передаются методам соответствующих классов отвечающих за чтение и запись данных. Например, нужно указать FileHandle
для загрузки
изображение с помощью Texture класса или для загрузки аудио файла с помощью Audio
модуля.
Список файлов и проверка свойств
Иногда необходимо проверить конкретный файл на его наличие или просмотреть содержимое директории. FileHandle
предоставляет методы, чтобы сделать этот в
простой форме.
Вот пример, который проверяет существование конкретного файла и проверяет, является ли он директорией или нет:
boolean exists = Gdx.files.external("doitexist.txt").exists(); boolean isDirectory = Gdx.files.external("test/").isDirectory();
Просмотр списка директории столь же прост:
FileHandle[] files = Gdx.files.local("mylocaldir/").list(); for(FileHandle file: files) { // делаем что-нибудь интересное с файлом }
Просмотр внутренних каталогов
Просмотр списка внутренних каталогов не поддерживается на Desktop.
Можно также запросить родительскую директорию файла или создать FileHandle
для файла в родительской директории.
FileHandle parent = Gdx.files.internal("data/graphics/myimage.png").parent(); FileHandle child = Gdx.files.internal("data/sounds/").child("myaudiofile.mp3");
parent
будет указывать на data/graphics/
, child
будет указывать на data/sounds/myaudiofile.mp3
.
В FileHandle есть множество методов позволяющих проверять определенные атрибуты файла. Пожалуйста, для деталей обратитесь к Javadoc.
В HTML5 функции в основном нереализованные
На текущий момент функции в основном нереализованные на HTML5 back-end. Постарайтесь не полагаться на них, если целевым приложением будет HTML5.
Обработка ошибок
Некоторые операции с дескрипторами файлов могут быть неудачными. Для сигнала об ошибки применяются RuntimeException
исключения, вместо
проверяемых исключений. Причиной этого является то, что в 90% времени мы получаем доступ к файлам, и мы знаем что они существуют и доступны для
чтения, например внутренние файлы, упакованные вместе с приложением.
Чтение из файла
После получения FileHandle
, мы можем либо передать его в класс, который знает, как загружать содержимое из файла (например, изображение) либо читать его сами.
Последнее делается через любой из методов ввода в FileHandle
классе. В следующем примере показано, как загрузить текст из внутреннего файла:
FileHandle file = Gdx.files.internal("myfile.txt"); String text = file.readString();
Если у вас есть двоичные данные, вы можете легко загрузить файл в байтовый массив:
FileHandle file = Gdx.files.internal("myblob.bin"); byte[] bytes = file.readBytes();
Класс FileHandle
имеет гораздо больше методов чтения. Смотрите дополнительные сведения в
Javadoc.
Запись в файл
Как и для чтения файлов, FileHandle
предоставляет методы для записи в файл. Заметьте, что только локальные, внешние и абсолютные типы файлов поддерживаются
для записи в файл. Запись строки в файл работает следующим образом:
FileHandle file = Gdx.files.local("myfile.txt"); file.writeString("My god, it's full of stars", false);
Второй параметр метода FileHandle.WriteString()
указывает, должно ли содержимое быть добавлено к файлу. Если установлено значение false, то
текущее содержимое файла будут перезаписано.
Можно, конечно и записывать двоичные данные в файл:
FileHandle file = Gdx.files.local("myblob.bin"); file.writeBytes(new byte[] { 20, 3, -2, 10 }, false);
Есть много других методов в FileHandle
, которые облегчают запись различными способами, например использование OutputStream
. Смотрите дополнительные сведения
в Javadoc.
Удаление, копирование, переименование и перемещение файлов/директорий
Эти операции возможны только для типов файлов доступных для записи (локальных, внешних и абсолютных). Однако заметьте, что источником операции копирования
может быть FileHandle
доступный только для чтения. Несколько примеров:
FileHandle from = Gdx.files.internal("myresource.txt"); from.copyTo(Gdx.files.external("myexternalcopy.txt"); Gdx.files.external("myexternalcopy.txt").rename("mycopy.txt"); Gdx.files.external("mycopy.txt").moveTo(Gdx.files.local("mylocalcopy.txt")); Gdx.files.local("mylocalcopy.txt").delete();
Обратите внимание, что источником и приемником могут быть файлы или директории.
Более подробную информацию о доступных методах смотрите в FileHandle Javadoc.