Inleiding tot de Java NIO2 File API

1. Overzicht

In dit artikel gaan we ons concentreren op de nieuwe I / O-API's in het Java-platform - NIO2 - om elementaire bestandsmanipulatie uit te voeren.

Bestands-API's in NIO2 vormen een van de belangrijkste nieuwe functionele gebieden van het Java-platform dat bij Java 7 werd geleverd, met name een subset van de nieuwe bestandssysteem-API naast Path API's.

2. Installatie

Het instellen van uw project voor het gebruik van bestands-API's is gewoon een kwestie van deze import maken:

importeer java.nio.file. *;

Aangezien de codevoorbeelden in dit artikel waarschijnlijk in verschillende omgevingen zullen worden uitgevoerd, laten we de homedirectory van de gebruiker eens bekijken, die geldig zal zijn voor alle besturingssystemen:

private static String HOME = System.getProperty ("user.home");

De Bestanden class is een van de belangrijkste toegangspunten van de java.nio.file pakket. Deze klasse biedt een uitgebreide set API's voor het lezen, schrijven en manipuleren van bestanden en mappen. De Bestanden class-methoden werken op instanties van Pad voorwerpen.

3. Een bestand of directory controleren

We kunnen een Pad instantie die een bestand of een map op het bestandssysteem vertegenwoordigt. Of dat bestand of de map waarnaar het verwijst, bestaat of niet, toegankelijk is of niet, kan worden bevestigd door een bestandsbewerking.

Eenvoudigheidshalve, wanneer we de term gebruiken het dossierverwijzen we naar zowel bestanden als mappen, tenzij expliciet anders vermeld.

Om te controleren of een bestand bestaat, gebruiken we de bestaat API:

@Test openbare leegte gegevenExistentPath_whenConfirmsFileExists_thenCorrect () {Pad p = Paths.get (HOME); assertTrue (Files.exists (p)); }

Om te controleren of een bestand niet bestaat, gebruiken we de bestaat niet API:

@Test openbare leegte gegevenNonexistentPath_whenConfirmsFileNotExists_thenCorrect () {Pad p = Paths.get (HOME + "/inexistent_file.txt"); assertTrue (Files.notExists (p)); }

We kunnen ook controleren of een bestand een normaal bestand is, zoals mijnbestand.txt of is slechts een directory, we gebruiken de isRegularFile API:

@Test openbare leegte gegevenDirPath_whenConfirmsNotRegularFile_thenCorrect () {Pad p = Paths.get (HOME); assertFalse (Files.isRegularFile (p)); }

Er zijn ook statische methoden om te controleren op bestandsrechten. Om te controleren of een bestand leesbaar is, gebruiken we de is leesbaar API:

@Test openbare ongeldig gegevenExistentDirPath_whenConfirmsReadable_thenCorrect () {Pad p = Paths.get (HOME); assertTrue (Files.isReadable (p)); }

Om te controleren of het schrijfbaar is, gebruiken we de isWritable API:

@Test openbare ongeldig gegevenExistentDirPath_whenConfirmsWritable_thenCorrect () {Pad p = Paths.get (HOME); assertTrue (Files.isWritable (p)); }

Evenzo, om te controleren of het uitvoerbaar is:

@ Test openbare ongeldig gegevenExistentDirPath_whenConfirmsExecutable_thenCorrect () {Pad p = Paths.get (HOME); assertTrue (Files.isExecutable (p)); }

Als we twee paden hebben, kunnen we controleren of ze allebei naar hetzelfde bestand op het onderliggende bestandssysteem verwijzen:

@Test openbare leegte gegevenSameFilePaths_whenConfirmsIsSame_thenCorrect () {Pad p1 = Paths.get (HOME); Pad p2 = Paths.get (HOME); assertTrue (Files.isSameFile (p1, p2)); }

4. Bestanden aanmaken

