57

I am used to the c-style getchar(), but it seems like there is nothing comparable for java. I am building a lexical analyzer, and I need to read in the input character by character.

I know I can use the scanner to scan in a token or line and parse through the token char-by-char, but that seems unwieldy for strings spanning multiple lines. Is there a way to just get the next character from the input buffer in Java, or should I just plug away with the Scanner class?

The input is a file, not the keyboard.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Jamison Dance
  • 19,896
  • 25
  • 97
  • 99
  • read a char without waiting carriage return: https://stackoverflow.com/questions/62122059/in-java-is-it-possible-to-system-in-read-reads-a-key-without-waiting-a-carriage – danilo May 31 '20 at 23:47

9 Answers9

65

Use Reader.read(). A return value of -1 means end of stream; else, cast to char.

This code reads character data from a list of file arguments:

public class CharacterHandler {
    //Java 7 source level
    public static void main(String[] args) throws IOException {
        // replace this with a known encoding if possible
        Charset encoding = Charset.defaultCharset();
        for (String filename : args) {
            File file = new File(filename);
            handleFile(file, encoding);
        }
    }

    private static void handleFile(File file, Charset encoding)
            throws IOException {
        try (InputStream in = new FileInputStream(file);
             Reader reader = new InputStreamReader(in, encoding);
             // buffer for efficiency
             Reader buffer = new BufferedReader(reader)) {
            handleCharacters(buffer);
        }
    }

    private static void handleCharacters(Reader reader)
            throws IOException {
        int r;
        while ((r = reader.read()) != -1) {
            char ch = (char) r;
            System.out.println("Do something with " + ch);
        }
    }
}

The bad thing about the above code is that it uses the system's default character set. Wherever possible, prefer a known encoding (ideally, a Unicode encoding if you have a choice). See the Charset class for more. (If you feel masochistic, you can read this guide to character encoding.)

(One thing you might want to look out for are supplementary Unicode characters - those that require two char values to store. See the Character class for more details; this is an edge case that probably won't apply to homework.)

McDowell
  • 107,573
  • 31
  • 204
  • 267
  • 4
    Typically you open a FileInputStream and wrap that in an InputStreamReader, specifying the character encoding. (FileReader unfortunately doesn't let you specify the encoding.) – Jon Skeet May 01 '09 at 16:10
  • I have a question on this please! If I am reading one character at a time why do I need a BufferedReader? – kzidane Aug 13 '13 at 13:07
  • 1
    @KareemMesbah Buffered reads improve performance as it means most calls to `read()` are from RAM and not the OS/disk. The code will work without the buffer or you could use a BufferedInputStream or use your own buffer by calling `read(char[])` instead. – McDowell Aug 13 '13 at 17:45
  • Thank you - exactly what I've been looking for – thonnor Oct 24 '16 at 13:16
  • @McDowell How is the performance compared to reading a file using reader? – beinghuman May 24 '18 at 05:11
21

Combining the recommendations from others for specifying a character encoding and buffering the input, here's what I think is a pretty complete answer.

Assuming you have a File object representing the file you want to read:

BufferedReader reader = new BufferedReader(
    new InputStreamReader(
        new FileInputStream(file),
        Charset.forName("UTF-8")));
int c;
while((c = reader.read()) != -1) {
  char character = (char) c;
  // Do something with your character
}
roryparle
  • 486
  • 2
  • 7
8

Another option is to not read things in character by character -- read the entire file into memory. This is useful if you need to look at the characters more than once. One trivial way to do that is:

  /** Read the contents of a file into a string buffer      */
    public static void readFile(File file, StringBuffer buf)
        throws IOException
    {
    FileReader fr = null;
    try {
      fr = new FileReader(file);
      BufferedReader br = new BufferedReader(fr);
      char[] cbuf = new char[(int) file.length()];
      br.read(cbuf);  
      buf.append(cbuf);
      br.close();
    }
    finally {
      if (fr != null) {
        fr.close();
      }
    }
}
David
  • 3,251
  • 18
  • 28
  • The char[] could be used as well to search through the file at a later point. The StringBuffer is just used to append the character array to the StringBuffer and pass it back to the calling point of execution. I would imagine that the StringBuffer buf is empty when it comes into the method. – Doug Hauf Jan 24 '14 at 18:35
  • This is an example method to demonstrate the concept. To actually use the technique, I would suggest a library like Guava – David Feb 12 '14 at 16:55
  • Given that you are already using a BufferedReader this might actually be slower than setting a mark and resetting the reader's buffer. It would be worth getting performance metrics before using this. – Txangel Oct 10 '14 at 11:06
7

Wrap your input stream in a buffered reader then use the read method to read one byte at a time until the end of stream.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Reader {

    public static void main(String[] args) throws IOException {

        BufferedReader buffer = new BufferedReader(
                 new InputStreamReader(System.in));
        int c = 0;
        while((c = buffer.read()) != -1) {
            char character = (char) c;          
            System.out.println(character);          
        }       
    }   
}
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
pfranza
  • 3,292
  • 2
  • 21
  • 34
2

If I were you I'd just use a scanner and use ".nextByte()". You can cast that to a char and you're good.

W. B. Reed
  • 1,614
  • 1
  • 10
  • 9
1

You have several options if you use BufferedReader. This buffered reader is faster than Reader so you can wrap it.

BufferedReader reader = new BufferedReader(new FileReader(path));
reader.read(char[] buffer);

this reads line into char array. You have similar options. Look at documentation.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
shake
  • 323
  • 9
  • 23
1

Wrap your reader in a BufferedReader, which maintains a buffer allowing for much faster reads overall. You can then use read() to read a single character (which you'll need to cast). You can also use readLine() to fetch an entire line and then break that into individual characters. The BufferedReader also supports marking and returning, so if you need to, you can read a line multiple times.

Generally speaking, you want to use a BufferedReader or BufferedInputStream on top of whatever stream you are actually using since the buffer they maintain will make multiple reads much faster.

James
  • 2,050
  • 13
  • 15
0

In java 5 new feature added that is Scanner method who gives the chance to read input character by character in java.

for instance; for use Scanner method import java.util.Scanner; after in main method:define

Scanner myScanner = new Scanner(System.in); //for read character

char anything=myScanner.findInLine(".").charAt(0);

you anything store single character, if you want more read more character declare more object like anything1,anything2... more example for your answer please check in your hand(copy/paste)

     import java.util.Scanner;
     class ReverseWord  {

    public static void main(String args[]){
    Scanner myScanner=new Scanner(System.in);
    char c1,c2,c3,c4;

    c1 = myScanner.findInLine(".").charAt(0);
        c2 = myScanner.findInLine(".").charAt(0);
    c3 = myScanner.findInLine(".").charAt(0);
    c4 = myScanner.findInLine(".").charAt(0);

    System.out.print(c4);
    System.out.print(c3);
    System.out.print(c2);
    System.out.print(c1);
    System.out.println();

   }
  }
samir vora
  • 531
  • 4
  • 3
-1

This will print 1 character per line from the file.

    try {

        FileInputStream inputStream = new FileInputStream(theFile);
        while (inputStream.available() > 0) {
            inputData = inputStream.read();
            System.out.println((char) inputData);

        }
        inputStream.close();
    } catch (IOException ioe) {
        System.out.println("Trouble reading from the file: " + ioe.getMessage());
    }
grant zukowski
  • 1,894
  • 1
  • 13
  • 10