Java를 사용하여 파일을 잠그는 방법 (가능한 경우)


121

FileReader를 사용하여 파일을 여는 Java 프로세스가 있습니다. 다른 (Java) 프로세스가이 파일을 열지 못하도록하거나 적어도 두 번째 프로세스에 파일이 이미 열려 있음을 알리려면 어떻게해야합니까? 파일이 열려 있으면 자동으로 두 번째 프로세스에서 예외가 발생합니까 (내 문제가 해결됨) 아니면 첫 번째 프로세스에서 일종의 플래그 또는 인수를 사용하여 명시 적으로 열어야합니까?

명확히하기 위해 :

폴더를 나열하고이를 처리하기 위해 목록의 각 파일을 여는 Java 앱이 있습니다. 각 파일을 차례로 처리합니다. 각 파일의 처리는 파일을 읽고 내용에 따라 계산하는 것으로 구성되며 약 2 분 정도 소요됩니다. 또한 동일한 작업을 수행하지만 파일에 쓰는 다른 Java 앱도 있습니다. 내가 원하는 것은 이러한 앱을 동시에 실행할 수 있으므로 시나리오가 이와 같이 진행되는 것입니다. ReadApp은 폴더를 나열하고 파일 A, B, C를 찾습니다. 파일 A를 열고 읽기를 시작합니다. WriteApp은 폴더를 나열하고 파일 A, B, C를 찾습니다. 파일 A를 열고 (예외 또는 어떤 방식 으로든) 열려있는 것을 확인하고 파일 B로 이동합니다. ReadApp은 파일 A를 완료하고 B로 계속합니다. 열려 있고 C로 계속됩니다. WriteApp이 t ReadApp이 동일한 파일을 읽는 동안 쓰거나 그 반대의 경우도 마찬가지입니다. 그들은 다른 과정입니다.


12
프로세스 중 (두 JVM) 또는 스레드 (동일 JVM)와 같이 '프로세스'를 의미합니까? 대답에 미치는 영향은 가장 중요합니다.
Stu Thompson

여기에 샘플 코드를 보여주는 솔루션을 확인하십시오 stackoverflow.com/a/58871479/5154619
다비 카 발칸 티

답변:


117

FileChannel.lock은 아마도 원하는 것입니다.

try (
    FileInputStream in = new FileInputStream(file);
    java.nio.channels.FileLock lock = in.getChannel().lock();
    Reader reader = new InputStreamReader(in, charset)
) {
    ...
}

(면책 조항 : 코드가 컴파일되지 않았으며 확실히 테스트되지 않았습니다.)

FileLock 에 대한 API 문서 의 "플랫폼 종속성"섹션을 참고하십시오 .


22
더 중요한 것은 JVM의 잠금이 단일 JVM 내에서 개별 스레드가 액세스하기 위해 파일을 잠그는 데 적합하지 않다는 것을 이해하는 것입니다.
Stu Thompson

11
쓰기 가능한 스트림 (예 :)이 필요합니다 FileOutputStream.
Javier

@ Javier 당신은? 나는 시도하지 않았다. API 문서에서 그것이 요구 사항이라고 말하는 것은 없습니다. FileOutputStreamA에 대한 많은 사용 될 수 없습니다 Reader.
Tom Hawtin-tackline apr

18
예, 시도했지만 배타적 잠금을 얻으려고 시도했지만 쓰기 액세스가 필요 NonWritableChannelException하기 때문에 던졌습니다 lock(). 입력 스트림 이있는 경우 lock(0L, Long.MAX_VALUE, false)공유 잠금을 획득하고 읽기 액세스 만 필요로하는 것을 사용할 수 있습니다. RandomAccessFile읽는 동안 배타적 잠금을 원할 경우 읽기-쓰기 모드 로 열린를 사용할 수도 있지만 동시 읽기를 금지합니다.
Javier

6
나는 당신이 말하는 뜻은 생각 @Javier lock(0L, Long.MAX_VALUE, true)하지 lock(0L, Long.MAX_VALUE, false). 마지막 인수가 boolean shared docs.oracle.com/javase/8/docs/api/java/nio/channels/...
존 설리반

60

java.io패키지 의 클래스를 사용하지 말고 대신 package를 사용하십시오 java.nio. 후자는 FileLock수업이 있습니다. 에 잠금을 적용 할 수 있습니다 FileChannel.

 try {
        // Get a file channel for the file
        File file = new File("filename");
        FileChannel channel = new RandomAccessFile(file, "rw").getChannel();

        // Use the file channel to create a lock on the file.
        // This method blocks until it can retrieve the lock.
        FileLock lock = channel.lock();

        /*
           use channel.lock OR channel.tryLock();
        */

        // Try acquiring the lock without blocking. This method returns
        // null or throws an exception if the file is already locked.
        try {
            lock = channel.tryLock();
        } catch (OverlappingFileLockException e) {
            // File is already locked in this thread or virtual machine
        }

        // Release the lock - if it is not null!
        if( lock != null ) {
            lock.release();
        }

        // Close the file
        channel.close();
    } catch (Exception e) {
    }

