为什么 BufferedInputStream 一次最多读取 2048 个字节?
why is BufferedInputStream reading max 2048 bytes at a time?
我正在尝试在我的 Android 应用程序的 AsyncTask
中使用 HttpUrlConnection
从网络读取文件。
虽然我注意到一件事,文件下载速度比应有的慢一点,因为我使用的网络速度更快。
所以我检查了一下,发现 BufferedInputStream
对象一次最多只能读取 2048 字节。没有我设置的缓冲区大小。 BufferedInputStream
的内部默认缓冲区大小甚至是 8192 字节。
我在此处添加我的代码以供参考。
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) {
}
}
这是日志的一部分,显示读取的数据从未超过 2048 字节,而缓冲区大小为 8192 字节。
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
我尝试了多个大于 2048 的缓冲区大小,但似乎没有任何改变读取速率。
这背后的原因是什么?我可以更改它以获取指定缓冲区大小的数据吗?
因为发送方式决定了随时可以阅读的所有内容。你对此无能为力,除了可能不经常读取 ;-) 一次需要 8192 字节没有特别的理由:在正确编写的读取循环中,你不应该关心它是一个字节还是一兆字节,或者无论您的缓冲区大小是多少。 read()
的合约只是传输 'at least one byte',除非发生异常或流结束。
我正在尝试在我的 Android 应用程序的 AsyncTask
中使用 HttpUrlConnection
从网络读取文件。
虽然我注意到一件事,文件下载速度比应有的慢一点,因为我使用的网络速度更快。
所以我检查了一下,发现 BufferedInputStream
对象一次最多只能读取 2048 字节。没有我设置的缓冲区大小。 BufferedInputStream
的内部默认缓冲区大小甚至是 8192 字节。
我在此处添加我的代码以供参考。
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) {
}
}
这是日志的一部分,显示读取的数据从未超过 2048 字节,而缓冲区大小为 8192 字节。
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
我尝试了多个大于 2048 的缓冲区大小,但似乎没有任何改变读取速率。
这背后的原因是什么?我可以更改它以获取指定缓冲区大小的数据吗?
因为发送方式决定了随时可以阅读的所有内容。你对此无能为力,除了可能不经常读取 ;-) 一次需要 8192 字节没有特别的理由:在正确编写的读取循环中,你不应该关心它是一个字节还是一兆字节,或者无论您的缓冲区大小是多少。 read()
的合约只是传输 'at least one byte',除非发生异常或流结束。