De bestandssysteem-API biedt bewerkingen op één regel voor het maken van bestanden. Om een ​​gewoon bestand te maken, gebruiken we de createFile API en geef het door a Pad object dat het bestand vertegenwoordigt dat we willen maken.

Alle naamelementen in het pad moeten bestaan, behalve de bestandsnaam, anders krijgen we een IOException:

@Test openbare leegte gegevenFilePath_whenCreatesNewFile_thenCorrect () {String fileName = "myfile_" + UUID.randomUUID (). ToString () + ".txt"; Pad p = Paths.get (HOME + "/" + bestandsnaam); assertFalse (Files.exists (p)); Files.createFile (p); assertTrue (Files.exists (p)); }

In de bovenstaande test, wanneer we voor het eerst het pad controleren, bestaat het niet, en daarna na de createFile operatie blijkt te bestaan.

Om een ​​directory te maken, gebruiken we de Map maken API:

@Test openbare leegte gegevenDirPath_whenCreatesNewDir_thenCorrect () {String dirName = "myDir_" + UUID.randomUUID (). ToString (); Pad p = Paths.get (HOME + "/" + dirName); assertFalse (Files.exists (p)); Files.createDirectory (p); assertTrue (Files.exists (p)); assertFalse (Files.isRegularFile (p)); assertTrue (Files.isDirectory (p)); }

Deze bewerking vereist dat alle name-elementen in het pad bestaan, zo niet, dan krijgen we ook een IOException:

@Test (verwacht = NoSuchFileException.class) public void givenDirPath_whenFailsToCreateRecursively_thenCorrect () {String dirName = "myDir_" + UUID.randomUUID (). ToString () + "/ subdir"; Pad p = Paths.get (HOME + "/" + dirName); assertFalse (Files.exists (p)); Files.createDirectory (p); }

Als we echter met een enkele oproep een hiërarchie van telefoonboeken willen maken, gebruiken we de createDirectories methode. In tegenstelling tot de vorige bewerking, genereert het, wanneer het ontbrekende naamelementen in het pad tegenkomt, geen IOException, het creëert ze recursief in de aanloop naar het laatste element:

@Test openbare ongeldige gegevenDirPath_whenCreatesRecursively_thenCorrect () {Path dir = Paths.get (HOME + "/ myDir_" + UUID.randomUUID (). ToString ()); Pad subdir = dir.resolve ("subdir"); assertFalse (Files.exists (dir)); assertFalse (Files.exists (subdir)); Files.createDirectories (subdir); assertTrue (Files.exists (dir)); assertTrue (Files.exists (subdir)); }

5. Tijdelijke bestanden maken

Veel applicaties creëren een spoor van tijdelijke bestanden in het bestandssysteem terwijl ze worden uitgevoerd. Als gevolg hiervan hebben de meeste bestandssystemen een speciale map om tijdelijke bestanden op te slaan die door dergelijke toepassingen zijn gegenereerd.

De nieuwe bestandssysteem-API biedt hiervoor specifieke bewerkingen. De createTempFile API voert deze bewerking uit. Het vereist een pad-object, een bestandsvoorvoegsel en een bestandsachtervoegsel:

@Test openbare ongeldig gegevenFilePath_whenCreatesTempFile_thenCorrect () {String prefix = "log_"; String achtervoegsel = ".txt"; Pad p = Paths.get (HOME + "/"); Files.createTempFile (p, voorvoegsel, achtervoegsel); assertTrue (Files.exists (p)); }

Deze parameters zijn voldoende voor vereisten die deze bewerking nodig hebben. Als u echter specifieke attributen van het bestand moet specificeren, is er een vierde parameter voor variabele argumenten.

De bovenstaande test maakt een tijdelijk bestand aan in de HUIS directory, in afwachting van en het toevoegen van respectievelijk de opgegeven voorvoegsel- en achtervoegselstrings. We zullen eindigen met een bestandsnaam zoals log_8821081429012075286.txt. De lange numerieke reeks wordt door het systeem gegenereerd.