btw, 나는이 팁 stackoverflow.com/a/35885/1422630 에서 현재 pid를 잠금 파일에 쓰고 있으므로 새 인스턴스에서 읽을 수 있습니다!
Aquarius Power

1
이것은 좋아 보였지만 작동하지 않습니다. 나는 파일도 exsist하지 않았다 때에도은 OverlappingFileLockException마다 시간을 얻을
Gavriel

1
이 예에서 기록 된대로 당신은 잠금 후 설정된 tryLock를 호출하는 경우 문제가 발생합니다
이고르 부코 비치를

17

Java NIO ( JDK 1.4 이상 )를 사용할 수 있다면 다음을 찾고 있다고 생각합니다.java.nio.channels.FileChannel.lock()

FileChannel.lock ()


5
아마도. OP가 '프로세스'가 의미하는 바에 따라 다릅니다. "파일 잠금은 전체 Java 가상 머신을 대신하여 유지됩니다. 동일한 가상 머신 내에서 여러 스레드가 파일에 대한 액세스를 제어하는 ​​데 적합하지 않습니다."
Stu Thompson

@Stu : 나는 당신이 오래 전에이 질문에 대답했다는 것을 알고 있지만, 당신이 말했을 때 의미하는 바를 자세히 설명 할 수 있기를 바랍니다File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine
Thang Pham

3
@Harry He는 다음 문서에서 인용하고 있습니다. download.oracle.com/javase/6/docs/api/java/nio/channels/… 이는 스레드에 보이지 않지만 다른 프로세스에 영향을 미친다는 것을 의미합니다.
Artur Czajka 2011

@Harry : 이러한 necro-comments에 더 많은 것을 추가하려면 Tomcat으로 웹 사이트를 제공하기 위해 Java를 사용한다고 상상해보십시오. 많은 스레드가있을 수 있으며 각 스레드는 웹 브라우저에서 하나의 요청을 제공합니다. 그러나 그들은 모두 부엌에서 너무 많은 요리사와 같은 동일한 파일 잠금 메커니즘을 제어합니다. 하나의 요청이 두 번째 요청 중간에 완료 될 수 있으며, 사용자가 여전히 작업 중에있는 동안 갑자기 파일이 "잠금 해제"된 다음 cronjob과 같은 다른 프로세스가 파일을 잠글 수 있으며 예기치 않게 파일을 잃었습니다. 잠금 및 요청은 ... 마칠 수 없습니다
다리 엔


5

이것은 당신이 찾고있는 것이 아닐 수도 있지만 다른 각도에서 문제를 제기하기 위해 ....

동일한 애플리케이션에서 동일한 파일에 액세스하려는이 두 Java 프로세스가 있습니까? 아마도 단일 동기화 방법을 통해 파일에 대한 모든 액세스를 필터링 할 수 있습니까 (또는 더 나은 방법은 JSR-166 사용 )? 이렇게하면 파일에 대한 액세스를 제어 할 수 있으며 액세스 요청을 대기열에 넣을 수도 있습니다.


3
두 프로세스는 동기화를 사용할 수 없으며 동일한 프로세스에서 두 개의 스레드 만 사용할 수 있습니다.
Marquis of Lorne

3

RandomAccessFile을 사용하여 채널을 가져온 다음 lock ()을 호출하십시오. 입력 또는 출력 스트림에서 제공하는 채널에 제대로 잠글 수있는 충분한 권한이 없습니다. finally 블록에서 unlock ()을 호출해야합니다 (파일을 닫아도 반드시 잠금이 해제되는 것은 아닙니다).


자세히 설명 할 수 있습니까? 확장 된 것은 RandomAccess File의 잠금이 스트림 1보다 낫거나 더 안전하다는 것입니다
Paralife

아래에 게시 된 간단한 예제에 대한 링크
Touko 2009-08-27

Paralife-지연되어 죄송합니다-방금 귀하의 질문을 발견했습니다. 스트림의 잠금은 읽기 잠금 (입력 스트림의 경우)과 배타적 전체 채널 쓰기 잠금 (출력 스트림의 경우)이됩니다. 내 경험에 따르면 RAF의 잠금은 더 세밀한 제어를 허용합니다 (즉, 파일의 일부를 잠글 수 있음).
Kevin Day

1

다음은 JVM이 처리 할 때까지 파일을 잠그는 샘플 스 니펫 코드입니다.

 public static void main(String[] args) throws InterruptedException {
    File file = new File(FILE_FULL_PATH_NAME);
    RandomAccessFile in = null;
    try {
        in = new RandomAccessFile(file, "rw");
        FileLock lock = in.getChannel().lock();
        try {

            while (in.read() != -1) {
                System.out.println(in.readLine());
            }
        } finally {
            lock.release();
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.