Extending OutputStream class; write(int) method - java

So my goal is to implement the write method in the class OutputStream to create a new class NumStream, which basically converts ints to Strings. Here is my sample code:
import java.io.*;
public class NumStream extends OutputStream {
public void write(int c) throws IOException {
// What goes here?
}
public static void main(String[] args) {
NumStream ns = new NumStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(ns));
pw.println("123456789 and ! and # ");
pw.flush(); // needed for anything to happen, try taking it out
}
}
I've tried using several different approaches, and my result always results in the program compiling, but when I run it, nothing happens. So far I've tried using switch statements to produce this result:
public void write(int c) throws IOException {
StringBuffer sb = new StringBuffer();
switch (c) {
case 1: sb.append("1");
break;
//etc. through 9
I'm unsure of what to do or try next to produce a result. :/ Any tips to steer me in the right direction?

I had the same problem too, Here is the solution:
public class MyOutputStream extends OutputStream {
StringBuilder anotatedText;
public MyOutputStream() {
// Custom constructor
}
#Override
public void write(int b) {
int[] bytes = {b};
write(bytes, 0, bytes.length);
}
public void write(int[] bytes, int offset, int length) {
String s = new String(bytes, offset, length);
anotatedText.append(s);
}
public void myPrint() {
System.out.println(anotatedText);
}
}
All we need to do is to implement the "write" method correctly which is clearly instructed in the above example.

Related

Java equivalent to python's "with"

Python has a nice feature: the "with" statement. It's useful for making global changes that affect all code called within the statement.
e.g. you could define a class CapturePrintStatements to capture all print statements called within the "with"
with CapturePrintStatements() as c:
print 'Stuff Done'
print 'More Stuff Done'
assert c.get_text() == 'Stuff Done'
Is there an equivalent in Java?
try-with-resources is its Java equivalent, and is available in Java 7 and up.
That gives you the possibility to work with resources that need to be explicitly closed, without worrying about closing them. For the example:
Before Java7:
InputStream input = null;
try {
input = new FileInputStream("myFile.txt");
} finally {
if(input != null){
input.close();
}
}
Java 7 & up:
try(FileInputStream input = new FileInputStream("myFile.txt")) {
// Do something with the InputStream
}
This is the try-with-resources construct. When the execution flow will go out of the try block, the FileInputStream will be closed automatically. This is due to the fact that FileInputStream implements the AutoCloseable interface.
As Mohammed noted, you can use try-with-resources. In this case, you want to have your own resource, and it is not really difficult to do.
Creating an auto-closeable class
First, your class should implement AutoCloseable:
public class CaptureOutput implements AutoCloseable {
When constructing this class, you should
store the old System.out,
create a PrintStream to replace it (cf. Java: PrintStream to String?) and
replace the default stream with System.setOut().
Here is how we do it
public CaptureOutput() {
this.stream = new ByteArrayOutputStream();
this.out = System.out;
System.setOut(new PrintStream(stream));
}
The secret is the AutoCloseable.close() method: you just undo your replacement there:
public void close() throws Exception {
System.setOut(this.out);
}
Finally, you need a method to retrieve the content:
public String getContent() {
return this.stream.toString();
}
Using try-with-resources
Done that, just pass the CaptureOutput to the try clause. The code below, for example...
public static void main(String[] args) throws Exception {
String content = null;
System.out.println("This will be printed");
try (CaptureOutput co = new CaptureOutput()) {
System.out.println("EXAMPLE");
content = co.getContent();
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + content);
}
...will result on this:
This will be printed
This will be printed, too.
The content of the string is EXAMPLE
Scope issues
Note that we do not call co.getContent() at the last line. It is not possible because, unlike Python, the co variable is scoped inside the try clause. Once the try block finishes, it is gone.[1] That's why we get the value from inside the block.
Not that elegant, right? A solution may be to give the BAOS to the CaptureOutput constructor:
public CaptureOutput(ByteArrayOutputStream stream) {
this.stream = stream;
this.out = System.out;
System.setOut(new PrintStream(this.stream));
}
Now, we just use the stream later:
public static void main(String[] args) throws Exception {
System.out.println("This will be printed");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try (CaptureOutput co = new CaptureOutput(stream)) {
System.out.println("EXAMPLE");
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + stream.toString());
}
(Also, it is not possible to create the CaptureOutput variable before the try. That makes sense: AutoCloseable objects are supposed to be "closed" after their use. What's the use of a closed file, after all? Our use case is a bit different from that, so we have to rely on alternatives.)
The full classes
And here are the full classes:
CaptureOutput.java:
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
public class CaptureOutput implements AutoCloseable {
private ByteArrayOutputStream stream;
private PrintStream out;
public CaptureOutput(ByteArrayOutputStream stream) {
this.stream = stream;
this.out = System.out;
System.setOut(new PrintStream(this.stream));
}
public CaptureOutput() {
this(new ByteArrayOutputStream());
}
#Override
public void close() throws Exception {
System.setOut(this.out);
}
public String getContent() {
return this.stream.toString();
}
}
Main.java:
import java.io.ByteArrayOutputStream;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("This will be printed");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try (CaptureOutput co = new CaptureOutput(stream)) {
System.out.println("EXAMPLE");
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + stream.toString());
}
}

Count the bytes written to file via BufferedWriter formed by GZIPOutputStream

I have a BufferedWriter as shown below:
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
new GZIPOutputStream( hdfs.create(filepath, true ))));
String line = "text";
writer.write(line);
I want to find out the bytes written to the file with out querying file like
hdfs = FileSystem.get( new URI( "hdfs://localhost:8020" ), configuration );
filepath = new Path("path");
hdfs.getFileStatus(filepath).getLen();
as it will add overhead and I don't want that.
Also I cant do this:
line.getBytes().length;
As it give size before compression.
You can use the CountingOutputStream from Apache commons IO library.
Place it between the GZIPOutputStream and the file Outputstream (hdfs.create(..)).
After writing the content to the file you can read the number of written bytes from the CountingOutputStream instance.
If this isn't too late and you are using 1.7+ and you don't wan't to pull in an entire library like Guava or Commons-IO, you can just extend the GZIPOutputStream and obtain the data from the associated Deflater like so:
public class MyGZIPOutputStream extends GZIPOutputStream {
public MyGZIPOutputStream(OutputStream out) throws IOException {
super(out);
}
public long getBytesRead() {
return def.getBytesRead();
}
public long getBytesWritten() {
return def.getBytesWritten();
}
public void setLevel(int level) {
def.setLevel(level);
}
}
You can make you own descendant of OutputStream and count how many time write method was invoked
This is similar to the response by Olaseni, but I moved the counting into the BufferedOutputStream rather than the GZIPOutputStream, and this is more robust, since def.getBytesRead() in Olaseni's answer is not available after the stream has been closed.
With the implementation below, you can supply your own AtomicLong to the constructor so that you can assign the CountingBufferedOutputStream in a try-with-resources block, but still retrieve the count after the block has exited (i.e. after the file is closed).
public static class CountingBufferedOutputStream extends BufferedOutputStream {
private final AtomicLong bytesWritten;
public CountingBufferedOutputStream(OutputStream out) throws IOException {
super(out);
this.bytesWritten = new AtomicLong();
}
public CountingBufferedOutputStream(OutputStream out, int bufSize) throws IOException {
super(out, bufSize);
this.bytesWritten = new AtomicLong();
}
public CountingBufferedOutputStream(OutputStream out, int bufSize, AtomicLong bytesWritten)
throws IOException {
super(out, bufSize);
this.bytesWritten = bytesWritten;
}
#Override
public void write(byte[] b) throws IOException {
super.write(b);
bytesWritten.addAndGet(b.length);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
super.write(b, off, len);
bytesWritten.addAndGet(len);
}
#Override
public synchronized void write(int b) throws IOException {
super.write(b);
bytesWritten.incrementAndGet();
}
public long getBytesWritten() {
return bytesWritten.get();
}
}

