Kako zaključati datoteku na Javi

1. Pregled

Tijekom čitanja ili pisanja datoteka moramo biti sigurni da postoje ispravni mehanizmi zaključavanja datoteka. To osigurava cjelovitost podataka u istodobnim I / O aplikacijama.

U ovom uputstvu ćemo pogledati razne pristupe kako bismo to postigli pomoću Java NIO knjižnice.

2. Uvod u zaključavanje datoteka

Općenito postoje dvije vrste brava:

    • Ekskluzivne brave - poznate i kao brave za pisanje
    • Dijeljene brave - također se nazivaju brave za čitanje

Jednostavno rečeno, ekskluzivna brava sprječava sve druge operacije - uključujući čitanje - dok se operacija pisanja dovršava.

Suprotno tome, zajedničko zaključavanje omogućuje istodobno čitanje više procesa. Svrha zaključavanja čitanja je spriječiti stjecanje zaključavanja upisa drugim postupkom. Tipično, datoteka u dosljednom stanju doista bi trebala biti čitljiva u bilo kojem postupku.

U sljedećem ćemo odjeljku vidjeti kako Java obrađuje ove vrste brava.

3. Zaključavanje datoteka u Javi

Java NIO knjižnica omogućuje zaključavanje datoteka na razini OS-a. The zaključaj () i tryLock () metode a FileChannel su u tu svrhu.

Možemo stvoriti FileChannel kroz bilo a FileInputStream, a FileOutputStream, ili a RandomAccessFile. Sva trojica imaju getChannel () metoda koja vraća a FileChannel.

Alternativno, možemo stvoriti FileChannel izravno putem statičkog otvorena metoda:

probajte (FileChannel channel = FileChannel.open (path, openOptions)) {// zapisivanje na kanal}

Zatim ćemo pregledati različite opcije za dobivanje ekskluzivnih i dijeljenih brava na Javi. Da biste saznali više o kanalima datoteka, pogledajte naš vodič za Java FileChannel vodič.

4. Ekskluzivne brave

Kao što smo već naučili, dok pišemo u datoteku, možemo spriječiti čitanje ili pisanje drugih procesa pomoću ekskluzivne brave.

Ekskluzivne brave dobivamo pozivom zaključaj () ili tryLock () na FileChannel razred. Također se možemo poslužiti njihovim preopterećenim metodama:

  • zaključavanje (dugi položaj, duga veličina, logička vrijednost dijeljena)
  • tryLock (duga pozicija, duga veličina, logička vrijednost podijeljena)

U tim slučajevima, podijeljeni parametar mora biti postavljen na lažno.

Da bismo dobili ekskluzivnu bravu, moramo upotrijebiti za pisanje FileChannel. Možemo ga stvoriti putem getChannel () metode a FileOutputStream ili a RandomAccessFile. Alternativno, kao što je prethodno spomenuto, možemo koristiti statički otvorena metoda FileChannel razred. Sve što trebamo je postaviti drugi argument na StandardOpenOption.APPEND:

probajte (FileChannel channel = FileChannel.open (path, StandardOpenOption.APPEND)) {// piši na kanal}

4.1. Ekskluzivne brave pomoću a FileOutputStream

A FileChannel stvorena iz a FileOutputStream je za pisanje. Stoga možemo dobiti ekskluzivnu bravu:

try (FileOutputStream fileOutputStream = new FileOutputStream ("/ tmp / testfile.txt"); FileChannel channel = fileOutputStream.getChannel (); FileLock lock = channel.lock ()) {// zapisivanje na kanal}

Ovdje, channel.lock () ili će blokirati dok ne dobije bravu ili će izbaciti iznimku. Na primjer, ako je navedeno područje već zaključano, prikazuje se OverlappingFileLockException baca se. Pogledajte Javadoc za cjelovit popis mogućih izuzetaka.

Također možemo izvršiti blokadu koja ne blokira pomoću channel.tryLock (). Ako ne uspije dobiti bravu jer drugi program sadrži preklapajuću, tada se vraća null. Ako to ne učini iz bilo kojeg drugog razloga, izbacuje se odgovarajuća iznimka.

4.2. Ekskluzivne brave pomoću a RandomAccessFile

S RandomAccessFile, trebamo postaviti zastavice na drugi parametar konstruktora.

Ovdje ćemo otvoriti datoteku s dozvolama za čitanje i pisanje:

try (RandomAccessFile file = new RandomAccessFile ("/ tmp / testfile.txt", "rw"); FileChannel channel = file.getChannel (); FileLock lock = channel.lock ()) {// zapisivanje na kanal} 

Ako datoteku otvorimo u načinu samo za čitanje i pokušamo upisati na njezin kanal, bacit će se NonWritableChannelException.

4.3. Ekskluzivne brave zahtijevaju mogućnost pisanja FileChannel

Kao što je već spomenuto, ekskluzivne brave trebaju kanal za pisanje. Stoga ne možemo dobiti ekskluzivnu bravu putem a FileChannel stvorena iz a FileInputStream:

Put puta = Files.createTempFile ("foo", "txt"); Logger log = LoggerFactory.getLogger (this.getClass ()); probajte (FileInputStream fis = novi FileInputStream (path.toFile ()); FileLock lock = fis.getChannel (). lock ()) {// nedostižni kôd} catch (NonWritableChannelException e) {// handle exception}

U gornjem primjeru, zaključaj () metoda će baciti a NonWritableChannelException. Doista, to je zato što se pozivamo getChannel na a FileInputStream, koji stvara kanal samo za čitanje.

Ovaj primjer samo pokazuje kako ne možemo pisati na nepisljivi kanal. U stvarnom scenariju ne bismo uhvatili i vratili iznimku.

5. Dijeljene brave

Zapamtite, zajedničke brave također se nazivaju čitati brave. Stoga, da bismo dobili bravu za čitanje, moramo koristiti čitljivo FileChannel.

Kao FileChannel može se dobiti pozivom na getChannel () metoda na a FileInputStream ili a RandomAccessFile. Opet, druga opcija je korištenje statičkog otvorena metoda FileChannel razred. U tom smo slučaju drugi argument postavili na StandardOpenOption.READ:

probajte (FileChannel channel = FileChannel.open (path, StandardOpenOption.READ); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// čitanje s kanala}

Ovdje treba napomenuti da smo odlučili zaključati cijelu datoteku pozivanjem zaključavanje (0, Long.MAX_VALUE, true). Također smo mogli zaključati samo određeno područje datoteke promjenom prva dva parametra u različite vrijednosti. Treći parametar mora biti postavljen na pravi u slučaju zajedničke brave.

Da bi stvari bile jednostavne, zaključat ćemo cijelu datoteku u svim primjerima u nastavku, ali imajte na umu da uvijek možemo zaključati određeno područje datoteke.

5.1. Dijeljene brave pomoću a FileInputStream

A FileChannel dobiven od a FileInputStream je čitljiv. Stoga možemo dobiti zajedničku bravu:

probajte (FileInputStream fileInputStream = new FileInputStream ("/ tmp / testfile.txt"); FileChannel channel = fileInputStream.getChannel (); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// čitanje s kanala }

U gornjem isječku, poziv na zaključaj () na kanalu će uspjeti. To je zato što zajedničko zaključavanje zahtijeva samo da kanal bude čitljiv. Ovdje je slučaj otkad smo ga stvorili iz FileInputStream.

5.2. Dijeljene brave pomoću a RandomAccessFile

Ovog puta datoteku možemo otvoriti samo čitati dozvole:

try (RandomAccessFile file = new RandomAccessFile ("/ tmp / testfile.txt", "r"); FileChannel channel = file.getChannel (); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// pročitajte s kanala}

U ovom smo primjeru stvorili RandomAccessFile s dopuštenjima za čitanje. Od njega možemo stvoriti čitljiv kanal i tako stvoriti zajedničku bravu.

5.3. Dijeljene brave zahtijevaju čitljivost FileChannel

Iz tog razloga ne možemo dobiti zajedničku bravu putem a FileChannel stvorena iz a FileOutputStream:

Put puta = Files.createTempFile ("foo", "txt"); try (FileOutputStream fis = new FileOutputStream (path.toFile ()); FileLock lock = fis.getChannel (). lock (0, Long.MAX_VALUE, true)) {// nedostižni kod} catch (NonWritableChannelException e) {// handle iznimka} 

U ovom primjeru, poziv na zaključaj () pokušava dobiti zajedničko zaključavanje na kanalu stvorenom od FileOutputStream. Takav je kanal samo za pisanje. Ne ispunjava potrebu da kanal mora biti čitljiv. Ovo će pokrenuti a NonWritableChannelException.

Opet, ovaj isječak želi samo pokazati da ne možemo čitati s nečitljivog kanala.

6. Stvari koje treba razmotriti

U praksi je teško koristiti brave datoteka; mehanizmi zaključavanja nisu prijenosni. Morat ćemo razviti svoju logiku zaključavanja imajući to na umu.

U POSIX sustavima brave su savjetodavne. Različiti procesi čitanja ili pisanja u određenu datoteku moraju se dogovoriti o protokolu zaključavanja. To će osigurati cjelovitost datoteke. Sam OS neće provesti zaključavanje.

Na sustavu Windows zaključavanje će biti ekskluzivno ako dijeljenje nije dopušteno. Rasprava o prednostima ili nedostacima mehanizama specifičnih za OS izvan je dosega ovog članka. Ipak, važno je znati ove nijanse prilikom primjene mehanizma zaključavanja.

7. Zaključak

U ovom smo uputstvu pregledali nekoliko različitih mogućnosti za dobivanje blokada datoteka u Javi.

Prvo smo započeli razumijevanjem dva glavna mehanizma zaključavanja i kako Java NIO knjižnica olakšava zaključavanje datoteka. Zatim smo prošetali kroz niz jednostavnih primjera koji pokazuju da u našim aplikacijama možemo dobiti ekskluzivne i zajedničke brave. Također smo pogledali tipične tipične iznimke na koje bismo mogli naići pri radu s bravama datoteka.

Kao i uvijek, izvorni kod za primjere dostupan je na GitHubu.


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