GrowinMan
GrowinMan

Reputation: 4907

How can you force a flush on an OutputStream object without closing it?

My question lies on the following assumptions which I hope are true, because I believe these as I read them while Googling my problems:

  1. Closing a Socket's OutputStream closes the socket too
  2. The flush() method of OutputStream does nothing

So I basically need to anyhow flush the data out of my OutputStream object for my app to work.

If you're interested in details then please see the following two links :

. Weird behavior : sending image from Android phone to Java server (code working)

This issue was resolved by closing the OutputStream. Doing that flushed all the data to the other end of the socket and made my app working further but this fix soon gave rise to problem number 2 - the corresponding socket also gets closed :

. SocketException - 'Socket is closed' even when isConnected() returns true

Upvotes: 6

Views: 23847

Answers (7)

ceph3us
ceph3us

Reputation: 7474

YES on Android flush() do nothing (example based on api 23)

public Socket() {
    this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();
    this.proxy = null;
}

public class PlainSocketImpl extends SocketImpl {

    @Override protected synchronized OutputStream getOutputStream() throws IOException {
        checkNotClosed();
        return new PlainSocketOutputStream(this);
    }


}

private static class PlainSocketOutputStream extends OutputStream {
        // doesn't override base class flush();
}

to flush output stream without closing socket you can shutdown output:

protected void shutdownOutput() throws IOException

-- this will close WRITE file descriptor.

instead of using output stream you can write directly to file descriptor or by creating own Socket implementation with OutputStream which will override flush method (for example using a Berkeley socket implementation in c (via native call).

It doesn't need to do anything. Writing to a socket output stream directly isn't buffered by Java, so there is nothing to flush. -user207421

  • we talking here about dalvik/art jvm implementation
  • tho op wanted confirmation on 2 questions & both were answered here

Upvotes: -1

user207421
user207421

Reputation: 310913

Closing a Socket's OutputStream closes the socket too

True.

The flush() method of OutputStream does nothing

False. There are overrides. See the Javadoc for FilterOutputStream.flush(), BufferedOutputStream.flush(), ObjectOutputStream.flush(), to name a few. All the streams that can buffer output internally have flush() methods. All the streams that don't, don't. Specifically, the output stream resulting from Socket.getOutputStream() is not buffered and does not override flush().

So your initial problem is non-existent, so you have no need for the 'solution' that causes problem #2.

Upvotes: 1

Stephen C
Stephen C

Reputation: 718816

The flush() method of OutputStream does nothing.

This is incorrect.

It is true that the base implementation of flush() provided by the OutputStream class does nothing. However, your app will be calling the version of that method that is provided by actual stream class that you are using. If the stream class doesn't have direct write semantics, it will override flush() to do what is required.

In short, if a flush is required (and it is required for a Socket output stream), then calling flush() will do the right thing. (If some internet source tells you otherwise it is either wrong or you are misinterpreting it.)


FYI, the reason that the base OutputStream implements flush() as a no-op is that:

  • some output stream classes don't need to do anything when flushed; e.g ByteArrayOutputStream, and
  • for the stream classes where flush() is not a no-op, there is no way to implement the operation at the base class level.

They could (in theory) have made designed the stream APIs so that OutputStream was an abstract class (and flush() an abstract method) or an interface. However this API was effectively frozen prior to Java 1.0, and at that time there wasn't enough experience with practical Java programming to realize that the API design was suboptimal.

Upvotes: 4

user3248022
user3248022

Reputation: 1

I had the same problem. Add "\n" at the end of the stream. flush works but the destinary does not know if the message ended

Upvotes: -1

everforth
everforth

Reputation: 1

I'll take a stab at it. I was having the same problem. closing the outputstream is the only way i can "flush" the data. but since i still need the outputstream that's not an option. so 1st i send the byte array length, out.writeInt, then the array itself. when all bytes have been read ie buffer.length == in.readInt() i break loop

    ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    byte[] fileBytes;
    int n;
    int length;

    try
    {
        size = in.readInt();

        while((n = in.read(buffer)) != -1)
        {
            dataBuffer.write(buffer, 0, n);

            if(dataBuffer.toByteArray().length == length)
            {
                fileBytes = dataBuffer.toByteArray(); break;
            }
        }
    }

Upvotes: -1

infografnet
infografnet

Reputation: 4005

Do you really need to flush? I also had an issue, where listener on c# server couldn't receive data sent from android (I tried to get the data synchronously).

I was sure that this is because on Android side, the following code didn't flush.

OutputStream str = btSocket.getOutputStream();
str.write(data_byte);
// "This implementation does nothing"
str.flush();

It turned out, that if I use asynchronous data retrieval on server's listener - it gets the data, and no flush() on client's side is required!

Upvotes: 0

smichak
smichak

Reputation: 4958

You can call the flush method of OutputStream instead of close. The concrete classes inheriting from OutputStream will override flush() to do something other than nothing (writing the data to a file or sending it over the network).

Upvotes: 6

Related Questions