Search code examples
javaandroidiohttpurlconnectionbufferedinputstream

why is BufferedInputStream reading max 2048 bytes at a time?


I'm trying to read a file from network using HttpUrlConnection in an AsyncTask in my Android Application.

While i noticed one thing that the file download worked a little slower than it should have, as the network speed i was using was faster.

So i checked and found out that the BufferedInputStream object reads only 2048 bytes max at a time. No what buffer size I set. Even internal default buffer size for BufferedInputStream is 8192 bytes.

I'm adding my code here for reference.

private class DownloadFileTask extends AsyncTask<String, Integer, String> {

  @Override
  protected String doInBackground(String... params) {
    HttpURLConnection connection = null;
    BufferedInputStream input = null;
    OutputStream output = null;
    int lengthOfFile;
    int totalBytesDownloaded = 0;
    int count;
    final int bufferSize = 8 * 1024; // 8KB
    try {
      // Create the URL
      URL url = new URL(params[0]);
      // Open connection
      connection = (HttpURLConnection) url.openConnection();
      // Get the file length
      lengthOfFile = connection.getContentLength();
      // Input stream to read file - with bufferSize buffer
      input = new BufferedInputStream(connection.getInputStream(), bufferSize);

      if (isCancelled()) {
        return null;
      }
      // Output stream to write file
      File parentFile = TestUtil.getStorageDir(getApplicationContext(),Constants.EXTRA_DIRECTORY_NAME_TEST_MEDIA);
      File file = new File(parentFile.getAbsolutePath() + "/" + "zipFile");

      if (!file.exists()) {
        file.getParentFile().mkdirs();
      }

      // Create the file o/p stream
      output = new FileOutputStream(file.getAbsolutePath());

      // Create the buffer o/p stream for performance
      BufferedOutputStream bos = new BufferedOutputStream(output, bufferSize);

      // Buffer
      byte data[] = new byte[bufferSize];
      while ((count = input.read(data, 0, bufferSize)) != -1 && !isCancelled()) {
        // Increase the total bytes downloaded
        totalBytesDownloaded += count;
        Log.d("DEBUG_LOG","total bytes read : " + count + " buffer size : " + data.length);

        // Write the data to the o/p buffer
        bos.write(data, 0, count);
      }

      // Publish update again since the loop may have skipped the last publish update
      publishProgress(totalBytesDownloaded, lengthOfFile);

      // Flush the o/p stream
      output.flush();
      return file.getAbsolutePath();
    } catch (SocketException | SocketTimeoutException e) {
      handler.sendEmptyMessage(Constants.CASE_INTERNET_FAILURE);
      Log.e("DEBUG_LOG", e);
    } catch (IOException e) {
      Log.e("DEBUG_LOG","Error: " + e.getMessage());
    } finally {
      // closing streams
      if (output != null) {
        try {
          output.close();
        } catch (IOException e) {
          AMLog.e(e);
        }
      }
      if (input != null) {
        try {
          input.close();
        } catch (IOException e) {
          AMLog.e(e);
        }
      }
      if (connection != null) {
        connection.disconnect();
      }
    }
    return null;
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
    int percentage = (values[0] * 100) / values[1] ;
    textDownloadSizeMb.setText(String.format(getString(R.string.label_download_mb), String.valueOf(values[0]), String.valueOf(values[1])));
    textDownloadPercent.setText(String.format(Locale.getDefault(), "%s%s", percentage, " %"));
    progressBar.setMax(values[1]);
    progressBar.setProgress(values[0]);
  }

  @Override
  protected void onPostExecute(String value) {
  }
}

Here is a part of log that shows the data read was never greater than 2048 bytes whereas the buffer size was 8192 bytes.

total bytes read : 1748 buffer size : 8192
total bytes read : 2048 buffer size : 8192
total bytes read : 2048 buffer size : 8192
total bytes read : 2048 buffer size : 8192
total bytes read : 1988 buffer size : 8192

I've tried multiple buffer sizes greater than 2048 but nothing seems to change the reading rate.

What's the reason behind this? Can i change it to get data in specified buffer size?


Solution

  • Because that's all that is ready to be read at any one time, due to the way it is being sent. Nothing you can do about that at this end, except maybe read less often ;-) There's no particular reason to want 8192 bytes at a time: in a correctly written read loop you shouldn't care whether it's one byte or a megabyte, or whatever your buffer size is. The contract of read() is merely that it transfers 'at least one byte', unless an exception or end of stream occurs.