Gids voor BufferedReader

1. Overzicht

BufferedReader is een klasse die het lezen van tekst uit een tekeninvoerstroom vereenvoudigt. Het buffert de karakters om het efficiënt lezen van tekstgegevens mogelijk te maken.

In deze zelfstudie gaan we kijken hoe u de BufferedReader klasse.

2. Wanneer te gebruiken BufferedReader

Over het algemeen, BufferedReader is handig als we tekst willen lezen van elke soort invoerbron, of dat nu bestanden, sockets of iets anders zijn.

Simpel gezegd, het stelt ons in staat om het aantal I / O-bewerkingen te minimaliseren door stukjes tekens te lezen en ze op te slaan in een interne buffer. Hoewel de buffer gegevens bevat, leest de lezer er uit in plaats van rechtstreeks uit de onderliggende stream.

2.1. Een andere lezer bufferen

Zoals de meeste Java I / O-klassen,BufferedReader werktuigen Decorateur patroon, wat betekent dat het een verwacht Lezer in zijn constructor. Op deze manier stelt het ons in staat om flexibel een exemplaar van een Lezer implementatie met bufferfunctionaliteit:

BufferedReader-lezer = nieuwe BufferedReader (nieuwe FileReader ("src / main / resources / input.txt"));

Maar als buffering voor ons niet uitmaakt, kunnen we gewoon een FileReader direct:

FileReader-lezer = nieuwe FileReader ("src / main / resources / input.txt");

Naast buffering, BufferedReader biedt ook een aantal handige hulpfuncties voor het regel voor regel lezen van bestanden. Dus ook al lijkt het eenvoudiger te gebruiken FileReader direct, BufferedReader kan een grote hulp zijn.

2.2. Een stroom bufferen

Over het algemeen, we kunnen configureren BufferedReader om elke inputstroom te ontvangenals onderliggende bron. We kunnen het gebruiken met InputStreamReader en wikkel het in de constructor:

BufferedReader-lezer = nieuwe BufferedReader (nieuwe InputStreamReader (System.in));

In het bovenstaande voorbeeld lezen we uit System.in wat doorgaans overeenkomt met de invoer van het toetsenbord. Evenzo kunnen we een invoerstroom doorgeven om te lezen uit een socket, bestand of elk denkbaar type tekstuele invoer. De enige voorwaarde is dat er een geschikt is InputStream implementatie ervoor.

2.3. BufferedReader versus scanner

Als alternatief kunnen we de Scanner class om dezelfde functionaliteit te bereiken als met BufferedReader.

Er zijn echter aanzienlijke verschillen tussen deze twee klassen, waardoor ze voor ons meer of minder handig kunnen zijn, afhankelijk van ons gebruik:

  • BufferedReader is gesynchroniseerd (thread-safe) terwijl Scanner dat niet is
  • Scanner kan primitieve typen en tekenreeksen ontleden met behulp van reguliere expressies
  • BufferedReader maakt het mogelijk om de grootte van de buffer te wijzigen terwijl Scanner een vaste buffergrootte heeft
  • BufferedReader heeft een grotere standaard buffergrootte
  • Scanner verbergt IOException, terwijl BufferedReader dwingt ons om ermee om te gaan
  • BufferedReader is meestal sneller dan Scanner omdat het alleen de gegevens leest zonder deze te ontleden

Met deze in gedachten, als we individuele tokens in een bestand analyseren, dan Scanner zal een beetje natuurlijker aanvoelen dan BufferedReader. Maar gewoon een regel tegelijk lezen is waar BufferedReader schijnt.

Indien nodig hebben we ook een gids Scanner ook.

3. Tekst lezen met BufferedReader

Laten we het hele proces van het bouwen, gebruiken en vernietigen van een BufferReader correct te lezen uit een tekstbestand.

3.1. Initialiseren van een BufferedReader

Ten eerste, laten we een BufferedReader met behulp van zijn BufferedReader (lezer) constructeur:

BufferedReader-lezer = nieuwe BufferedReader (nieuwe FileReader ("src / main / resources / input.txt"));

Het inpakken van het FileReader Dit is een leuke manier om buffering als aspect aan andere lezers toe te voegen.

Standaard wordt hiervoor een buffer van 8 KB gebruikt. Als we echter kleinere of grotere blokken willen bufferen, kunnen we de BufferedReader (Reader, int) constructeur:

BufferedReader-lezer = nieuwe BufferedReader (nieuwe FileReader ("src / main / resources / input.txt")), 16384);

Dit stelt de buffergrootte in op 16384 bytes (16 KB).

De optimale buffergrootte is afhankelijk van factoren zoals het type invoerstroom en de hardware waarop de code draait. Om deze reden, om de ideale buffergrootte te bereiken, moeten we deze zelf vinden door te experimenteren.

Het is het beste om macht 2 als buffergrootte te gebruiken, aangezien de meeste hardwareapparaten een macht van 2 hebben als blokgrootte.

Tenslotte, er is nog een handige manier om een BufferedReader de ... gebruiken Bestanden helper klasse van de java.nioAPI:

BufferedReader-lezer = Files.newBufferedReader (Paths.get ("src / main / resources / input.txt"))

CreërenDit is een leuke manier om te bufferen als we een bestand willen lezen, omdat we niet handmatig een FileReader eerst en dan inpakken.

3.2. Regel voor regel lezen

Laten we vervolgens de inhoud van het bestand lezen met behulp van de Lees regel methode:

public String readAllLines (BufferedReader-lezer) gooit IOException {StringBuilder content = new StringBuilder (); String lijn; while ((line = reader.readLine ())! = null) {content.append (regel); content.append (System.lineSeparator ()); } retourneer content.toString (); }

We kunnen hetzelfde doen als hierboven met de lijnen methode geïntroduceerd in Java 8 een beetje eenvoudiger:

openbare String readAllLinesWithStream (BufferedReader-lezer) {return reader.lines () .collect (Collectors.joining (System.lineSeparator ())); }

3.3. De stroom sluiten

Na gebruik van de BufferedReader, we moeten haar bellen dichtbij() methode om alle bijbehorende systeembronnen vrij te geven. Dit gebeurt automatisch als we een probeer-met-middelen blok:

probeer (BufferedReader reader = nieuwe BufferedReader (nieuwe FileReader ("src / main / resources / input.txt"))) {return readAllLines (reader); }

4. Andere nuttige methoden

Laten we ons nu concentreren op verschillende handige methoden die beschikbaar zijn in BufferedReader.

4.1. Een enkel personage lezen

We kunnen de lezen() methode om een ​​enkel teken te lezen. Laten we de hele inhoud karakter voor karakter lezen tot het einde van de stream:

openbare String readAllCharsOneByOne (BufferedReader-lezer) gooit IOException {StringBuilder content = new StringBuilder (); int waarde; while ((value = reader.read ())! = -1) {content.append ((char) waarde); } retourneer content.toString (); }

Dit leest de tekens (geretourneerd als ASCII-waarden), cast ze naar char en voeg ze toe aan het resultaat. We herhalen dit tot het einde van de stream, wat wordt aangegeven door de antwoordwaarde -1 van de lezen() methode.

4.2. Meerdere karakters lezen

Als we meerdere tekens tegelijk willen lezen, kunnen we de methode gebruiken lezen (char [] cbuf, int off, int len):

public String readMultipleChars (BufferedReader-lezer) gooit IOException {int length; char [] chars = new char [lengte]; int charsRead = reader.read (tekens, 0, lengte); String resultaat; if (charsRead! = -1) {resultaat = nieuwe String (chars, 0, charsRead); } anders {resultaat = ""; } resultaat teruggeven; }

In het bovenstaande codevoorbeeld lezen we maximaal 5 tekens in een char-array en construeren we daaruit een string. In het geval dat er geen tekens zijn gelezen tijdens onze leespoging (d.w.z. we hebben het einde van de stream bereikt), retourneren we eenvoudig een lege string.

4.3. Tekens overslaan

We kunnen ook een bepaald aantal tekens overslaan door de overslaan (lange n) methode:

@Test openbare leegte gegevenBufferedReader_whensSkipChars_thenOk () gooit IOException {StringBuilder resultaat = nieuwe StringBuilder (); probeer (BufferedReader-lezer = nieuwe BufferedReader (nieuwe StringReader ("1__2__3__4__5"))) {int waarde; while ((value = reader.read ())! = -1) {result.append ((char) waarde); reader.skip (2L); }} assertEquals ("12345", resultaat); }

In het bovenstaande voorbeeld lezen we uit een invoertekenreeks die getallen bevat die worden gescheiden door twee onderstrepingstekens. Om een ​​string te construeren die alleen de cijfers bevat, slaan we de onderstrepingstekens over door de overspringen methode.

4.4. Mark en resetten

We kunnen de mark (int readAheadLimit) en resetten () methoden om een ​​positie in de stream te markeren en er later naar terug te keren. Laten we als een ietwat gekunsteld voorbeeld gebruiken Mark() en resetten () om alle witruimten aan het begin van een stream te negeren:

@Test openbare leegte gegevenBufferedReader_whenSkipsWhitespacesAtBeginning_thenOk () gooit IOException {String resultaat; probeer (BufferedReader reader = nieuwe BufferedReader (nieuwe StringReader ("Lorem ipsum dolor sit amet."))) {do {reader.mark (1); } while (Character.isWhitespace (reader.read ())) reader.reset (); resultaat = reader.readLine (); } assertEquals ("Lorem ipsum dolor sit amet.", resultaat); }

In het bovenstaande voorbeeld gebruiken we de Mark() methode om de positie te markeren die we zojuist hebben gelezen. Door het een waarde van 1 te geven, onthoudt alleen de code het teken voor één teken vooruit. Het is hier handig omdat, zodra we ons eerste niet-witruimte-teken zien, we terug kunnen gaan en dat teken opnieuw kunnen lezen zonder de hele stream opnieuw te hoeven verwerken. Zonder een merkteken te hebben, zouden we de L. in onze laatste reeks.

Merk op dat omdat Mark() kan een UnsupportedOperationException, is het vrij gebruikelijk om te associëren markSupported () met code die aanroept Mark(). Maar we hebben het hier niet echt nodig. Dat is omdat markSupported () retourneert altijd waar voor BufferedReader.

Natuurlijk kunnen we het bovenstaande misschien wat eleganter doen op andere manieren, en inderdaad Mark en resetten zijn niet erg typische methoden. Ze komen echter zeker van pas als het nodig is om vooruit te kijken.

5. Conclusie

In deze korte tutorial hebben we geleerd hoe we tekeninvoerstromen kunnen lezen aan de hand van een praktisch voorbeeld met BufferedReader.

Ten slotte is de broncode voor de voorbeelden beschikbaar op Github.


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