Lab 5
Get started now
## Overview In this assignment you will create `BufferedInputStream` and `BufferedOutputStream` classes as well as a program to test your implementations. Each class will wrap an input or output stream and use an array as a buffer to minimize the number of `read()`/`write()` calls to the wrapped input/output streams. ## Resources * [Lab5Sample.java](Lab5Sample.java) &mdash; a simple class that demonstrates how to read/write bytes with IO streams. ## Objectives * Develop tests that test boundary conditions * Define FIFO and explain how it relates to a queue<sup><a href="#fn__1" name="fnt__1" class="fn_top">1)</a></sup> ## In Lab Activity You should read the lab assignment prior to the beginning of lab. At the beginning of lab, work with a classmate to create a list of things to fully test your `read(byte[])` method. You list should include descriptions of how you would construct the test for each of the items in your list. You must include this list, along with the name of the classmate with whom you worked as a comment at the end of your `Lab5Tests` class. ## Assignment Details If no size is specified when the streams are constructed, a default buffer size of 32 should be used. ### Buffered Input Stream You must implement the following methods in your `BufferedInputStream` class: * `BufferedInputStream(InputStream)` &mdash; follow the Javadoc for [`java.io.BufferedInputStream.BufferedInputStream(InputStream in)`](http://javadoc.taylorial.com/java.base/io/BufferedInputStream.html#<init>%28java.io.InputStream%29) * `BufferedInputStream(InputStream, int)` &mdash; follow the Javadoc for [`java.io.BufferedInputStream.BufferedInputStream(InputStream in, int size)`](http://javadoc.taylorial.com/java.base/io/BufferedInputStream.html#<init>%28java.io.InputStream,int%29) * `read()` &mdash; follow the Javadoc for [`java.io.BufferedInputStream.read()`](http://javadoc.taylorial.com/java.base/io/BufferedInputStream.html#read%28%29) (with the addition of potentially throwing an `IllegalStateException` as described below) * `read(byte[])` &mdash; follow the Javadoc for [`java.io.BufferedInputStream.read(byte[] b, int off, int len)`](http://javadoc.taylorial.com/java.base/io/BufferedInputStream.html#read%28byte[],int,int%29) where `off==0` and `len==b.length` (with the addition of potentially throwing an `IllegalStateException` as described below) In addition, you must implement the following method: * `readBit()` &mdash; This method reads the next bit of data from the input stream. The value of the bit is returned as an `int` in the range `0` to `1`. If no bit is available because the end of the stream has been reached, the value `-1` is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown. Bits are returned from most to least significant. E.g., if the input stream contains one byte with the value 0b10110000, this method will return bit values in the following order: 1, 0, 1, 1, 0, 0, 0, 0. #### Deviation from `java.io.BufferedInputStream` Javadoc: > If `readBit()` is called once, a partial byte (seven bits) will be left in the input stream. Once the `readBit()` method has been called, you must ensure that it is called seven more times before allowing any of the `read()` methods to be called. To ensure this, you will need to modify the behavior of the two `read()` methods so that an `IllegalStateException` is thrown if called when a byte from the input stream has only been partially read. I.e., `readBit()` has been called at least once but not a number of times that is evenly divisible by `8`. ### Buffered Output Stream You must implement the following methods in your `BufferedOutputStream` class: * `BufferedOutputStream(OutputStream)` &mdash; follow the Javadoc for [`java.io.BufferedOutputStream.BufferedOutputStream(OutputStream out)`](http://javadoc.taylorial.com/java.base/io/BufferedOutputStream.html#<init>%28java.io.OutputStream%29) * `BufferedOutputStream(OutputStream, int)` &mdash; follow the Javadoc for [`java.io.BufferedOutputStream.BufferedOutputStream(OutputStream out, int size)`](http://javadoc.taylorial.com/java.base/io/BufferedOutputStream.html#<init>%28java.io.OutputStream,int%29) * `write(int)` &mdash; follow the Javadoc for [`java.io.BufferedOutputStream.write(int b)`](http://javadoc.taylorial.com/java.base/io/BufferedOutputStream.html#write%28int%29) (with the addition of potentially throwing an `IllegalStateException` as described below). Note that the least significant `byte` of the `int` should be written and the other three bytes ignored (as specified by the [`java.io.OutputStream.write(int b)` method documentation](http://javadoc.taylorial.com/java.base/io/OutputStream.html#write%28int%29)). * `write(byte[])` &mdash; follow the Javadoc for [`java.io.BufferedOutputStream.write(byte[] b, int off, int len)`](http://javadoc.taylorial.com/java.base/io/BufferedOutputStream.html#write%28byte[],int,int%29) where `off==0` and `len==b.length` (with the addition of potentially throwing an `IllegalStateException` as described below) * `flush()` &mdash; follow the Javadoc for [`java.io.BufferedOutputStream.flush()`](http://javadoc.taylorial.com/java.base/io/BufferedOutputStream.html#flush%28%29) (with the addition of potentially throwing an `IllegalStateException` as described below) In addition, you must implement the following method: * `writeBit(int)` &mdash; This method writes the specified bit to this output stream. The bit to be written is the lowest-order bit of the argument `bit`. The 31 high-order bits of `bit` are ignored. E.g., if the integer passed to the method has a value of 0b1111000011110000111100001111000<mark>1</mark>, all but the highlighted bit are ignored. #### Deviation from `java.io.BufferedOutputStream` Javadoc: > If `writeBit()` is called once, seven additional bits will need to be written to complete the partial byte worth of data in the output stream. Once the `writeBit()` method has been called, you must ensure that it is called seven more times before allowing the `flush()` method or any of the `write()` methods to be called. To ensure this, you will need to modify the behavior of the `flush()` and two `write()` methods so that an `IllegalStateException` is thrown if called when a byte in the output stream has only been partially written. I.e., `writeBit()` has been called at least once but not a number of times that is evenly divisible by `8`. ### Testing Class You must design and implement a `Lab5Tests` class that tests your `BufferedInputStream` and `BufferedOutputStream` implementations. Be sure to include the results of your in-lab-activity as a comment at the end of this class. You may use JUnit5 to implement your test class; however, you are not required to do so. You may just create a `main()` method that calls all of your test code. ## Dealing with Bits In order to implement the `readBit()` and `writeBit(int)` methods, you will need to extract/insert a bit from a `byte` or to an `int`. The following binary operators will be useful for this: * `value >> num` &mdash; shift the bits in `value` `num` bits to the right. E.g., `0b00101000 >> 2` produces `0b00001010`. * `value << num` &mdash; shift the bits in `value` `num` bits to the left. E.g., `0b00101000 << 2` produces `0b10100000`. * `value & mask` &mdash; Bitwise AND operator. E.g., `0b001`<mark>`1`</mark>`1000 & 0b010`<mark>`1`</mark>`0101` produces `0b000`<mark>`1`</mark>`0000`. * `value1 | value2` &mdash; Bitwise OR operator. E.g., `0b`<mark>`0`</mark>`01110`<mark>`0`</mark>`0 & 0b`<mark>`0`</mark>`10101`<mark>`0`</mark>`1` produces `0b`<mark>`0`</mark>`11111`<mark>`0`</mark>`1` In order to implement the `readBit()` method, you'll need to extract a single bit from a byte of data. A byte consists of eight bits. To get each bit from a byte, `value` and return it as a `int`, you could do this: ``` Java return value & 0b00000001; // least significant bit return (value >> 1) & 0b00000001; // second-least significant bit return (value >> 2) & 0b00000001; // third-least significant bit return (value >> 3) & 0b00000001; // fourth-least significant bit return (value >> 4) & 0b00000001; // fourth-most significant bit return (value >> 5) & 0b00000001; // third-most significant bit return (value >> 6) & 0b00000001; // second-most significant bit return (value >> 7) & 0b00000001; // most significant bit ``` In order to implement the `writeBit(int)` method, you will need to shift the bit to be written into the appropriate location and then do a bitwise OR with the partially written byte. The first bit in a partially written byte should be located in the most significant bit position. If `bit` is the integer that contains the bit value to be written, you can get the value of the partially written byte by doing the following: ``` Java byte partialByte = (byte)(bit << 7); ``` If you already have a partially written byte, you can merge the new bit into the partially written byte by doing the following: ``` Java partialByte = (byte)((bit << 6) | partialByte); // adds second bit into partially written byte partialByte = (byte)((bit << 5) | partialByte); // adds third bit into partially written byte partialByte = (byte)((bit << 4) | partialByte); // adds fourth bit into partially written byte partialByte = (byte)((bit << 3) | partialByte); // adds fifth bit into partially written byte partialByte = (byte)((bit << 2) | partialByte); // adds sixth bit into partially written byte partialByte = (byte)((bit << 1) | partialByte); // adds seventh bit into partially written byte partialByte = (byte)(bit | partialByte); // adds the last bit to the partially written so // that it is now ready to be sent to the OutputStream ``` ## Just For Fun Movitated students may wish to consider implementing the following once they have completed the requirements for the assignment: * Implement the `BufferedInputStream.read(byte[], int, int)` method * Implement the `BufferedOutputStream.write(byte[], int, int)` method * Experiement with benchmarking different buffer capacities to determine what effect it has on performance * Modify your `Lab5Tests` class to produce appropriately formatted output for each failed test that can be inserted in a student's graded report. See your instructor for details on the format your instructor uses. ## Lab Deliverables > See your professor's instructions for details on submission guidelines and due dates. > * Dr. Taylor's students: See below > * All other students should refer to Blackboard > > If you have any questions, consult your instructor. ## Acknowledgements This assignment was written by [Dr. Chris Taylor](/taylor/). <div class="footnote"> <sup><a href="#fnt__1" id="fn__1" name="fn__1" class="fn_bot">1)</a></sup> Note that a buffer is essentially a fixed length queue. `BufferedInputStream.read()` is analagous to `Queue.poll()`. The `BufferedInputStream` does not have a `Queue.offer()` method. Instead, the `BufferedInputStream` does a bulk load from the `InputStream` whenever the buffer/queue is empty and `read()` is called. Similarly, `BufferOutputStream.write()` is analagous to `Queue.offer()`. Instead of having a `Queue.poll()` method, the `BufferedOutputStream` does a bulk flush to the `OutputStream` when the buffer/queue is filled. <br /> </div>

Tuesday, 09-Apr-2019 14:53:39 CDT