1. Обзор
В этом руководстве мы сосредоточимся на стандартных параметрах открытия, доступных для файлов в Java.
Мы рассмотрим перечисление StandardOpenOption , которое реализует интерфейс
OpenOption
и определяет эти стандартные параметры открытия.
2. Параметр OpenOption
В Java мы можем работать с файлами, используя NIO2 API, который содержит несколько служебных методов. Некоторые из этих методов используют необязательный параметр OpenOption
, который настраивает способ открытия или создания файла. Кроме того, если этот параметр не задан, он будет иметь значение по умолчанию, которое может быть разным для каждого из этих методов.
Тип перечисления StandardOpenOption
определяет стандартные параметры и реализует интерфейс OpenOption
.
Вот список поддерживаемых опций, которые мы можем использовать с перечислением StandardOpenOptions
:
WRITE
: открывает файл для записи.APPEND
: добавляет некоторые данные в файлTRUNCATE_EXISTING
: усекает файлCREATE_NEW
: создает новый файл и выдает исключение, если файл уже существует.CREATE
: открывает файл, если он существует, или создает новый файл, если он не существует.DELETE_ON_CLOSE
: удаляет файл после закрытия потокаSPARSE
: вновь созданный файл будет разреженным.SYNC
: сохраняет содержимое и метаданные синхронизированного файла.DSYNC
: сохраняет только содержимое синхронизированного файла.
В следующих разделах мы увидим примеры использования каждой из этих опций.
Чтобы избежать путаницы в пути к файлу, давайте получим дескриптор домашнего каталога пользователя, который будет действителен во всех операционных системах:
private static String HOME = System.getProperty("user.home");
3. Открытие файла для чтения и записи
Во- первых, если мы хотим создать новый файл, если он не существует, мы можем использовать опцию CREATE
:
@Test
public void givenExistingPath_whenCreateNewFile_thenCorrect() throws IOException {
assertFalse(Files.exists(Paths.get(HOME, "newfile.txt")));
Files.write(path, DUMMY_TEXT.getBytes(), StandardOpenOption.CREATE);
assertTrue(Files.exists(path));
}
Мы также можем использовать опцию CREATE_NEW,
которая создаст новый файл, если он не существует. Однако он выдаст исключение, если файл уже существует.
Во- вторых, если мы хотим открыть файл для чтения, мы можем использовать метод newInputStream(Path, OpenOption
...). Этот метод открывает файл для чтения и возвращает входной поток:
@Test
public void givenExistingPath_whenReadExistingFile_thenCorrect() throws IOException {
Path path = Paths.get(HOME, DUMMY_FILE_NAME);
try (InputStream in = Files.newInputStream(path); BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
String line;
while ((line = reader.readLine()) != null) {
assertThat(line, CoreMatchers.containsString(DUMMY_TEXT));
}
}
}
Обратите внимание, что мы не использовали опцию READ
, потому что она используется по умолчанию методом newInputStream
.
В- третьих, мы можем создать файл, добавить в файл или записать в файл с помощью метода newOutputStream(Path, OpenOption
...). Этот метод открывает или создает файл для записи и возвращает OutputStream
.
API создаст новый файл, если мы не укажем параметры открытия, а файл не существует. Однако, если файл существует, он будет усечен. Эта опция аналогична вызову метода с опциями CREATE
и TRUNCATE_EXISTING .
Давайте откроем существующий файл и добавим некоторые данные:
@Test
public void givenExistingPath_whenWriteToExistingFile_thenCorrect() throws IOException {
Path path = Paths.get(HOME, DUMMY_FILE_NAME);
try (OutputStream out = Files.newOutputStream(path, StandardOpenOption.APPEND, StandardOpenOption.WRITE)) {
out.write(ANOTHER_DUMMY_TEXT.getBytes());
}
}
4. Создание файла SPARSE
Мы можем указать файловой системе, что вновь созданный файл должен быть разреженным (файлы, содержащие пустые места, которые не будут записываться на диск).
Для этого мы должны использовать опцию SPARSE
с опцией CREATE_NEW
. Однако этот параметр будет проигнорирован, если файловая система не поддерживает разреженные файлы .
Давайте создадим разреженный файл:
@Test
public void givenExistingPath_whenCreateSparseFile_thenCorrect() throws IOException {
Path path = Paths.get(HOME, "sparse.txt");
Files.write(path, DUMMY_TEXT.getBytes(), StandardOpenOption.CREATE_NEW, StandardOpenOption.SPARSE);
}
5. Синхронизация файла
В перечислении StandardOpenOptions есть параметры
SYNC
и DSYNC
. Эти параметры требуют, чтобы данные записывались в файл синхронно в хранилище. Другими словами, они гарантируют, что данные не будут потеряны в случае сбоя системы .
Давайте добавим некоторые данные в наш файл и воспользуемся опцией SYNC
:
@Test
public void givenExistingPath_whenWriteAndSync_thenCorrect() throws IOException {
Path path = Paths.get(HOME, DUMMY_FILE_NAME);
Files.write(path, ANOTHER_DUMMY_TEXT.getBytes(), StandardOpenOption.APPEND, StandardOpenOption.WRITE, StandardOpenOption.SYNC);
}
Разница между SYNC
и DSYNC
заключается в том, что SYNC
синхронно сохраняет содержимое и метаданные файла в хранилище, а DSYNC синхронно
сохраняет в хранилище только содержимое файла .
6. Удаление файла после закрытия потока
Перечисление StandardOpenOptions
также предлагает полезную опцию, которая дает нам возможность уничтожить файл после закрытия потока. Это полезно, если мы хотим создать временный файл.
Давайте добавим некоторые данные в наш файл и воспользуемся опцией DELETE_ON_CLOSE
:
@Test
public void givenExistingPath_whenDeleteOnClose_thenCorrect() throws IOException {
Path path = Paths.get(HOME, EXISTING_FILE_NAME);
assertTrue(Files.exists(path)); // file was already created and exists
try (OutputStream out = Files.newOutputStream(path, StandardOpenOption.APPEND,
StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE)) {
out.write(ANOTHER_DUMMY_TEXT.getBytes());
}
assertFalse(Files.exists(path)); // file is deleted
}
7. Заключение
В этом руководстве мы рассмотрели доступные варианты открытия файлов в Java с использованием нового API файловой системы (NIO2), который был включен в состав Java 7.
Как обычно, исходный код со всеми примерами из руководства можно найти на Github .