DEV Community

Cover image for Character streams
Tristan Elliott
Tristan Elliott

Posted on • Edited on

Character streams

Introduction

  • The second post on streams, it will be on character streams in Java. I have created a YouTube video version, so please make sure to check that out as well.

Character Streams

  • Java stores character values using Unicode conventions. Character streams automatically translate this internal format to and from our local character set, which is dependant on what language you have written the code in.

Unicode

  • Unicode is a computing industry standard for consistently and uniquely encoding Characters used in any written languages around the world.

  • All character stream classes are descendants from the Reader and Writer class, which are abstract classes for reading and writing character streams. We can then use those abstract classes to specialize depending on what kind of data we are reading and writing.

  • Listed below is going to be the source code for this project. After the code block I will be describing each line of the code to the best of my abilities.

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

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

        FileReader inputStream = null;
        FileWriter outputStream = null;

        try {
            inputStream = new FileReader("characterinput.txt");
            outputStream = new FileWriter("characteroutput.txt");

            int c;
            while ((c = inputStream.read()) != -1) {
                outputStream.write(c);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Code explanation

  • 1) throws : throws is used in the method signature of main to tell the compiler that the main method has the chance to throw an exception. throws also tells the compiler that it delegates the responsibility of handling this exception to the calling method. However, since there is not calling method and the JVM can not find a suitable handler for it, our program will promptly crash when given an exception. I believe this tutorial does not handle exceptions properly because the point of this project is character streams and not exceptions.

  • 2) IOException : this is to signal that an I/O exception could occur. It is just an generalization of the I/O operations

  • 3) FileReader : this is just a convivence class for reading character files and since we gave it a string, the appropriate constructor will be triggered and it will read from a file with the name of "characterinput.txt" in the root directory. If that file is not in the root directory then a exception will occur.

  • 4) FileWriter : this is also a convivence class but for writing character files. Since we gave it a string, the appropriate constructor will be called and it will write to a file with the name of "characteroutput.txt" in the root directory.

  • 5) read() : it will return a single character or -1 if the end of the stream has been reached. This method is what allows us to read form the specified file, one character at a time

  • 6) write() : writes a single character to the output file. This method is what allows us to write to the specified file, one character at a time.

  • 7) close() : this will close the stream but first it will flush it.

What is flushing the stream?

  • When we write data to a stream, it does not get written immediately, it gets buffered. While I know this does not answer the question, we first have to understand buffered streams before we can under stand what flushing a stream does.

Buffered Stream

  • So first lets talk about unbuffered streams. When a stream is unbuffered every read or write request is handled directly by the underlying OS(operating system). This can make things very inefficient because each request can often trigger more expensive operations like, disk access, network activity and more.

  • In order to reduce this massive overhead, Java introduced buffered I/O streams. Buffered input streams read data from a temporary memory area called a buffer. The native API is called only when the buffer is empty. Buffered output streams write data to a buffer and the native API is only called when the buffer is full. A good mental mode is presented here, it is in node.js but the idea is still the same.

What is flushing the stream

  • Well it is when we empty the buffer completely before closing the stream. Why would we do that? well it is to ensure that we have actually sent data to out output device and not just waiting for it to be sent.

Conclusion

  • Thank you for taking the time out of you day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.
  • Also make sure to checkout my YouTube channel for more programming tutorials.

Top comments (0)