If I create a Channel from an InputStream, and then close the InputStream, will it close the associated Channel? Do I need to close the associated Channel explicitly? I know closing Channel will close Stream, but what about the reverse?
try (InputStream ioStream = getInputStream()) {
ReadableByteChannel inputChannel = Channels.newChannel(ioStream);
//do something
}
In the general case, the InputStream knows nothing about the Channel, so closing the InputStream cannot automatically close the Channel.
However, trying to read from the Channel after the InputStream has been closed will throw an IOException:
the channel has to fetch data from the inputstream through InputStream.getBytes()
InputStream.getBytes() will throw an IOException if the inputstream has been closed.
For the special case of a FileInputStream the Channels.newChannel(ioStream) call will return FileInputStream.getChannel(), so in this special case closing the inputstream will also close the channel.
Looking at the implementation of Channels.newChannel:
public static ReadableByteChannel newChannel(InputStream in) {
Objects.requireNonNull(in, "in");
if (in.getClass() == FileInputStream.class) {
return ((FileInputStream) in).getChannel();
}
return new ReadableByteChannelImpl(in);
}
As you can see, if the input stream is a file stream we have a special case. In this special case the close() method of the resulting channel will just return ! checked, where checked is a private boolean field of the corresponding file input stream. When you close the file input stream it sets the closed to true and then the channel will also think that it's closed:
InputStream is = new FileInputStream(new File("test.file"));
ReadableByteChannel channel = Channels.newChannel(is);
System.out.println(channel.isOpen()); // True
is.close();
System.out.println(channel.isOpen()); // False
However, this is an implementation detail, so you can't rely on it. Also, if the input stream is not a file input stream, then the above will not work at all.
I assume the core of your concern is that you don't have a "leak" by leaving resources open.
As far as I'm aware, so long as the underlying resource gets closed you won't have a leak since that underlying object (with native methods) is what's talking to the OS and keeping the resource open.
Since the documentation says that it simply redirects to the stream (emphasized in bold by me) then closing the InputStream itself will close the only actual resource as Channel.newChannel(InputStream) is not creating a new resource.
I would, however, rather open your Channel in a try-with-resources and let it be closed automatically, which will cascade to the underlying resource.
User Slaw has the correct idea that the InputStream has no knowledge of the Channel (except in the special case of a FileInputStream as shown by Alex). This is one of the reasons you should close your wrapper resources rather than just the underlying resources, so that your wrappers have consistent knowledge of the actual resource.
java.nio.channels.Channels.newChannel(InputStream) - Java 1.8 API
Constructs a channel that reads bytes from the given stream.
The resulting channel will not be buffered; it will simply redirect its I/O operations to the given stream. Closing the channel will in turn cause the stream to be closed.
Parameters:
in - The stream from which bytes are to be read
Returns:
A new readable byte channel
From Java API 7:
The resulting channel will not be buffered; it will simply redirect its I/O operations to the given stream. Closing the channel will in turn cause the stream to be closed.
Hope it helps!
Related
It is very common to get an InputStream from URLConnection like so:
InputStream stream = connection.getInputStream();
where connection is a URLConnection.
https://developer.android.com/reference/java/net/URLConnection.html#getInputStream()
I have a situation where I would like to reuse a stream. I have access to the connection object and my question now is does a single instance of a URLConnection return the 'same' InputStream every time ? That is if I call connection.getInputStream() again (but for the same connection object) will I be getting a new stream ?
In general, the answer to this kind of question ("Does X do Y?") is: Does the documentation say X does Y? If so, yes (or it's broken); if not, you have no guarantee so and must assume not.
So let's look at URLConnection#getInputStream's documentation:
Returns an input stream that reads from this open connection. A SocketTimeoutException can be thrown when reading from the returned input stream if the read timeout expires before data is available for read.
Returns:
an input stream that reads from this open connection.
So you can't rely on it doing so, because it doesn't promise to. (I also looked elsewhere in the JavaDoc for URLConnection.)
(My tests outside Android suggest that HttpURLConnection does at least sometimes, though.)
URLConnection is an interface and it all depends on the implementors if the getInputStream returns a new stream or not.
The best way to verify this is...
URLConnection con = new URL(MY_URL_STRING).openConnection() ;
InputStream in1 = con.getInputStream();
InputStream in2 = con.getInputStream();
boolean streamEquals = in1.equals(in2);
It doesn't matter. It wouldn't make any difference whether it did or it didn't. Consider a method that always returns new DataInputStream(socket.getInputStream()). (I don't claim it is implemented like that: we are just considering.) There is nothing practical you can do with the stream short of comparing it with == that would tell you whether it was a new stream each time like that or always the same stream. What you read out of it is not affected.
bis = new BufferedInputStream(connection.getInputStream(), 8192);
(use bis)
bis.close;
In this case, has the inputStream created in the connection been closed (when not autocloseable)? Is there a way I could have found this answer out myself with code?
Usually, all stream wrappers in Java API propagate close method calls to the wrapped objects. So no, you don't have to call it on the wrapped stream - the connection input stream.
I have a problem with a BufferedOutputStream. I want to send a kml file from an Android device to a java server through a socket connection.
(The connection is ok, i am already able to exchange data with a PrintWriter in an other part of my program)
To send my kml file, I fill the buffer. But when i flush() it, nothing happen.
int lu = inFile.read();
while(lu != -1){
out.write(lu);
lu = inFile.read();
}
out.flush();
inFile.close();
inFile is my stream used to read the kml file
out is my BufferedOutputStream using the OutputStream of my socket
I don't close my out object but i don't want to, i don't use it just once. And this is the problem...
The close() method send the buffer's data but close the socket too.
The flush() method does not send the buffer's data.
I want to flush the buffer without closing my socket.
I also tried to use mySocket.shutdownOutput();
int lu = inFile.read();
while(lu != -1){
out.write(lu);
lu = inFile.read();
}
out.flush();
mySocket.shutdownOutput();
inFile.close();
This method close my stream and keep my socket open, that's what i want.
But when i try to open a new output stream, the Exception java.net.SocketException: Socket output is shutdown
So, how to flush my buffer without closing my sokcet are being unable to open a new output stream ?
Socket.close() and Socket.shutdownOutput() both send an EOS to the peer, on which he should close the socket, and after which you can no longer write to the socket, because you've closed it in that direction.
So if you need to continue writing to the socket you cannot use either of these methods.
Probably what you are searching for is a way to delimit application protocol messages. There are at least three techniques:
Send a length word prior to each message.
Send an out-of-band delimiter after each message, i.e. a byte or byte sequence that cannot occur in a message. The STX/ETX protocol, with escapes, is an example of this.
Use a self-describing message format such as Object Serialization or XML. STX/ETX is also an example of this.
Class c extends thread
static Queue<Socket> socketQueue
Make connection to another server or client
And then add socket to socketqueue
Class a extends thread
method a
bufferedinputstream bis = socketQueue.poll
Do work
Make bis null without closing it<br>
Class b extends thread
Method b
Bufferedinputstream bis = socketqueue.poll
Do work
Make bis null without closing it
I did make bufferedinput stream null since i do not want to close the connected socket. Several posts were telling me that closing input/output stream would close the socket as well.
Whenever I use input/output stream with socket, I usually close stream and socket if its not null.
What I am trying to do here is to make the socket alive and reuse when input or output stream is needed without connecting again.
I tried socket.shutdowninput and output, however, this throws an exception when i make another input/output stream with the socket.
Is there anything I have misunderstood or am missing at this point?
A connection over a socket only ever has one InputStream and one OutputStream. As soon as you close any of those (or the Socket itself) the connection is automatically closed. You need to store the streams you need somewhere and use those, you can not get them from the same Socket each time you need them.
I write a client-server application which will be sending an .xml file from the client to the server. I have a problem with sending large data. I notice that the server can get at most 1460 bytes. When I send a file with more than 1460 bytes the server gets only first 1460 bytes and nothng more. In effect I get uncompleted file. Here is my code:
client send:
public void sendToServer(File file) throws Exception
{
OutputStream output = sk.getOutputStream();
FileInputStream fileInputStream = new FileInputStream(file);
byte[] buffer = new byte[1024*1024];
int bytesRead = 0;
while((bytesRead = fileInputStream.read(buffer))>0)
{
output.write(buffer,0,bytesRead);
}
fileInputStream.close();
}
server get:
public File getFile(String name) throws Exception
{
File file=null;
InputStream input = sk.getInputStream();
file = new File("C://protokolPliki/" + name);
FileOutputStream out = new FileOutputStream(file);
byte[] buffer = new byte[1024*1024];
int bytesReceived = 0;
while((bytesReceived = input.read(buffer))>0) {
out.write(buffer,0,bytesReceived);
System.out.println(bytesReceived);
break;
}
return file;
}
Do anyone know what is wrong with this code? Thanks for any help.
EDIT:
Nothing help :(. I google about that and I think its may connected with TCP MSS with is equal 1460 bytes.
Make sure you call flush() on the streams.
A passerby asks: isn't close() enough?
You linked to the docs for Writer, and the info. on the close() method states..
Closes the stream, flushing it first. ..
So you are partly right, OTOH, the OP is clearly using an OutputStream and the docs for close() state:
Closes this output stream and releases any system resources associated with this stream. The general contract of close is that it closes the output stream. A closed stream cannot perform output operations and cannot be reopened.
The close method of OutputStream does nothing.
(Emphasis mine.)
So to sum up. No, calling close() on a plain OutputStream will have no effect, and might as well be removed by the compiler.
Although not relate to your question, the API document said FileInputStream.read returns -1 for end of file. You should use >=0 for the while loop.
The MTU (Maximum Transmission Unit) for Ethernet is around 1500 bytes. Consider sending the file in chunks (i.e. one line at a time or 1024 bytes at a time).
See if using 1024 instead of 1024 * 1024 for the byte buffer solves your problem.
In the code executed on the server side, there is a break instruction in the while loop. Therefore the code in the loop will only get executed once. Remove the break instruction and the code should work just fine.