Append to ObjectOutputStream iteratively

I want to add lots of data to a file. I defined the HYB class since my object contains ofdifferent types of data (String and byte[]). I used ObjectOutputStream and ObjectInputStream to write and read from the file. But my code does not print the expected result. To write my code I used code in the following pages:
How can I append to an existing java.io.ObjectStream?
ClassCastException when Appending Object OutputStream
I try to debug my code and found the problem but I could not. This is my code:
import java.io.*;
import java.io.BufferedOutputStream;
import java.util.*;
public class HYB implements Serializable
{
private static final long serialVersionUID = 1L;
private List<byte[]> data = new ArrayList<>();
public void addRow(String s,byte[] a)
{
data.add(s.getBytes()); // add encoding if necessary
data.add(a);
}
#Override public String toString()
{
StringBuilder sb = new StringBuilder();
synchronized (data)
{
for(int i=0;i<data.size();i+=2)
{
sb.append(new String(data.get(i)));
sb.append(Arrays.toString(data.get(i+1))+"\n");
}
}
return sb.toString();
}
private static void write(File storageFile, HYB hf)
throws IOException {
ObjectOutputStream oos = getOOS(storageFile);
oos.writeObject(hf);
oos.flush();
oos.close();
}
public static ObjectOutputStream getOOS(File file) throws IOException
{
if (file.exists()) {
return new AppendableObjectOutputStream(new FileOutputStream(file, true));
} else {
return new ObjectOutputStream(new FileOutputStream(file));
}
}
private static ObjectInputStream getOIS(FileInputStream fis)
throws IOException {
long pos = fis.getChannel().position();
return pos == 0 ? new ObjectInputStream(fis) :
new AppendableObjectInputStream(fis);
}
private static class AppendableObjectOutputStream extends
ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out)
throws IOException {
super(out);
}
#Override
protected void writeStreamHeader() throws IOException {
}
}
private static class AppendableObjectInputStream extends ObjectInputStream {
public AppendableObjectInputStream(InputStream in) throws IOException {
super(in);
}
#Override
protected void readStreamHeader() throws IOException {
// do not read a header
}
}
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException
{
File x=new File ("test");
HYB hf1 = new HYB();
hf1.addRow("fatemeh",new byte[] {11,12,13});
hf1.addRow("andisheh",new byte[] {14,15,16});
write(x,hf1);
HYB hf = new HYB();
hf.addRow("peter",new byte[] {1,2,3});
hf.addRow("jaqueline",new byte[] {4,5,6});
write(x,hf);
FileInputStream fis = new FileInputStream(x);
HYB hf2 = (HYB) getOIS(fis).readObject();
System.out.println(hf2);
}
}
expected results:
fatemeh[11, 12, 13]
andisheh[14, 15, 16]
peter[1, 2, 3]
jaqueline[4, 5, 6]
actual results:
fatemeh[11, 12, 13]
andisheh[14, 15, 16]
Writing the two HYB objects to the ObjectOutputStream doesn't merge them into a single HYB object; the ObjectOutputStream still contains two HYB object, of which your code reads one. If you did a second call to readObject(), the second one would be retrieved and could be printed to the screen. So you could just wrap the readObject() and println() calls in a loop that reads/writes until there's nothing else to read from the stream.
You are writing two HYB objects to the stream, but only reading one out.
You need to readObject() twice.

