DigestOutputStream Class Example

In this post under Java –> Security, I will explain with example the use of DigestOutputStream class.

When any stream class under java.io package is used, the data flows from source to destination in a stream.

DigestOutputStream class can be used to calculate a Message Digest when data is being written to the destination using the streams. As new data enters the stream, the digest is regularly updated internally.

Once the data is completely written out to the destination, a final message digest is calculated.

The DigestOutputStream class takes help of MessageDigest class to calculate the message digest.

MessageDigest class are one way hash functions which take arbitrary data and calculates fixed length hash value. The fixed length hash value is called Message Digest.

Below Main class shows how to use the DigestOutputStream class.

Main Class

1  package security;
3  import java.io.BufferedWriter;
4  import java.io.File;
5  import java.io.FileOutputStream;
6  import java.io.IOException;
7  import java.io.OutputStreamWriter;
8  import java.security.DigestOutputStream;
9  import java.security.MessageDigest;
10 import java.security.NoSuchAlgorithmException;
12 public class Example1 {
13 	public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
14 		String data = "Writes text to a character-output stream, buffering characters so as to provide for the efficient writing of single characters, arrays, and strings.\r\n" + 
15 				"The buffer size may be specified, or the default size may be accepted. The default is large enough for most purposes.\r\n" + 
16 				"\r\n" + 
17 				"A newLine() method is provided, which uses the platform's own notion of line separator as defined by the system property line.separator. Not all platforms use the newline character ('\\n') to terminate lines. Calling this method to terminate each output line is therefore preferred to writing a newline character directly.\r\n" + 
18 				"\r\n" + 
19 				"In general, a Writer sends its output immediately to the underlying character or byte stream. Unless prompt output is required, it is advisable to wrap a BufferedWriter around any Writer whose write() operations may be costly, such as FileWriters and OutputStreamWriters. For example,\r\n" + 
20 				"\r\n" + 
21 				" PrintWriter out\r\n" + 
22 				"   = new PrintWriter(new BufferedWriter(new FileWriter(\"foo.out\")));\r\n" + 
23 				" \r\n" + 
24 				"will buffer the PrintWriter's output to the file. Without buffering, each invocation of a print() method would cause characters to be converted into bytes that would then be written immediately to the file, which can be very inefficient.";

25 		MessageDigest messageDigest = MessageDigest.getInstance("SHA");
26 		File file = new File("OutputFile.txt");
27 		try(FileOutputStream fos = new FileOutputStream(file);
28 			DigestOutputStream dos = new DigestOutputStream(fos, messageDigest);
29 			OutputStreamWriter osw = new OutputStreamWriter(dos);
30 			BufferedWriter bw = new BufferedWriter(osw);) {
31 			bw.write(data);
32 			bw.flush();
33 			bw.close();
34 			byte[] digest = dos.getMessageDigest().digest();
35 			System.out.println(digest);
36 		}
37 	}
38 }

In the above code, at line 14, the string variable “data” holds the actual data to be written out to a file.

At line 25, an MessageDigest instance named “messageDigest” is obtained through its static method “getInstance”. The getInstance method takes the algorithm name and based on the algorithm name`, an appropriate instance of MessageDigest class is created.

This messageDigest instance is passed to DigestOutputStream class as constructor argument at line 28. The DigestOutputStream also takes FileOutputStream instance “fos” as an constructor argument.

So basically FileOutputStream instance “fos” is used for writing data to a file. We wrap this output stream with DigestOutputStream “dos” which enhances the functionality of FileOutputStream instance “fos” by adding the functionality of calculating message digest.

At line 31 we write the data to output stream.

At line 32 we flush whatever data is left out in the stream and line 33 we close the stream.

At line 34 we get the MessageDigest instance created at line 25 and call its “digest” method. This method returns the final computed hash value as byte array, which is printed at line 35.

In this way we can calculate the message digest when data is being written out to a stream.

Leave a Reply