Sådan låses en fil i Java

1. Oversigt

Når vi læser eller skriver filer, er vi nødt til at sikre, at de rette fillåsemekanismer er på plads. Dette sikrer dataintegritet i samtidige I / O-baserede applikationer.

I denne vejledning ser vi på forskellige tilgange for at opnå dette ved hjælp af Java NIO-biblioteket.

2. Introduktion til fillåse

Generelt er der to typer låse:

    • Eksklusive låse - også kendt som skrivelåse
    • Delt låse - også kaldet læselåse

Enkelt sagt forhindrer en eksklusiv lås alle andre operationer - inklusive læsninger - mens en skrivehandling er afsluttet.

Derimod tillader en delt lås, at mere end en proces kan læses på samme tid. Pointen med en læselås er at forhindre erhvervelse af en skrivelås ved en anden proces. Typisk skal en fil i en ensartet tilstand faktisk kunne læses af enhver proces.

I det næste afsnit vil vi se, hvordan Java håndterer disse typer låse.

3. Fillåser i Java

Java NIO-biblioteket muliggør låsning af filer på OS-niveau. Det låse() og tryLock () metoder til a FileChannel er til dette formål.

Vi kan oprette en FileChannel gennem enten a FileInputStream, a FileOutputStream, eller a RandomAccessFile. Alle tre har en getChannel () metode, der returnerer en FileChannel.

Alternativt kan vi oprette en FileChannel direkte via det statiske åben metode:

prøv (FileChannel channel = FileChannel.open (sti, openOptions)) {// skriv til kanalen}

Dernæst gennemgår vi forskellige muligheder for at få eksklusive og delte låse i Java. For at lære mere om filkanaler, se vores Guide til Java FileChannel tutorial.

4. Eksklusive låse

Som vi allerede har lært, mens du skriver til en fil, vi kan forhindre andre processer i at læse eller skrive til det ved hjælp af en eksklusiv lås.

Vi får eksklusive låse ved at ringe låse() eller tryLock () på den FileChannel klasse. Vi kan også bruge deres overbelastede metoder:

  • lås (lang position, lang størrelse, boolsk delt)
  • tryLock (lang position, lang størrelse, boolsk delt)

I disse tilfælde er delt parameter skal indstilles til falsk.

For at få en eksklusiv lås skal vi bruge en skrivbar FileChannel. Vi kan skabe det gennem getChannel () metoder til a FileOutputStream eller a RandomAccessFile. Alternativt kan vi som tidligere nævnt bruge det statiske åben metode til FileChannel klasse. Alt, hvad vi har brug for, er at indstille det andet argument til StandardOpenOption.APPEND:

prøv (FileChannel channel = FileChannel.open (sti, StandardOpenOption.APPEND)) {// skriv til kanal}

4.1. Eksklusive låse ved hjælp af en FileOutputStream

EN FileChannel oprettet fra en FileOutputStream er skrivbar. Vi kan derfor erhverve en eksklusiv lås:

prøv (FileOutputStream fileOutputStream = ny FileOutputStream ("/ tmp / testfile.txt"); FileChannel channel = fileOutputStream.getChannel (); FileLock lock = channel.lock ()) {// skriv til kanalen}

Her, channel.lock () vil enten blokere, indtil den får en lås, eller det vil kaste en undtagelse. For eksempel, hvis den angivne region allerede er låst, en OverlappingFileLockException kastes. Se Javadoc for en komplet liste over mulige undtagelser.

Vi kan også udføre en ikke-blokerende lås ved hjælp af channel.tryLock (). Hvis det ikke lykkes at få en lås, fordi et andet program indeholder en overlappende, vender det tilbage nul. Hvis det ikke gør det af anden grund, kastes en passende undtagelse.

4.2. Eksklusive låse ved hjælp af en RandomAccessFile

Med en RandomAccessFile, skal vi indstille flag på konstruktørens anden parameter.

Her åbner vi filen med læse- og skrivetilladelser:

prøv (RandomAccessFile fil = ny RandomAccessFile ("/ tmp / testfile.txt", "rw"); FileChannel channel = file.getChannel (); FileLock lock = channel.lock ()) {// skriv til kanalen} 

Hvis vi åbner filen i skrivebeskyttet tilstand og prøver at skrive til dens kanal, kaster den en NonWritableChannelException.

4.3. Eksklusive låse kræver en skrivbar FileChannel

Som nævnt før har eksklusive låse brug for en skrivbar kanal. Derfor kan vi ikke få en eksklusiv lås gennem en FileChannel oprettet fra en FileInputStream:

Sti sti = Files.createTempFile ("foo", "txt"); Logger log = LoggerFactory.getLogger (this.getClass ()); prøv (FileInputStream fis = ny FileInputStream (sti.tilFil ()); FileLock-lås = fis.getChannel (). lås ()) {// utilgængelig kode} fangst (NonWritableChannelException e) {// undtagelse af håndtag}

I eksemplet ovenfor er låse() metoden vil kaste en NonWritableChannelException. Faktisk er det fordi vi påberåber os getChannel på en FileInputStream, der opretter en skrivebeskyttet kanal.

Dette eksempel er bare for at demonstrere, at vi ikke kan skrive til en ikke-skrivbar kanal. I et virkeligt scenarie ville vi ikke fange og omlægge undtagelsen.

5. Delt låse

Husk, at delte låse også kaldes Læs låse. Derfor, for at få en læselås, skal vi bruge en læsbar FileChannel.

Sikken en FileChannel kan fås ved at ringe til getChannel () metode på en FileInputStream eller a RandomAccessFile. Igen er en anden mulighed at bruge det statiske åben metode til FileChannel klasse. I så fald sætter vi det andet argument til StandardOpenOption.READ:

prøv (FileChannel channel = FileChannel.open (sti, StandardOpenOption.READ); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// læses fra kanalen}

En ting at bemærke her er, at vi valgte at låse hele filen ved at ringe lås (0, Long.MAX_VALUE, true). Vi kunne også kun have låst en bestemt region af filen ved at ændre de to første parametre til forskellige værdier. Den tredje parameter skal indstilles til rigtigt i tilfælde af en delt lås.

For at gøre tingene enkle låser vi hele filen i alle eksemplerne nedenfor, men husk, at vi altid kan låse en bestemt region i en fil.

5.1. Delt låse ved hjælp af en FileInputStream

EN FileChannel opnået fra en FileInputStream er læselig. Vi kan derfor få en delt lås:

prøv (FileInputStream fileInputStream = ny FileInputStream ("/ tmp / testfile.txt"); FileChannel channel = fileInputStream.getChannel (); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// læses fra kanalen }

I uddraget ovenfor kaldes op til låse() på kanalen vil lykkes. Det skyldes, at en delt lås kun kræver, at kanalen er læsbar. Det er tilfældet her, da vi oprettede det fra en FileInputStream.

5.2. Delt låse ved hjælp af en RandomAccessFile

Denne gang kan vi åbne filen med bare Læs tilladelser:

prøv (RandomAccessFile fil = ny RandomAccessFile ("/ tmp / testfile.txt", "r"); FileChannel channel = file.getChannel (); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// læse fra kanalen}

I dette eksempel oprettede vi en RandomAccessFile med læsetilladelser. Vi kan oprette en læsbar kanal ud fra den og dermed oprette en delt lås.

5.3. Delte låse kræver en læsbar FileChannel

Af den grund kan vi ikke erhverve en delt lås gennem en FileChannel oprettet fra en FileOutputStream:

Sti sti = Files.createTempFile ("foo", "txt"); prøv (FileOutputStream fis = ny FileOutputStream (path.toFile ()); FileLock lock = fis.getChannel (). lock (0, Long.MAX_VALUE, true)) {// unreachable code} catch (NonWritableChannelException e) {// handle undtagelse} 

I dette eksempel kaldes til låse() forsøger at få en delt lås på en kanal oprettet fra en FileOutputStream. En sådan kanal er skrivebeskyttet. Det opfylder ikke behovet for, at kanalen skal være læsbar. Dette vil udløse en NonWritableChannelException.

Igen er dette uddrag kun for at demonstrere, at vi ikke kan læse fra en ikke-læsbar kanal.

6. Ting at overveje

I praksis er det vanskeligt at bruge fillåse; låsemekanismerne er ikke bærbare. Vi bliver nødt til at udforme vores låsningslogik med dette i tankerne.

I POSIX-systemer er låse rådgivende. Forskellige processer, der læser eller skriver til en given fil, skal være enige om en låseprotokol. Dette vil sikre filens integritet. OS selv håndhæver ikke nogen låsning.

På Windows er låse eksklusive, medmindre deling er tilladt. At diskutere fordele eller ulemper ved OS-specifikke mekanismer er uden for denne artikels anvendelsesområde. Alligevel er det vigtigt at kende disse nuancer, når du implementerer en låsemekanisme.

7. Konklusion

I denne vejledning har vi gennemgået flere forskellige muligheder for at få fillåse i Java.

Først startede vi med at forstå de to hovedlåsmekanismer, og hvordan Java NIO-biblioteket letter låsning af filer. Derefter gik vi gennem en række enkle eksempler, der viser, at vi kan få eksklusive og delte låse i vores applikationer. Vi kiggede også på de typer af typiske undtagelser, vi kan støde på, når vi arbejder med fillåse.

Som altid er kildekoden til eksemplerne tilgængelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found