1

I get this error when I read an InputStream and try to used it again.

07-20 17:36:24.762  11253-11277/? W/System.err﹕ java.io.IOException
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at java.io.InputStream.reset(InputStream.java:208)
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at demo31.com.maps.GMapDirections$DownloadDocumentTask.doInBackground(GMapDirections.java:134)
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at demo31.com.maps.GMapDirections$DownloadDocumentTask.doInBackground(GMapDirections.java:86)
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at android.os.AsyncTask$2.call(AsyncTask.java:292)
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at javautil.concurrent.FutureTask.run(FutureTask.java:237)
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
07-20 17:36:24.762  11253-11277/? W/System.err﹕ at java.lang.Thread.run(Thread.java:818)
07-20 17:36:24.762  11253-11277/? D/GMapDirections﹕ Exception while downloading data: java.io.IOException

The code that I'm using is ...

@Override
protected Document doInBackground(ArrayList... latLngs) {
  Log.d(TAG, "DownloadDocumentTask(doInBackground): Estoy dentro del background!!!");
  try {
    HttpsURLConnection urlConnection;
    FileService file = new FileService();
    InputStream iStream;
    Document result;

    file.writeLog(TAG, GMapDirections.class.getName(), getUrlConnection());

    URL url = new URL(getUrlConnection());

    // Creating an http connection to communicate with url
    urlConnection = (HttpsURLConnection) url.openConnection();

    // Connecting to url
    urlConnection.setRequestMethod("POST");
    urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    urlConnection.setRequestProperty("charset", "utf-8");
    urlConnection.setRequestProperty("Accept", "application/xml");
    urlConnection.setDoOutput(true);
    urlConnection.setDoInput(true);
    urlConnection.setUseCaches(false);
    urlConnection.connect();

    //Return data
    iStream = urlConnection.getInputStream();

    //Display what returns POST request
    BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
    StringBuilder sb = new StringBuilder();

    String line;
    while ((line = br.readLine()) != null) {
      sb.append(line + "\n");
    }
    br.close();
    file.writeLog(GMapDirections.TAG, "doInBackground", sb.toString());

    // Parse the data to a Document Object
    DocumentBuilder builder =  DocumentBuilderFactory.newInstance().newDocumentBuilder();
    result = builder.parse(iStream);
    urlConnection.disconnect();

    return result;
  } catch (Exception e) {
     e.printStackTrace();
     Log.d(TAG, "Exception while downloading data: " + e.toString());
  }
  return null;
}

The exception is launched when I try to parse the content of iStream because previously I have read it using BufferedReader.

DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
result = builder.parse(iStream);

So, how I can read the iStream with the BufferedReader and then used it to parse the content and not get an error?

José Carlos
  • 2,850
  • 12
  • 59
  • 95
  • No, it's in the correct order. First I've got several warnings, but finally, I've got an exception and the method return null, when the data get it from the connection is correct. – José Carlos Jul 20 '15 at 15:53

5 Answers5

2

Your stack trace and code do not seem to match up. From the stack trace it looks like doInBackground is recursively calling itself and then InputStream.reset(). But I can see neither call in your code.

Regarding your actual problem re-reading the stream: Since you apparently already tried (and failed) with InputStream.reset(), the amount of data in that stream is probably too large for that (or you forgot to call InputStream.mark()). The easy way is to create another connection + stream and read that. It does mean that you will actually and inefficiently transfer that data twice from the URL.

More efficient ways to do this:

  1. Read the entire contents of the stream into memory / or into a temporary file (depending on size) and then use that as your data source.

  2. Use TeeInputStream (https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/input/TeeInputStream.html) to copy stream data as you go.

emu
  • 399
  • 2
  • 6
  • I think is better to use the first option, to read entire contents from memory / temporary file / Document. So the best thing is to read the Document and write it lately in a file, for example – José Carlos Jul 20 '15 at 16:56
  • If available memory is not an issue, load the contents into a byte array and then use ByteArrayInputStream based on that. Only thing that might be a cause for trouble is, if that XML has any relative references (eg. XML includes). And that case can easily be fixed by passing the original URL of the document to the parser (ie. DocumentBuilder.parse(InputStream is, String systemId)). – emu Jul 20 '15 at 21:17
