Útmutató a Java FileChannelhez

1. Áttekintés

Ebben a gyors bemutatóban megnézzük a FileChannel osztályban biztosított Java NIO könyvtár. Megbeszéljük hogyan lehet adatokat olvasni és írni FileChannel és ByteBuffer.

Megvizsgáljuk a használat előnyeit is FileChannel és néhány más fájlkezelési funkciója.

2. A. Előnyei FileChannel

A. Előnyei FileChannel tartalmazza:

  • Olvasás és írás fájlban egy adott helyen
  • A fájl egy szakaszának betöltése a memóriába, ami hatékonyabb lehet
  • Gyorsabb sebességgel továbbíthatjuk a fájladatokat egyik csatornáról a másikra
  • Zárolhatunk egy fájl egy részét, hogy korlátozzuk a hozzáférést más szálakhoz
  • Az adatvesztés elkerülése érdekében kényszeríthetjük a fájl frissítéseinek azonnali tárolására

3. Olvasás vele FileChannel

FileChannel gyorsabban teljesít, mint a szokásos I / O, ha nagy fájlt olvasunk.

Meg kell jegyeznünk, hogy bár a Java NIO, FileChannel a műveletek blokkolják és nem rendelkezik nem blokkoló üzemmóddal.

3.1. Fájl olvasása a FileChannel

Értsük meg, hogyan kell egy fájlt elolvasni FileChannel fájlon, amely a következőket tartalmazza:

Helló Világ

Ez a teszt elolvassa a fájlt, és ellenőrzi, hogy rendben van-e:

@Test public void givenFile_whenReadWithFileChannelUsingRandomAccessFile_thenCorrect () dobja az IOException {próbálkozzon (RandomAccessFile olvasó = új RandomAccessFile ("src / test / erőforrások / test_read.in", "r"); FileChannel csatorna = olvasó )) {int bufferSize = 1024; if (bufferSize> channel.size ()) {bufferSize = (int) channel.size (); } ByteBuffer buff = ByteBuffer.allocate (bufferSize); while (csatorna.olvasott (buff)> 0) {out.write (buff.array (), 0, buff.position ()); buff.clear (); } String fileContent = új karakterlánc (out.toByteArray (), StandardCharsets.UTF_8); assertEquals ("Hello world", fileContent); }}

Itt bájtokat olvasunk a fájlból a FileChannel, RandomAccessFile, és ByteBuffer.

Azt is meg kell jegyeznünk több egyidejű szál használható FileChannels biztonságosan. Ugyanakkor egyszerre csak egy szál engedélyezett olyan művelet, amely magában foglalja a csatorna helyzetének frissítését vagy a fájlméret megváltoztatását. Ez megakadályozza, hogy más szálak hasonló műveletet kíséreljenek meg, amíg az előző művelet be nem fejeződik.

A kifejezett csatornapozíciókat biztosító műveletek azonban blokkolás nélkül egyidejűleg is futhatnak.

3.2. Nyitás a FileChannel

A fájl használatával a FileChannel, ki kell nyitnunk.

Nézzük meg, hogyan lehet megnyitni a FileChannel felhasználásával RandomAccessFile:

RandomAccessFile reader = új RandomAccessFile (fájl, "r"); FileChannel csatorna = reader.getChannel ();

Az „r” mód azt jelzi, hogy a csatorna „csak olvasásra van nyitva”. Meg kell jegyeznünk, hogy a záró a RandomAccessFile bezárja a társított csatornát is.

Ezután meglátjuk a FileChannel fájl használatával FileInputStream:

FileInputStream fin = új FileInputStream (fájl); FileChannel csatorna = fin.getChannel ();

Hasonlóképpen a FileInputStream bezárja a hozzá tartozó csatornát is.

3.3. Adatok olvasása a FileChannel

Az adatok kiolvasásához használhatjuk a olvas mód.

Lássuk, hogyan olvassuk el a bájtsort. Használjuk a ByteBuffer az adatok tárolásához:

ByteBuffer buff = ByteBuffer.allocate (1024); int noOfBytesRead = csatorna.olvasott (buff); String fileContent = új karakterlánc (buff.array (), StandardCharsets.UTF_8); assertEquals ("Hello world", fileContent);

