Предотвратить гонку с файлами - PullRequest
3 голосов
/ 01 февраля 2020

Если я проверю, есть ли у меня права доступа к файлу, например, java.io.File#canRead(), и после этого создаю FileOutputStream, то (насколько я знаю) возможно, что другой процесс (например, chmod или mv) ) изменяет права доступа или переименовывает файл, удаляет его или переключает его с другим файлом.

Например, я хочу записать что-либо в файл, только если он исполняемый.

В C, такие условия гонки можно предотвратить с помощью FileDescriptor.

В Java есть класс java.io.FileDescriptor, но, похоже, этот класс предназначен только для синхронизации буферов и создания потоков, и я бы нужен File*Stream, чтобы получить FileDescriptor.

Как можно предотвратить это состояние гонки, например, с помощью FileDescriptor или другого механизма?

Или защищено File против этого каким-то образом?

1 Ответ

2 голосов
/ 01 февраля 2020

Вы можете изменить свой подход и использовать Java класс NIO API FileLock из пакета java.nio.channels. В соответствии с официальной документацией :

Этот API блокировки файлов предназначен для непосредственного сопоставления с собственными средствами блокировки базовой операционной системы. Таким образом, блокировки, хранящиеся в файле, должны быть видны всем программам, имеющим доступ к файлу, независимо от языка, на котором написаны эти программы.

private static FileChannel fc;
private static RandomAccessFile raFile;

public FileLockProcesser(final String fileName) throws FileNotFoundException {
    raFile = new RandomAccessFile(fileName, "rw");
}

public void lockedWrite(final String data) {
    fc = raFile.getChannel();
    ByteBuffer buffer = null;
    try (fc; raFile; FileLock fileLock = fc.tryLock()) {
        if (fileLock != null) {
            buffer = ByteBuffer.wrap(data.getBytes());
            buffer.put(data.toString().getBytes());
            buffer.flip();

            while (buffer.hasRemaining())
                fc.write(buffer);
        }
    } catch (OverlappingFileLockException | IOException ex) {
        ...
    }
}

Чтобы проверить разрешения, вы можете снова используйте NIO API. Пример:

import java.io.FileNotFoundException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public static void main(String[] args) {

    String filePath = args[0];  
    Path p = Paths.get(filePath);

    if (Files.notExists(p))
        throw new FileNotFoundException();

    if (Files.isWritable(p))
        ...

    if (Files.isReadable(p))
        ...

    if (Files.isExecutable(p))
        ...

}
...