Als we echter geen voorvoegsel en achtervoegsel opgeven, bevat de bestandsnaam alleen de lange numerieke tekenreeks en een standaard .tmp uitbreiding:

@Test openbare leegte gegevenPath_whenCreatesTempFileWithDefaults_thenCorrect () {Pad p = Paths.get (HOME + "/"); Files.createTempFile (p, null, null); assertTrue (Files.exists (p)); }

De bovenstaande bewerking maakt een bestand met een naam zoals 8600179353689423985.tmp.

Als we tenslotte geen pad, voorvoegsel of achtervoegsel opgeven, zal de bewerking overal standaardwaarden gebruiken. De standaardlocatie van het gemaakte bestand is de door het bestandssysteem verstrekte map met tijdelijke bestanden:

@Test openbare void givenNoFilePath_whenCreatesTempFileInTempDir_thenCorrect () {Pad p = Files.createTempFile (null, null); assertTrue (Files.exists (p)); }

Op Windows is dit standaard zoiets als C: \ Users \ user \ AppData \ Local \ Temp \ 6100927974988978748.tmp.

Alle bovenstaande bewerkingen kunnen worden aangepast om mappen te maken in plaats van gewone bestanden door createTempDirectory in plaats van createTempFile.

6. Verwijderen van een bestand

Om een ​​bestand te verwijderen, gebruiken we de verwijderen API. Voor de duidelijkheid: de volgende test zorgt er eerst voor dat het bestand niet al bestaat, maakt het vervolgens en bevestigt dat het nu bestaat en verwijdert het ten slotte en bevestigt dat het niet meer bestaat:

@Test openbare leegte gegevenPath_whenDeletes_thenCorrect () {Pad p = Paths.get (HOME + "/fileToDelete.txt"); assertFalse (Files.exists (p)); Files.createFile (p); assertTrue (Files.exists (p)); Files.delete (p); assertFalse (Files.exists (p)); }

Als een bestand echter niet aanwezig is in het bestandssysteem, mislukt het verwijderen met de extensie IOException:

@Test (verwacht = NoSuchFileException.class) openbare leegte gegevenInexistentFile_whenDeleteFails_thenCorrect () {Pad p = Paths.get (HOME + "/inexistentFile.txt"); assertFalse (Files.exists (p)); Files.delete (p); }

We kunnen dit scenario vermijden door deleteIfExists die stilletjes mislukken als het bestand niet bestaat. Dit is belangrijk wanneer meerdere threads deze bewerking uitvoeren en we geen foutmelding willen, simpelweg omdat een thread de bewerking eerder heeft uitgevoerd dan de huidige thread die is mislukt:

@Test openbare ongeldige gegevenInexistentFile_whenDeleteIfExistsWorks_thenCorrect () {Path p = Paths.get (HOME + "/inexistentFile.txt"); assertFalse (Files.exists (p)); Files.deleteIfExists (p); }

Als we te maken hebben met mappen en niet met gewone bestanden, moeten we onthouden dat het verwijderen standaard niet recursief werkt. Dus als een directory niet leeg is, zal deze mislukken met een IOException:

@Test (verwacht = DirectoryNotEmptyException.class) openbare leegte gegevenPath_whenFailsToDeleteNonEmptyDir_thenCorrect () {Padmap = Paths.get (HOME + "/ emptyDir" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir); assertTrue (Files.exists (dir)); Padbestand = dir.resolve ("file.txt"); Files.createFile (bestand); Files.delete (dir); assertTrue (Files.exists (dir)); }

7. Bestanden kopiëren

U kunt een bestand of map kopiëren met behulp van de kopiëren API:

@Test openbare leegte gegevenFilePath_whenCopiesToNewLocation_thenCorrect () {Pad dir1 = Paths.get (HOME + "/ firstdir_" + UUID.randomUUID (). ToString ()); Path dir2 = Paths.get (HOME + "/ otherdir_" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir1); Files.createDirectory (dir2); Pad file1 = dir1.resolve ("filetocopy.txt"); Pad file2 = dir2.resolve ("filetocopy.txt"); Files.createFile (bestand1); assertTrue (Files.exists (file1)); assertFalse (Files.exists (file2)); Files.copy (bestand1, bestand2); assertTrue (Files.exists (file2)); }

Het kopiëren mislukt als het doelbestand bestaat, tenzij het VERVANG BESTAANDE optie is gespecificeerd:

@Test (verwacht = FileAlreadyExistsException.class) openbare ongeldige gegevenPath_whenCopyFailsDueToExistingFile_thenCorrect () {Path dir1 = Paths.get (HOME + "/ firstdir_" + UUID.randomUUID (). ToString ()); Path dir2 = Paths.get (HOME + "/ otherdir_" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir1); Files.createDirectory (dir2); Pad file1 = dir1.resolve ("filetocopy.txt"); Pad file2 = dir2.resolve ("filetocopy.txt"); Files.createFile (bestand1); Files.createFile (file2); assertTrue (Files.exists (file1)); assertTrue (Files.exists (file2)); Files.copy (bestand1, bestand2); Files.copy (bestand1, bestand2, StandardCopyOption.REPLACE_EXISTING); }

Bij het kopiëren van mappen wordt de inhoud echter niet recursief gekopieerd. Dit betekent dat if / baeldung bevat /articles.db en /authors.db bestanden, kopiëren / baeldung naar een nieuwe locatie wordt een lege map gemaakt.

8. Bestanden verplaatsen

U kunt een bestand of map verplaatsen met de Actie API. Het is in de meeste opzichten vergelijkbaar met het kopiëren operatie. Als de kopieerbewerking analoog is aan een knippen en plakken werking in GUI-gebaseerde systemen, dan Actie is analoog aan een Knip en plak operatie:

@Test openbare leegte gegevenFilePath_whenMovesToNewLocation_thenCorrect () {Pad dir1 = Paths.get (HOME + "/ firstdir_" + UUID.randomUUID (). ToString ()); Path dir2 = Paths.get (HOME + "/ otherdir_" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir1); Files.createDirectory (dir2); Pad file1 = dir1.resolve ("filetocopy.txt"); Pad file2 = dir2.resolve ("filetocopy.txt"); Files.createFile (bestand1); assertTrue (Files.exists (file1)); assertFalse (Files.exists (file2)); Files.move (bestand1, bestand2); assertTrue (Files.exists (file2)); assertFalse (Files.exists (file1)); }

De Actie bewerking mislukt als het doelbestand bestaat, tenzij de VERVANG BESTAANDE optie is gespecificeerd net zoals we deden met de kopiëren operatie:

@Test (verwacht = FileAlreadyExistsException.class) openbare ongeldige gegevenFilePath_whenMoveFailsDueToExistingFile_thenCorrect () {Path dir1 = Paths.get (HOME + "/ firstdir_" + UUID.randomUUID (). ToString ()); Path dir2 = Paths.get (HOME + "/ otherdir_" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir1); Files.createDirectory (dir2); Pad file1 = dir1.resolve ("filetocopy.txt"); Pad file2 = dir2.resolve ("filetocopy.txt"); Files.createFile (bestand1); Files.createFile (file2); assertTrue (Files.exists (file1)); assertTrue (Files.exists (file2)); Files.move (bestand1, bestand2); Files.move (bestand1, bestand2, StandardCopyOption.REPLACE_EXISTING); assertTrue (Files.exists (file2)); assertFalse (Files.exists (file1)); }

9. Conclusie

In dit artikel leerden we over bestands-API's in de nieuwe bestandssysteem-API (NIO2) die als onderdeel van Java 7 werd geleverd en zagen we de meeste belangrijke bestandsbewerkingen in actie.

De codevoorbeelden die in dit artikel worden gebruikt, zijn te vinden in het Github-project van het artikel.