Sprievodca po Java FileChannel

1. Prehľad

V tomto rýchlom výučbe sa pozrieme na FileChannel trieda uvedená v Java NIO knižnica. Budeme diskutovať ako čítať a zapisovať dáta pomocou FileChannel a ByteBuffer.

Preskúmame tiež výhody používania FileChannel a niektoré ďalšie jeho funkcie na manipuláciu so súbormi.

2. Výhody FileChannel

Výhody FileChannel zahŕňajú:

  • Čítanie a zápis na konkrétnom mieste v súbore
  • Načítanie časti súboru priamo do pamäte, čo môže byť efektívnejšie
  • Môžeme prenášať údaje súborov z jedného kanála do druhého rýchlejším tempom
  • Časť súboru môžeme uzamknúť, aby sme obmedzili prístup iným vláknam
  • Aby sme sa vyhli strate údajov, môžeme vynútiť okamžité ukladanie aktualizácií do súboru

3. Čítanie s FileChannel

FileChannel pracuje rýchlejšie ako štandardné I / O, keď čítame veľký súbor.

Mali by sme poznamenať, že hoci je súčasťou Java NIO, FileChannel operácie blokujú a nemajú neblokujúci režim.

3.1. Čítanie súboru pomocou FileChannel

Poďme pochopiť, ako čítať súbor pomocou FileChannel v súbore, ktorý obsahuje:

Ahoj svet

Tento test načíta súbor a skontroluje, či bol načítaný v poriadku:

@Test public void givenFile_whenReadWithFileChannelUsingRandomAccessFile_thenCorrect () vyvolá IOException {try (RandomAccessFile reader = new RandomAccessFile ("src / test / resources / test_read.in", "r"); FileChannel kanál = reader.getChannel (); ByArte = )) {int bufferSize = 1024; if (bufferSize> channel.size ()) {bufferSize = (int) channel.size (); } ByteBuffer buff = ByteBuffer.allocate (bufferSize); while (channel.read (buff)> 0) {out.write (buff.array (), 0, buff.position ()); buff.clear (); } String fileContent = nový String (out.toByteArray (), StandardCharsets.UTF_8); assertEquals ("Hello world", fileContent); }}

Tu načítame bajty zo súboru pomocou FileChannel, RandomAccessFilea ByteBuffer.

Mali by sme si to tiež uvedomiť môže používať viac súbežných vlákien FileChannels bezpečne. Avšak vždy je povolené iba jedno vlákno, operácia zahŕňajúca aktualizáciu polohy kanála alebo zmenu jeho veľkosti súboru. Toto blokuje ďalšie vlákna pokúšajúce sa o podobnú operáciu, kým sa nedokončí predchádzajúca operácia.

Avšak operácie, ktoré poskytujú explicitné pozície kanálov, môžu bežať súčasne bez blokovania.

3.2. Otvorenie a FileChannel

Aby bolo možné prečítať súbor pomocou FileChannel, musíme to otvoriť.

Pozrime sa, ako otvoriť a FileChannel použitím RandomAccessFile:

Čítačka RandomAccessFile = nový RandomAccessFile (súbor, "r"); Kanál FileChannel = reader.getChannel ();

Režim „r“ označuje, že kanál je „otvorený iba na čítanie“. Mali by sme poznamenať, že uzavretie a RandomAccessFile tiež zatvorí súvisiaci kanál.

Ďalej uvidíme otvorenie a FileChannel na čítanie súboru pomocou FileInputStream:

FileInputStream fin = nový FileInputStream (súbor); Kanál FileChannel = fin.getChannel ();

Podobne aj zatváranie a FileInputStream tiež zatvorí kanál s ním spojený.

3.3. Čítanie údajov z a FileChannel

Na čítanie údajov môžeme použiť jednu z čítať metódy.

Pozrime sa, ako čítať postupnosť bajtov. Použijeme a ByteBuffer uchovať údaje:

ByteBuffer buff = ByteBuffer.allocate (1024); int noOfBytesRead = channel.read (buff); String fileContent = new String (buff.array (), StandardCharsets.UTF_8); assertEquals ("Hello world", fileContent);

Ďalej uvidíme, ako čítať postupnosť bajtov, počnúc pozíciou súboru:

ByteBuffer buff = ByteBuffer.allocate (1024); int noOfBytesRead = channel.read (buff, 5); String fileContent = new String (buff.array (), StandardCharsets.UTF_8); assertEquals ("svet", fileContent);

Mali by sme si uvedomiť potrebu a Charset na dekódovanie bajtového poľa do String.

Zadávame Charset pomocou ktorého boli bajty pôvodne kódované. Bez toho, môžeme skončiť so skomoleným textom. Najmä viacbajtové kódovanie ako UTF-8 a UTF-16 nemusí byť schopný dekódovať ľubovoľnú časť súboru, pretože niektoré z viacbajtových znakov môžu byť neúplné.

4. Písanie s FileChannel

4.1. Zápis do súboru pomocou FileChannel

Poďme preskúmať, ako písať pomocou FileChannel:

@ Test public void whenWriteWithFileChannelUsingRandomAccessFile_thenCorrect () vyvolá IOException {String file = "src / test / resources / test_write_using_filechannel.txt"; try (RandomAccessFile writer = new RandomAccessFile (file, "rw"); FileChannel channel = writer.getChannel ()) {ByteBuffer buff = ByteBuffer.wrap ("Hello world" .getBytes (StandardCharsets.UTF_8)); channel.write (buff); // overenie RandomAccessFile reader = new RandomAccessFile (file, "r"); assertEquals ("Hello world", reader.readLine ()); reader.close (); }}

4.2. Otvorenie a FileChannel

Aby bolo možné zapísať do súboru pomocou FileChannel, musíme to otvoriť.

Pozrime sa, ako otvoriť a FileChannel použitím RandomAccessFile:

Zapisovač RandomAccessFile = nový RandomAccessFile (súbor, "rw"); Kanál FileChannel = writer.getChannel ();

Režim „rw“ označuje, že kanál je „otvorený na čítanie a zápis“.

Pozrime sa tiež, ako otvoriť a FileChannel použitím FileOutputStream:

FileOutputStream fout = nový FileOutputStream (súbor); Kanál FileChannel = fout.getChannel (); 

4.3. Zápis údajov pomocou FileChannel

Ak chcete zapísať údaje pomocou a FileChannel, môžeme použiť jednu z napíš metódy.

Pozrime sa, ako napísať postupnosť bajtov pomocou a ByteBuffer na uloženie údajov:

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

Ďalej uvidíme, ako napísať postupnosť bajtov, počnúc pozíciou súboru:

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

5. Aktuálna pozícia

FileChannel umožňuje nám získať a zmeniť pozíciu, v ktorej čítame alebo píšeme.

Pozrime sa, ako získať aktuálnu pozíciu:

dlhá originalPosition = channel.position ();

Ďalej sa pozrime, ako nastaviť pozíciu:

kanál.pozícia (5); assertEquals (originalPosition + 5, channel.position ());

6. Získajte veľkosť súboru

Pozrime sa, ako používať FileChannel.size metóda na získanie veľkosti súboru v bajtoch:

@Test public void whenGetFileSize_thenCorrect () hodí IOException {RandomAccessFile reader = new RandomAccessFile ("src / test / resources / test_read.in", "r"); Kanál FileChannel = reader.getChannel (); // pôvodná veľkosť súboru je 11 bajtov. assertEquals (11, channel.size ()); channel.close (); reader.close (); }

7. Skráťte súbor

Poďme pochopiť, ako používať FileChannel.truncate metóda na skrátenie súboru na zadanú veľkosť v bajtoch:

@ Test public void whenTruncateFile_thenCorrect () hodí IOException {String input = "toto je testovací vstup"; FileOutputStream fout = nový FileOutputStream ("src / test / resources / test_truncate.txt"); Kanál FileChannel = fout.getChannel (); ByteBuffer buff = ByteBuffer.wrap (input.getBytes ()); channel.write (buff); buff.flip (); channel = channel.truncate (5); assertEquals (5, channel.size ()); fout.close (); channel.close (); } 

8. Vynútiť aktualizáciu súborov do úložiska

Operačný systém môže z dôvodu výkonu ukladať zmeny súborov do medzipamäte a v prípade zlyhania systému sa môžu stratiť údaje. Na vynútenie nepretržitého zápisu obsahu súboru a metadát na disk môžeme použiť sila metóda:

channel.force (true);

Táto metóda je zaručená, iba ak sa súbor nachádza v lokálnom zariadení.

9. Vložte časť súboru do pamäte

Pozrime sa, ako pomocou aplikácie načítať časť súboru do pamäte FileChannel.map. Používame FileChannel.MapMode.READ_ONLY otvorenie súboru v režime iba na čítanie:

@Test public void givenFile_whenReadAFileSectionIntoMemoryWithFileChannel_thenCorrect () vyvolá IOException {try (RandomAccessFile reader = new RandomAccessFile ("src / test / resources / test_read.in", "r"); FileChannel channel = reader.getChannelOut = By.getChannelOut )) {MappedByteBuffer buff = channel.map (FileChannel.MapMode.READ_ONLY, 6, 5); if (buff.hasRemaining ()) {byte [] data = new byte [buff.remaining ()]; buff.get (data); assertEquals ("svet", nový reťazec (data, StandardCharsets.UTF_8)); }}}

Podobne môžeme použiť FileChannel.MapMode.READ_WRITE otvoríte súbor v režime čítania aj zápisu.

Môžeme tiež použiťFileChannel.MapMode.PRIVATE režim, kde sa zmeny nevzťahujú na pôvodný súbor.

10. Zamknite časť súboru

Poďme pochopiť, ako uzamknúť časť súboru, aby sa zabránilo súčasnému prístupu do časti pomocou FileChannel.tryLock metóda:

@ Test verejné neplatné dané (6, 5, Boolean.FALSE)) {// robiť ďalšie operácie ... assertNotNull (fileLock); }}

The tryLock metóda sa pokúša získať zámok v sekcii súborov. Ak je požadovaná časť súboru už blokovaná iným vláknom, hodí sa OverlappingFileLockException výnimkou. Táto metóda tiež vyžaduje a boolovský parameter požadovať buď zdieľaný zámok, alebo výlučný zámok.

Mali by sme poznamenať, že niektoré operačné systémy nemusia povoliť zdieľaný zámok, namiesto toho použije výlučný zámok.

11. Uzávierka a FileChannel

Nakoniec, keď skončíme pomocou a FileChannel, musíme to uzavrieť. V našich príkladoch sme použili vyskúšajte zdroje.

Ak je to potrebné, môžeme uzavrieť FileChannel priamo s Zavrieť metóda:

channel.close ();

12. Záver

V tomto návode sme videli ako použiť FileChannel na čítanie a zápis súborov. Okrem toho sme preskúmali, ako čítať a meniť veľkosť súboru a jeho súčasné umiestnenie na čítanie a zápis, a pozreli sme sa na to, ako ho používať FileChannels v súbežných alebo dátovo kritických aplikáciách.

Zdrojový kód príkladov je ako vždy k dispozícii na serveri GitHub.


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