Ezután meglátjuk, hogyan olvassuk el a bájtsorozatot, egy fájl helyzetétől kezdve:

ByteBuffer buff = ByteBuffer.allocate (1024); int noOfBytesRead = channel.read (buff, 5); String fileContent = új karakterlánc (buff.array (), StandardCharsets.UTF_8); assertEquals ("világ", fileContent);

Meg kell jegyeznünk a Charset hogy dekódoljon egy bájt tömböt Húr.

Megadjuk a Charset amellyel a bájtokat eredetileg kódolták. Nélküle, zűrzavaros szöveget eredményezhetünk. Különösen a többbájtos kódolások, mint a UTF-8 és UTF-16 lehet, hogy nem tudja dekódolni a fájl tetszőleges szakaszát, mivel a több bájtos karakterek egy része hiányos lehet.

4. Írás vele FileChannel

4.1. Írása fájlba a következővel: FileChannel

Fedezzük fel, hogyan kell írni FileChannel:

@Test public void, amikor aWriteWithFileChannelUsingRandomAccessFile_thenCorrect () dobja az IOException {String file = "src / test / resources / test_write_using_filechannel.txt" parancsot; próbáld (RandomAccessFile író = új RandomAccessFile (fájl, "rw"); FileChannel csatorna = író.getChannel ()) {ByteBuffer buff = ByteBuffer.wrap ("Hello world" .getBytes (StandardCharsets.UTF_8)); channel.write (buff); // RandomAccessFile olvasó ellenőrzése = new RandomAccessFile (fájl, "r"); assertEquals ("Hello world", reader.readLine ()); olvasó.zárja (); }}

4.2. Nyitás a FileChannel

A fájl használatával a FileChannel, ki kell nyitnunk.

Nézzük meg, hogyan lehet megnyitni a FileChannel felhasználásával RandomAccessFile:

RandomAccessFile író = új RandomAccessFile (fájl, "rw"); FileChannel csatorna = író.getChannel ();

Az „rw” mód azt jelzi, hogy a csatorna „nyitott olvasásra és írásra”.

Lássuk azt is, hogyan lehet megnyitni a FileChannel felhasználásával FileOutputStream:

FileOutputStream fout = új FileOutputStream (fájl); FileChannel csatorna = fout.getChannel (); 

4.3. Adatok írása a következővel: FileChannel

Adatok írása a FileChannel, használhatjuk a ír mód.

Lássuk, hogyan írhatunk bájtsorozatot az a használatával ByteBuffer az adatok tárolásához:

ByteBuffer buff = ByteBuffer.wrap ("Hello world" .getBytes (StandardCharsets.UTF_8)); channel.write (buff); 

Ezután meglátjuk, hogyan kell írni egy bájtsorozatot, egy fájl helyzetétől kezdve:

ByteBuffer buff = ByteBuffer.wrap ("Hello world" .getBytes (StandardCharsets.UTF_8)); channel.write (buff, 5); 

5. Jelenlegi helyzet

FileChannel lehetővé teszi számunkra, hogy megszerezzük és megváltoztassuk azt a pozíciót, amelyen olvasunk vagy írunk.

Lássuk, hogyan kaphatjuk meg az aktuális pozíciót:

hosszú eredetiPosition = channel.position ();

Ezután nézzük meg, hogyan állítsuk be a pozíciót:

csatorna.helyzet (5); assertEquals (eredetiPozíció + 5, csatorna.pozíció ());

6. Szerezze meg a fájl méretét

Lássuk, hogyan kell használni a FileChannel.size módszer a fájl méretének bájtokban történő megszerzésére:

@Test public void, amikor a GETFileSize_thenCorrect () az IOException-t dobja {RandomAccessFile reader = new RandomAccessFile ("src / test / resources / test_read.in", "r"); FileChannel csatorna = reader.getChannel (); // az eredeti fájlméret 11 bájt. assertEquals (11, channel.size ()); csatorna.zár (); olvasó.zárja (); }

7. Csonkoljon meg egy fájlt

Értsük meg, hogyan kell használni a FileChannel.truncate módszer egy fájl bájtban megadott méretre csonkolásához:

@Test public void, amikor aTruncateFile_thenCorrect () IOException-t dob ​​{String input = "ez egy tesztbevitel"; FileOutputStream fout = új FileOutputStream ("src / test / resources / test_truncate.txt"); FileChannel csatorna = fout.getChannel (); ByteBuffer buff = ByteBuffer.wrap (input.getBytes ()); channel.write (buff); buff.flip (); csatorna = channel.truncate (5); assertEquals (5, channel.size ()); fout.close (); csatorna.zár (); } 

8. Kényszerítse a fájlfrissítést a tárolóba

Az operációs rendszer teljesítmény okokból gyorsítótárba helyezheti a fájlokat, és a rendszer összeomlása esetén elveszhetnek az adatok. A fájl tartalmának és metaadatainak folyamatos lemezre írására kényszerítésére használhatjuk a Kényszerítés módszer:

channel.force (true);

Ez a módszer csak akkor garantált, ha a fájl helyi eszközön található.

9. Töltse be a fájl egy részét a memóriába

Lássuk, hogyan tölthetünk be egy fájl egy részét a memóriába a segítségével FileChannel.map. Használunk FileChannel.MapMode.READ_ONLY a fájl írásvédett módban történő megnyitásához:

@Test public void givenFile_whenReadAFileSectionIntoMemoryWithFileChannel_thenCorrect () dobja az IOException {try (RandomAccessFile olvasó = új RandomAccessFile ("src / test / resources / test_read.in", "r"); FileChannel csatorna = olvasó )) {MappedByteBuffer buff = channel.map (FileChannel.MapMode.READ_ONLY, 6, 5); if (buff.hasRemaining ()) {byte [] data = új byte [buff.remaining ()]; buff.get (adatok); assertEquals ("világ", új String (adatok, StandardCharsets.UTF_8)); }}}

Hasonlóképpen használhatjuk FileChannel.MapMode.READ_WRITE a fájl olvasási és írási módba történő megnyitásához.

Használhatjuk isFileChannel.MapMode.PRIVATE mód, ahol a változtatások nem vonatkoznak az eredeti fájlra.

10. Zárolja le a fájl egy részét

Tisztázzuk, hogyan zárolhatunk egy fájl egy szakaszát, hogy megakadályozzuk a szakasz egyidejű hozzáférését a FileChannel.tryLock módszer:

@Test public void givenFile_whenWriteAFileUsingLockAFileSectionWithFileChannel_thenCorrect () dobja az IOException {try (RandomAccessFile olvasó = új RandomAccessFile ("src / teszt / erőforrások / test_read.in", "rw"); FileChannel csatorna.olvasó (6, 5, Boolean.FALSE)) {// egyéb műveletek végrehajtása ... assertNotNull (fileLock); }}

A tryLock metódus megpróbálja megszerezni a fájlrész zárját. Ha a kért fájlszakaszt már letiltotta egy másik szál, akkor egy ÁtfedőFileLockException kivétel. Ez a módszer a logikai paraméter egy megosztott zár vagy egy kizárólagos zár kérésére.

Meg kell jegyeznünk, hogy egyes operációs rendszerek nem engedélyezik a megosztott zárolást, ehelyett alapértelmezés szerint egy kizárólagos zárat használnak.

11. Zárás a FileChannel

Végül, ha elkészültünk az a használatával FileChannel, be kell zárnunk. Példáinkban használtuk erőforrásokkal próbálkozzon.

Ha szükséges, bezárhatjuk a FileChannel közvetlenül a Bezárás módszer:

csatorna.zár ();

12. Következtetés

Ebben az oktatóanyagban láttuk hogyan kell használni FileChannel fájlok olvasására és írására. Ezen felül megvizsgáltuk a fájlméret és annak jelenlegi olvasási / írási helyének olvasási és módosítási módját, valamint megvizsgáltuk a használat módját FileChannels egyidejű vagy adatkritikus alkalmazásokban.

Mint mindig, a példák forráskódja elérhető a GitHubon.


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