Link to home
Create AccountLog in
Avatar of slickdeals
slickdeals

asked on

What do mark and reset methods of InputStream really help us with?

Well working with java io i found these two methods really hard to understand.

Read the code:

Please can some one explain me in detail what this mark and reset buy me.

FYI: Also the BufferedInputStream is default initialized to 8192 bytes.




DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath)));
 
din.mark(4)
 
// do some logic like 
din.readInt()
din.getFload()
 
// now reset
din.reset();

Open in new window

Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Yes - i can't remember, btw if mark/reset are supported in the class - you can of course call isMarkSupported to find out

The methods are basically there to introduce a small level of random access functionality. Normally a stream is read serially from beginning to end but with mark and reset, you can mark a position so that positioin can be read again. Reset moves the stream pointer to the position marked
Here's an example from Struts - it's being used to allow the stream to be re-read fully, so the mark is therefore set right at the end of the file:

http://www.jajakarta.org/struts/struts1.0/en/src/share/org/apache/struts/upload/MultipartIterator.java
Also, sometimes when working on data that lacks symmetry or predictability (lengths of records vary, delimiters of different types occur, or even the data may be corrupted etc etc) you may need to go back and re-read some data, given that new information. This can help you do that. Also PushBackReader allows you to put bytes back onto the inputstream again. As CEHJ says, mark() and reset() are callable on these streams.
Avatar of slickdeals
slickdeals

ASKER

My mark on the above mentioned code works even tough DataInputStream does not support mark() because of the decoration of BufferedInputStream.

When I did mark(4) in the debugger saw the markPosition change from -1 to 0.

What is this behavior and why?

>>because of the decoration of BufferedInputStream.

That's right

>>What is this behavior and why?

Not sure. I think i'd sooner trust the output from a debugging log statement
>> even tough DataInputStream does not support mark()  <<

sorry ... why? Both DataInputStream and BufferedinputStream support mark() reset(); the latter through the former. Or ... ?
DataInputStream is not overriding the mark behavior.. That is why it gets delegated to the decorator class which is bufferedInputstream.

Can u give me more example where we might need mark and then reset.
Yes, that's right DataInputStream supports mark/reset
>>DataInputStream is not overriding the mark behavior.. That is why it gets delegated to the decorator class which is bufferedInputstream.<< I think you misunderstand inheritance in this instance. BufferedInputStream uses the InputStream's mark() and reset() methods - that's what inheritance is about - unless your class is overriding it. If so, where is your class?
>>DataInputStream is not overriding the mark behavior.

Yes it supports mark/reset in its own right
Well, sorry, overriding FilterInputStream's mark(). That's a maximum number of bytes to read in that case.
what does that mean that it is supporting mark/reset in its own right.