0

If you want to read from a Stream again, you'll have to reset it by calling iStream.reset()

From the InputStream docs: http://developer.android.com/reference/java/io/InputStream.html

public synchronized void reset ()

Added in API level 1

Rests this stream to the last marked location. Throws anIOException if the number of bytes read since the mark has been set is greater than the limit provided to mark, or if no mark has been set.

This implementation always throws an IOException and concrete subclasses should provide the proper implementation.

Throws

IOExceptionif this stream is closed or another IOException occurs.

Taylor Clark
  • 570
  • 2
  • 10
  • Was about to update my answer to say to copy the Stream locally, but @emu mentions it below. That's the best solution, IMO – Taylor Clark Jul 20 '15 at 16:42
0

It's because you call BufferedReader.close(). From the Javadocs,

Closes the stream and releases any system resources associated with it.

I looked at this a while ago because I was worried that a sequence like:

new BufferedReader(new FileReader(...))

would leak a Reader handle for the FileReader. Turns out that the BufferedReader.close also closed the underlying reader as well.

schtever
  • 3,210
  • 16
  • 25
  • Hi!!! If I comment br.close() I've got the same error. The problem is due to I cannot use iStream twice. First time, I used to read the content and write all these content in a file. That's works fine!!! The problem is when I try to transform this iStream in a Document becuase iStream it seems that are closed or empty. And if iStream is closed is not due to br.close(), because if I comment these instrucction I've got the same error. Thanks – José Carlos Jul 20 '15 at 16:55
0

Add finally section where you close all streams. Move declaration of streams outside of your try block, i.e. :

BufferedReader br;
InputStream iStream;
try {
    // your regular code, but remove this line as you'll close later
    // br.close();
} catch (Exception whatever) {
    //...
} finally {
    if (iStream != null) {
        iStream.close(); // TODO you need to catch exception here too
    }
}
kiruwka
  • 9,250
  • 4
  • 30
  • 41
  • Thank you but the problem is that I cannot use twice the same iStream and I would like to know if there is any easy way to do it – José Carlos Jul 20 '15 at 16:51
0

According with the answer of @emu (see point 1)

More efficient ways to do this:
1. Read the entire contents of the stream into memory / or into a temporary file (depending on size) and then use that as your data source.

The best solution would be ...

        @Override
    protected Document doInBackground(Void... voids) {
        try {
            HttpsURLConnection urlConnection;
            FileService file = new FileService();
            InputStream iStream;
            Document result;

            file.writeLog(TAG, GMapDirections.class.getName(), getUrlConnection());


            URL url = new URL(getUrlConnection());

            // Creating an http connection to communicate with url
            urlConnection = (HttpsURLConnection) url.openConnection();

            // Connecting to url
            urlConnection.setRequestMethod("POST");
            urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            urlConnection.setRequestProperty("charset", "utf-8");
            urlConnection.setRequestProperty("Accept", "application/xml");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setUseCaches(false);
            urlConnection.connect();

            //Return data
            iStream = urlConnection.getInputStream();

            // Parse the data to a Document Object
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            result = builder.parse(iStream);
            urlConnection.disconnect();

            //Write data get it from POST request
            //Transform Document 2 InputStream
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            Source xmlSource = new DOMSource(result);
            Result outputTarget = new StreamResult(outputStream);
            TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
            iStream = new ByteArrayInputStream(outputStream.toByteArray());

            //Write document in a file
            BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
            StringBuilder sb = new StringBuilder();

            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line + "\n");
            }
            br.close();
            file.writeLog(GMapDirections.TAG, "doInBackground", sb.toString());

            //Return Document with data
            return result;

        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "Exception while downloading data: " + e.toString());
        }

        return null;
    }
José Carlos
  • 2,850
  • 12
  • 59
  • 95