Veiledning til Java FileChannel

1. Oversikt

I denne raske opplæringen vil vi se på FileChannel klasse gitt i Java NIO bibliotek. Vi diskuterer hvordan du leser og skriver data ved hjelp av FileChannel og ByteBuffer.

Vi vil også utforske fordelene ved å bruke FileChannel og noen av dens andre filmanipuleringsfunksjoner.

2. Fordeler med FileChannel

Fordelene med FileChannel inkludere:

  • Lese og skrive på en bestemt posisjon i en fil
  • Laste en del av en fil direkte i minnet, noe som kan være mer effektivt
  • Vi kan overføre fildata fra en kanal til en annen med en raskere hastighet
  • Vi kan låse en del av en fil for å begrense tilgangen til andre tråder
  • For å unngå tap av data kan vi tvinge å skrive oppdateringer til en fil umiddelbart til lagring

3. Lesing med FileChannel

FileChannel fungerer raskere enn standard I / O når vi leser en stor fil.

Vi bør merke oss at selv om en del av Java NIO, FileChannel operasjoner blokkerer og ikke har en modus som ikke blokkerer.

3.1. Lese en fil ved hjelp av FileChannel

La oss forstå hvordan du leser en fil ved hjelp av FileChannel på en fil som inneholder:

Hei Verden

Denne testen leser filen og sjekker at den ble lest ok:

@Test offentlig ugyldig givenFile_whenReadWithFileChannelUsingRandomAccessFile_thenCorrect () kaster IOException {try (RandomAccessFile reader = new RandomAccessFile ("src / test / resources / test_read.in", "r"); FileChannel channel = reader.getStreamray)) )) {int bufferSize = 1024; hvis (bufferSize> channel.size ()) {bufferSize = (int) channel.size (); } ByteBuffer buff = ByteBuffer.allocate (bufferSize); mens (channel.read (buff)> 0) {out.write (buff.array (), 0, buff.position ()); buff.clear (); } String fileContent = ny streng (out.toByteArray (), StandardCharsets.UTF_8); assertEquals ("Hello world", fileContent); }}

Her leser vi byte fra filen ved hjelp av FileChannel, RandomAccessFile, og ByteBuffer.

Vi bør også merke oss det flere samtidige tråder kan bruke FileChannels trygt. Imidlertid er bare en tråd om gangen tillatt for en operasjon som innebærer oppdatering av en kanals posisjon eller endring av filstørrelse. Dette blokkerer andre tråder som prøver en lignende operasjon til den forrige operasjonen er fullført.

Imidlertid kan operasjoner som gir eksplisitte kanalposisjoner kjøre samtidig uten å bli blokkert.

3.2. Åpning av en FileChannel

For å lese en fil ved hjelp av FileChannel, vi må åpne den.

La oss se hvordan du åpner en FileChannel ved hjelp av RandomAccessFile:

RandomAccessFile reader = ny RandomAccessFile (fil, "r"); FileChannel channel = reader.getChannel ();

Mode 'r' indikerer at kanalen bare er 'åpen for lesing'. Vi bør merke oss at lukking a RandomAccessFile vil også lukke den tilknyttede kanalen.

Deretter ser vi åpning av en FileChannel å lese en fil ved hjelp av FileInputStream:

FileInputStream fin = ny FileInputStream (fil); FileChannel channel = fin.getChannel ();

Tilsvarende lukker en FileInputStream lukker også kanalen som er tilknyttet den.

3.3. Lesing av data fra a FileChannel

For å lese dataene kan vi bruke en av lese metoder.

La oss se hvordan vi leser en sekvens med byte. Vi bruker en ByteBuffer å holde dataene:

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

Deretter får vi se hvordan vi leser en sekvens med byte, og starter ved en filposisjon:

ByteBuffer buff = ByteBuffer.allocate (1024); int noOfBytesRead = channel.read (buff, 5); Streng fileContent = ny streng (buff.array (), StandardCharsets.UTF_8); assertEquals ("verden", fileContent);

Vi bør merke oss behovet for en Charset å dekode et byte-array til String.

Vi spesifiserer Charset som bytene opprinnelig var kodet med. Uten det, vi kan ende opp med forvrenget tekst. Spesielt koding med flere byte som UTF-8 og UTF-16 kan ikke dekode en vilkårlig del av filen, da noen av flerbytetegnene kan være ufullstendige.

4. Skrive med FileChannel

4.1. Skrive inn i en fil ved hjelp av FileChannel

La oss utforske hvordan du skriver ved hjelp FileChannel:

@Test offentlig ugyldig nårWriteWithFileChannelUsingRandomAccessFile_thenCorrect () kaster IOException {String file = "src / test / resources / test_write_using_filechannel.txt"; prøv (RandomAccessFile skribent = ny RandomAccessFile (fil, "rw"); FileChannel kanal = writer.getChannel ()) {ByteBuffer buff = ByteBuffer.wrap ("Hello world" .getBytes (StandardCharsets.UTF_8)); channel.write (buff); // verifisere RandomAccessFile-leser = ny RandomAccessFile (fil, "r"); assertEquals ("Hello world", reader.readLine ()); reader.close (); }}

4.2. Åpning av en FileChannel

For å skrive inn i en fil ved hjelp av FileChannel, vi må åpne den.

La oss se hvordan du åpner en FileChannel ved hjelp av RandomAccessFile:

RandomAccessFile skribent = ny RandomAccessFile (fil, "rw"); FileChannel channel = writer.getChannel ();

Mode 'rw' indikerer at kanalen er 'åpen for lesing og skriving'.

La oss også se hvordan du åpner en FileChannel ved hjelp av FileOutputStream:

FileOutputStream fout = ny FileOutputStream (fil); FileChannel channel = fout.getChannel (); 

4.3. Skrive data med FileChannel

Å skrive data med en FileChannel, kan vi bruke en av skrive metoder.

La oss se hvordan vi skriver en sekvens med byte ved hjelp av a ByteBuffer for å lagre dataene:

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

Deretter får vi se hvordan vi skriver en sekvens med byte, og starter med en filposisjon:

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

5. Nåværende posisjon

FileChannel lar oss få og endre posisjonen vi leser eller skriver på.

La oss se hvordan du får den nåværende posisjonen:

lang originalPosisjon = channel.position ();

Deretter, la oss se hvordan du stiller inn posisjonen:

channel.position (5); assertEquals (originalPosisjon + 5, channel.position ());

6. Få størrelsen på en fil

La oss se hvordan du bruker FileChannel.size metode for å få størrelsen på en fil i byte:

@Test offentlig ugyldig nårGetFileSize_thenCorrect () kaster IOException {RandomAccessFile reader = new RandomAccessFile ("src / test / resources / test_read.in", "r"); FileChannel channel = reader.getChannel (); // den opprinnelige filstørrelsen er 11 byte. assertEquals (11, channel.size ()); channel.close (); reader.close (); }

7. Avkort en fil

La oss forstå hvordan du bruker FileChannel.truncate metode for å kutte en fil til gitt størrelse i byte:

@Test offentlig ugyldig nårTruncateFile_thenCorrect () kaster IOException {String input = "dette er en testinngang"; FileOutputStream fout = ny FileOutputStream ("src / test / resources / test_truncate.txt"); FileChannel channel = fout.getChannel (); ByteBuffer buff = ByteBuffer.wrap (input.getBytes ()); channel.write (buff); buff.flip (); kanal = channel.truncate (5); assertEquals (5, channel.size ()); fout.close (); channel.close (); } 

8. Tving filoppdatering til lagring

Et operativsystem kan cache filendringer av ytelsesårsaker, og data kan gå tapt hvis systemet krasjer. For å tvinge filinnhold og metadata til å skrive til disken kontinuerlig kan vi bruke makt metode:

channel.force (true);

Denne metoden garanteres bare når filen ligger på en lokal enhet.

9. Legg en del av en fil i minnet

La oss se hvordan du laster en del av en fil i minnet ved hjelp av FileChannel.map. Vi bruker FileChannel.MapMode.READ_ONLY for å åpne filen i skrivebeskyttet modus:

@Test offentlig ugyldighet givenFile_whenReadAFileSectionIntoMemoryWithFileChannel_thenCorrect () kaster IOException {try (RandomAccessFile reader = new RandomAccessFile ("src / test / resources / test_read.in", "r"); FileChannel channel = reader.getStream) (ChannelStream =) )) {MappedByteBuffer buff = channel.map (FileChannel.MapMode.READ_ONLY, 6, 5); hvis (buff.hasRemaining ()) {byte [] data = ny byte [buff.remaining ()]; buff.get (data); assertEquals ("verden", ny streng (data, StandardCharsets.UTF_8)); }}}

På samme måte kan vi bruke FileChannel.MapMode.READ_WRITE for å åpne filen i både lese- og skrivemodus.

Vi kan også brukeFileChannel.MapMode.PRIVATE modus, der endringene ikke gjelder originalfilen.

10. Lås en del av en fil

La oss forstå hvordan du låser en del av en fil for å forhindre samtidig tilgang til en seksjon ved hjelp av FileChannel.tryLock metode:

@Test offentlig ugyldig givenFile_whenWriteAFileUsingLockAFileSectionWithFileChannel_thenCorrect () kaster IOException {try (RandomAccessFile reader = new RandomAccessFile ("src / test / resources / test_read.in", "rw"); FileChannel channelLiver = reader.get; fileChannel channel = reader.get; (6, 5, Boolean.FALSE)) {// gjør andre operasjoner ... assertNotNull (fileLock); }}

De tryLock metoden forsøker å skaffe seg en lås på filseksjonen. Hvis den forespurte filseksjonen allerede er blokkert av en annen tråd, kaster den en OverlappingFileLockException unntak. Denne metoden tar også en boolsk parameter for å be om enten en delt lås eller en eksklusiv lås.

Vi bør merke oss at noen operativsystemer kanskje ikke tillater en delt lås, men som standard er en eksklusiv lås.

11. Avslutning a FileChannel

Til slutt, når vi er ferdige med å bruke en FileChannel, vi må lukke den. I eksemplene vi har brukt prøv-med-ressurser.

Om nødvendig kan vi lukke FileChannel direkte med Lukk metode:

channel.close ();

12. Konklusjon

I denne opplæringen har vi sett hvordan å bruke FileChannel å lese og skrive filer. I tillegg har vi utforsket hvordan vi kan lese og endre filstørrelsen og dens nåværende lese / skrive plassering og sett på hvordan du bruker FileChannels i samtidige eller datakritiske applikasjoner.

Som alltid er kildekoden for eksemplene tilgjengelig på GitHub.


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