Testing output of void main with Console.readline() involved

I need to junit test an existing code by the output ( in system.out )
public static void main(String args[])
{
Console console = System.console();
String str = console.readLine();
System.out.println("halo"+str);
}
Since the console.readline is waiting for user input, I found it will halt in the console.readline(),thus block me from getting the output.
Is there a way to do this? Is it posible to do it using Mockito or something?
It is nearly impossible to test code that works with System.console(), because you System.console() always retuns null in tests. Additionally Console is final class without a public constructor.
I recommend to work with the writers and readers of Console and test the code that works with the writers and readers.
public static void main(String args[]) {
Console console = System.console();
BufferedReader reader = new BufferedReader(console.reader());
main2(reader, console.writer(), args);
}
static void main2(BufferedReader reader, Writer writer, String args[] {
String str = reader.readline();
System.out.println("halo"+str);
}
Output to System.out can be tested with the StandardOutputStreamLog rule of the System Rules library. But in your code it is much easier to write to the Console's writer instead of System.out.
The main method is not a good candidate for unit testing. It is just an entry point for an application. Probably, you need to refactor your class to some kind of dependency injection. For example:
public class Something {
private final LinesProvider linesProvider;
public Something(LinesProvider linesProvider) {
this.linesProvider = linesProvider;
}
public void sayHello() {
String str = linesProvider.readLine();
System.out.println("halo "+str);
}
public static void main(String args[]) {
new Something(new LinesProvider() {
private final Console console = System.console();
#Override
public String readLine() {
return console.readLine();
}
}).sayHello();
}
}
interface LinesProvider {
String readLine();
}
Then, you can test the system output like shown below, though it's not a good practice. Instead, try to separate I/O logic from application logic:
public class TestSomething {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private PrintStream printStream = new PrintStream(outputStream, true);
#Before
public void setUp() {
System.setOut(printStream);
}
#Test
public void test() {
new Something(new LinesProvider() {
#Override
public String readLine() {
return "Vasya";
}
}).sayHello();
assertEquals("halo Vasya" + System.getProperty("line.separator"), new String(outputStream.toByteArray()));
}
}
The following test will work, using the JMockit mocking API:
#Test
public void testMyApp(#Mocked final Console console)
{
new NonStrictExpectations(System.class) {{
System.console(); result = console;
console.readLine(); result = " test";
}};
OutputStream output = new ByteArrayOutputStream();
System.setOut(new PrintStream(output));
MyApp.main(new String[0]);
String lineSep = System.getProperty("line.separator");
assertEquals("halo test" + lineSep, output.toString());
}

Record size of objects as they're being serialized?

What's the best way to record the size of certain objects as they are being serialized? For example, once objects of type A, B, C are serialized, record the size of their serialized bytes. We can get the size of the entire object graph via getBytes, but we'd like to break it down as to what are the largest contributors to the overall serialized size.
ObjectOutputStream offers writeObjectOverride, but we don't want to rewrite the serialization process. In simplified terms, we need to be aware of when we encounter a certain object prior to serialization, record the total current byte count, and then after it's serialized, take the difference of byte counts. It seems like encompassing writeSerialData would work, but the method is private.
Ideas?
Thanks.
--- UPDATE ---
The answers/suggestions below are insightful. Below is what I have so far. Let me know your thoughts. Thanks.
// extend to get a handle on outputstream
MyObjectOutputStream extends ObjectOutputStream {
private OutputStream out;
public MyObjectOutputStream(out) {
super(out);
this.out = out;
}
public OutputStream getOut() {
return this.out;
}
}
// counter
public static class CounterOutputStream extends FilterOutputStream {
private int bytesWritten = 0;
...
public int getBytesWritten() {
return this.bytesWritten;
}
public void resetCounter() {
bytesWritten = 0;
}
private void update(int len) {
bytesWritten += len;
}
}
// go serialize
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new MyObjectOutputStream(new CounterOutputStream(out, 1024));
// record serialized size of this class; do this for every interested class
public class MyInterestingObject {
...
private void writeObject(ObjectOutputStream out) throws IOException {
CounterOutputStream counter = null;
if (out instanceof MyObjectOutputStream) {
counter = (CounterOutputStream)((MyObjectOutputStream)out).getOut();
counter.resetCounter();
}
// continue w/ standard serialization of this object
out.defaultWriteObject();
if (counter != null) {
logger.info(this.getClass() + " bytes written: " + counter.getBytesWritten());
// TODO: store in context or somewhere to be aggregated post-serialization
}
}
}
The simplest solution would be to wrap the OutputStream you're using with an implementation that will count bytes written.
import java.io.IOException;
import java.io.OutputStream;
public class CountingOutputStream extends OutputStream {
private int count;
private OutputStream out;
public CountingOutputStream(OutputStream out) {
this.out = out;
}
public void write(byte[] b) throws IOException {
out.write(b);
count += b.length;
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
count += len;
}
public void flush() throws IOException {
out.flush();
}
public void close() throws IOException {
out.close();
}
public void write(int b) throws IOException {
out.write(b);
count++;
}
public int getBytesWritten() {
return count;
}
}
Then you would just use that
CountingOutputStream s = new CountingOutputStream(out);
ObjectOutputStream o = new ObjectOutputStream(s);
o.write(new Object());
o.close();
// s.getBytesWritten()
You could implement Externalizable rather than Serializable on any objects you need to capture such data from. You could then implement field-by-field byte counting in the writeExternal method, maybe by handing off to a utility class. Something like
public void writeExternal(ObjectOutput out) throws IOException
{
super.writeExternal(out);
out.writeUTF(this.myString == null ? "" : this.myString);
ByteCounter.getInstance().log("MyClass", "myString", this.myString);
}
Another hackish way would be to stick with Serializable, but to use the readResolve or writeReplace hooks to capture whatever data you need, e.g.
public class Test implements Serializable
{
private String s;
public Test(String s)
{
this.s = s;
}
private Object readResolve()
{
System.err.format("%s,%s,%s,%d\n", "readResolve", "Test", "s", s.length());
return this;
}
private Object writeReplace()
{
System.err.format("%s,%s,%s,%d\n", "writeReplace", "Test", "s", s.length());
return this;
}
public static void main(String[] args) throws Exception
{
File tmp = File.createTempFile("foo", "tmp");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(tmp));
Test test = new Test("hello world");
out.writeObject(test);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(tmp));
test = (Test)in.readObject();
in.close();
}
}

Categories

Resources