Say if you have something like this new DataInputStream(//inputStream that does not support mark).
We will get no behavior then.
>>Yes it supports mark/reset in its own right

Incorrect - it defers to its 'decoree' - to coin an awful term
SOLUTION
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
may be it is my English or what but is still cannot get the idea of mark/rest

Questions that come to my head are like:

What happens if i read the entire stream and do a reset(). Remember I have not marked anything?
What happens if we mark() and forget to reset() -- ie doing a conditional reset()

In general I really can't capture the idea of mark() method eg say i read my stream and then did mark(4) now if I do reset() where will i read from ...

Please explain me in detail this mark and reset business ... thakyou guys for all your time. It really helps ... to know that u have great experts to advice.
If you read the entire stream then you're at the end of stream. If you reset() at that point, then you'll get an IOException if the stream has not been marked or if the mark has been invalidated.

If you mark() and don't reset, then no effect. If you are doing this in a conditional context as you said, then you'd probably need to have a default handler, since you are implying that you might have cases with which you cannot foresee contending at the time.

If you do a mark(4) and then a reset, it will read again from the place where you made the mark. The (4) is a read limit before it becomes invalid.

Use them as a pair - obviously. The (4) syntax is relevant since a buffer is involved in this case remember. Essentially, it's the same as mark().

If you ran the code I chopped in above, you'd see from the System.outs what's happening.
>>if you do a mark(4) and then a reset, it will read again from the place where you made the mark.

Can u please elaborate and explain me this thing again.

BTW: I tried the code. After reading the 4 bytes we did a mark() and then kept reset(). Which made us read the same byte. I really didnt understand the point.
>>BTW: I tried the code. After reading the 4 bytes we did a mark() and then kept reset(). Which made us read the same byte. I really didnt understand the point. <<

Well, the loop was there just to show how mark() and reset() work. The file was first mark()ed one int from the end, and then in the loop,  reset() was called several times just to show that reset always reset to the same point (hence the repeated printing of the variable). It's just like rewinding a VCR to a given point, and playing it again.
I really dont understand what mark and reset accomplished me for this piece of code I have pasted. Please explain ...

Thankyou for being so patient.
public static void main(String[] args) throws Exception{
		String s = "This mark sign will get me back to the mark.";
		byte[] buf = s.getBytes();
		ByteArrayInputStream bais = new ByteArrayInputStream(buf);
		BufferedInputStream bis  = new BufferedInputStream(bais);
		
		bis.mark(10);
		
		int c;
		while((c = bis.read())!= -1){
			System.out.print((char) c);
		}
		bis.reset();
			
		int d;
		while((d = bis.read())!= -1){
			System.out.print((char) d);
		}
		
	}

Open in new window

No, nor do I, sorry about that.
ASKER CERTIFIED SOLUTION
Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
>>bis.mark(buf.length - cursor);

This is the same as : bis.mark(cursor); = bis.mark(0);


since the (n) is only an invalidation delta.
Oh - it's CEHJ, overlooked that. ;)

Please try marking with (0) though.
BTW, slickdeals, using a one-byte buffer to read in your chars is meaningless in this context, because mark(n) cannot be invalidated where n >= 1.
Krakatoa,
>> BTW, slickdeals, using a one-byte buffer to read in your chars is meaningless in this context, because mark(n) cannot be invalidated where n >= 1.

can u please explain what do you mean by one-byte buffer ... may be i will be able to get the whole thing ...

hey chej/krakatoa,

Ur explanation does exactly what u had mentioned before of the behavior of rewind. Thanx.

This means the parameter of readBytes to the mark method is meaningless ... since the mark is still active even if we read bytes more than we have pass as an argument to the mark method.

eg. if we pass mark(10). After reading 10 bytes the mark should be invalidated and reset should return to the mark position. But we don't see this behavior ... correct me so that we can get to the end of this questions. Thankyou ...
Not so fast :
>>and reset should return to the mark position. <<

No.
1 : >This means the parameter of readBytes to the mark method is meaningless ... since the mark is still active even if we read bytes more than we have pass as an argument to the mark method.<

i) 'parameter' is not meaningless because, without it, you will not be able to call mark on a BufferedInputStream; that's the VM contract - end of story.

ii) an Exception (IOException) *might* be thrown *if* the mark has become invalidated.

iii) from unofficial Docs. : "The general contract of mark is that, if the method markSupported returns true, the stream somehow remembers all the bytes read after the call to mark and stands ready to supply those same bytes again if and whenever the method reset is called. However, the stream is not required to remember any data at all if more than readlimit bytes are read from the stream before reset is called. "

iv) You have access to the buffer's contents, not to the underlying stream which is used to fill the buffer. From unofficial Docs. : "This subclass buffers input from an underlying implementation to provide a possibly more efficient read mechanism. It maintains the buffer and buffer state in instance variables that are available to subclasses. The default buffer size of 2048 bytes can be overridden by the creator of the stream.

This class also implements mark/reset functionality. It is capable of remembering any number of input bytes, to the limits of system memory or the size of Integer.MAX_VALUE."

2.>if we pass mark(10). After reading 10 bytes the mark should be invalidated and reset should return to the mark position. But we don't see this behavior ... correct me so that we can get to the end of this questions. Thankyou ...<

In my loopy code above, reset() can be called multiple times against a call to mark(4). But all the time that loop is running, there is no more data being read into the buffer from the underlying stream - just the read pointer into the buffer is being reset to a given position. That's not the same thing as invalidating the mark.
:-)