Android 从OKHTTP下载二进制文件
我在android应用程序中使用OKHTTP客户端进行联网 示例显示如何上载二进制文件。我想知道如何使用OKHTTP客户端获取二进制文件下载的inputstream 以下是示例列表:Android 从OKHTTP下载二进制文件,android,inputstream,bufferedinputstream,okhttp,Android,Inputstream,Bufferedinputstream,Okhttp,我在android应用程序中使用OKHTTP客户端进行联网 示例显示如何上载二进制文件。我想知道如何使用OKHTTP客户端获取二进制文件下载的inputstream 以下是示例列表: public class InputStreamRequestBody extends RequestBody { private InputStream inputStream; private MediaType mediaType; public static RequestBod
public class InputStreamRequestBody extends RequestBody {
private InputStream inputStream;
private MediaType mediaType;
public static RequestBody create(final MediaType mediaType,
final InputStream inputStream) {
return new InputStreamRequestBody(inputStream, mediaType);
}
private InputStreamRequestBody(InputStream inputStream, MediaType mediaType) {
this.inputStream = inputStream;
this.mediaType = mediaType;
}
@Override
public MediaType contentType() {
return mediaType;
}
@Override
public long contentLength() {
try {
return inputStream.available();
} catch (IOException e) {
return 0;
}
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(inputStream);
sink.writeAll(source);
} finally {
Util.closeQuietly(source);
}
}
}
简单get请求的当前代码为:
OkHttpClient client = new OkHttpClient();
request = new Request.Builder().url("URL string here")
.addHeader("X-CSRFToken", csrftoken)
.addHeader("Content-Type", "application/json")
.build();
response = getClient().newCall(request).execute();
现在如何将响应转换为InputStream
。类似于来自apachehttp客户端的响应的东西,类似于OkHttp
响应:
InputStream is = response.getEntity().getContent();
编辑
我接受了下面的回答。
我的修改代码:
request = new Request.Builder().url(urlString).build();
response = getClient().newCall(request).execute();
InputStream is = response.body().byteStream();
BufferedInputStream input = new BufferedInputStream(is);
OutputStream output = new FileOutputStream(file);
byte[] data = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
从OKHTTP获取ByTestStream
我一直在查阅OkHttp的文档,你需要这样做
使用此方法:
response.body().ByTestStream()将返回一个InputStream
因此,您可以简单地使用BufferedReader或任何其他替代方法
从OKHTTP获取ByTestStream
我一直在查阅OkHttp的文档,你需要这样做
使用此方法:
response.body().ByTestStream()将返回一个InputStream
因此,您可以简单地使用BufferedReader或任何其他替代方法
值得一提的是,我建议使用response.body().source()
from(因为OkHttp已经在本机上支持它),以便更轻松地处理下载文件时可能出现的大量数据
@Override
public void onResponse(Call call, Response response) throws IOException {
File downloadedFile = new File(context.getCacheDir(), filename);
BufferedSink sink = Okio.buffer(Okio.sink(downloadedFile));
sink.writeAll(response.body().source());
sink.close();
}
与InputStream相比,从文档中获得的几个优点:
该接口在功能上等同于InputStream。
当使用的数据是异构数据时,InputStream需要多个层:用于基本值的DataInputStream、用于缓冲的BufferedInputStream和用于字符串的InputStreamReader。此类将BufferedSource用于上述所有操作。
Source避免了不可能实现的available()方法。相反,调用者指定他们需要多少字节
Source省略了InputStream跟踪的不安全组合标记和重置状态;而呼叫者只是缓冲他们需要的东西
在实现源代码时,您不必担心单字节读取方法难以有效实现,并且返回257个可能值中的一个
而且source有一个更强的跳过方法:BufferedSource.skip(long)不会过早返回
值得一提的是,我建议使用response.body().source()
from(因为OkHttp已经在本机上支持它),以便更轻松地处理下载文件时可能出现的大量数据
@Override
public void onResponse(Call call, Response response) throws IOException {
File downloadedFile = new File(context.getCacheDir(), filename);
BufferedSink sink = Okio.buffer(Okio.sink(downloadedFile));
sink.writeAll(response.body().source());
sink.close();
}
与InputStream相比,从文档中获得的几个优点:
该接口在功能上等同于InputStream。
当使用的数据是异构数据时,InputStream需要多个层:用于基本值的DataInputStream、用于缓冲的BufferedInputStream和用于字符串的InputStreamReader。此类将BufferedSource用于上述所有操作。
Source避免了不可能实现的available()方法。相反,调用者指定他们需要多少字节
Source省略了InputStream跟踪的不安全组合标记和重置状态;而呼叫者只是缓冲他们需要的东西
在实现源代码时,您不必担心单字节读取方法难以有效实现,并且返回257个可能值中的一个
而且source有一个更强的跳过方法:BufferedSource.skip(long)不会过早返回
这就是我在每次区块下载后发布下载进度时如何使用Okhttp+Okio库的方法:
public static final int DOWNLOAD_CHUNK_SIZE = 2048; //Same as Okio Segment.SIZE
try {
Request request = new Request.Builder().url(uri.toString()).build();
Response response = client.newCall(request).execute();
ResponseBody body = response.body();
long contentLength = body.contentLength();
BufferedSource source = body.source();
File file = new File(getDownloadPathFrom(uri));
BufferedSink sink = Okio.buffer(Okio.sink(file));
long totalRead = 0;
long read = 0;
while ((read = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
totalRead += read;
int progress = (int) ((totalRead * 100) / contentLength);
publishProgress(progress);
}
sink.writeAll(source);
sink.flush();
sink.close();
publishProgress(FileInfo.FULL);
} catch (IOException e) {
publishProgress(FileInfo.CODE_DOWNLOAD_ERROR);
Logger.reportException(e);
}
这就是我在每次区块下载后发布下载进度时如何使用Okhttp+Okio库的方法:
public static final int DOWNLOAD_CHUNK_SIZE = 2048; //Same as Okio Segment.SIZE
try {
Request request = new Request.Builder().url(uri.toString()).build();
Response response = client.newCall(request).execute();
ResponseBody body = response.body();
long contentLength = body.contentLength();
BufferedSource source = body.source();
File file = new File(getDownloadPathFrom(uri));
BufferedSink sink = Okio.buffer(Okio.sink(file));
long totalRead = 0;
long read = 0;
while ((read = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
totalRead += read;
int progress = (int) ((totalRead * 100) / contentLength);
publishProgress(progress);
}
sink.writeAll(source);
sink.flush();
sink.close();
publishProgress(FileInfo.FULL);
} catch (IOException e) {
publishProgress(FileInfo.CODE_DOWNLOAD_ERROR);
Logger.reportException(e);
}
更好的解决方案是将OkHttpClient用作:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
// Headers responseHeaders = response.headers();
// for (int i = 0; i < responseHeaders.size(); i++) {
// System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
// }
// System.out.println(response.body().string());
InputStream in = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String result, line = reader.readLine();
result = line;
while((line = reader.readLine()) != null) {
result += line;
}
System.out.println(result);
}
});
OkHttpClient=new-OkHttpClient();
Request Request=newrequest.Builder()
.url(“http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback()){
@凌驾
公共void onFailure(调用调用,IOE异常){
e、 printStackTrace();
}
@凌驾
public void onResponse(调用调用、响应响应)引发IOException{
如果(!response.issusccessful())抛出新IOException(“意外代码”+响应);
//Headers responseHeaders=response.Headers();
//对于(int i=0;i
更好的解决方案是将OkHttpClient用作:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
// Headers responseHeaders = response.headers();
// for (int i = 0; i < responseHeaders.size(); i++) {
// System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
// }
// System.out.println(response.body().string());
InputStream in = response.body().byteStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String result, line = reader.readLine();
result = line;
while((line = reader.readLine()) != null) {
result += line;
}
System.out.println(result);
}
});
OkHttpClient=new-OkHttpClient();
Request Request=newrequest.Builder()
.url(“http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback()){
@凌驾
公共void onFailure(调用调用,IOE异常){
e、 printStackTrace();
}
@凌驾
public void onResponse(调用调用、响应响应)引发IOException{
如果(!response.issusccessful())抛出新IOException(“意外代码”+响应);
//
fun Uri?.toOutputStream(context: Context)
: OutputStream? {
if (this == null) {
return null
}
fun createAssetFileDescriptor() = try {
context.contentResolver.openAssetFileDescriptor(this, "w")
} catch (e: FileNotFoundException) {
null
}
fun createParcelFileDescriptor() = try {
context.contentResolver.openFileDescriptor(this, "w")
} catch (e: FileNotFoundException) {
null
}
/** scheme://<authority>/<path>/<id> */
if (scheme.equals(ContentResolver.SCHEME_FILE)) {
/** - If AssetFileDescriptor is used, it always writes 0B.
* - (FileOutputStream | ParcelFileDescriptor.AutoCloseOutputStream) works both for app-specific + shared storage
* - If throws "FileNotFoundException: open failed: EACCES (Permission denied)" on Android 10+, use android:requestLegacyExternalStorage="true" on manifest and turnOff/turnOn "write_external_storage" permission on phone settings. Better use Content Uri on Android 10+ */
return try {
FileOutputStream(toFile())
} catch (e: Throwable) {
null
}
} else if (scheme.equals(ContentResolver.SCHEME_ANDROID_RESOURCE)) {
// i think you can't write to asset inside apk
return null
} else {
// content URI (MediaStore)
if (authority == android.provider.MediaStore.AUTHORITY) {
return try {
context.contentResolver.openOutputStream(this, "w")
} catch (e: Throwable) {
null
}
} else {
// content URI (provider), not tested
return try {
val assetFileDescriptor = createAssetFileDescriptor()
if (assetFileDescriptor != null) {
AssetFileDescriptor.AutoCloseOutputStream(assetFileDescriptor)
} else {
val parcelFileDescriptor = createParcelFileDescriptor()
if (parcelFileDescriptor != null) {
ParcelFileDescriptor.AutoCloseOutputStream(parcelFileDescriptor)
} else {
null
}
}
} catch (e: Throwable) {
null
}
}
}
}
// create Request
val request = Request.Builder()
.method("GET", null)
.url(url)
.build()
// API call function
fun apiCall(): Response? {
return try {
client.newCall(request).execute()
} catch (error: Throwable) {
null
}
}
// execute API call
var response: Response? = apiCall()
// your retry logic if request failed (response==null)
// if failed, return
if (response == null || !response.isSuccessful) {
return
}
// response.body
val body: ResponseBody? = response!!.body
if (body == null) {
response.closeQuietly()
return
}
// outputStream
val outputStream = destinationUri.toOutputStream(appContext)
if (outputStream == null) {
response.closeQuietly() // calls body.close
return
}
val bufferedSink: BufferedSink = outputStream!!.sink().buffer()
val outputBuffer: Buffer = bufferedSink.buffer
// inputStream
val bufferedSource = body!!.source()
val contentLength = body.contentLength()
// write
var totalBytesRead: Long = 0
var toBeFlushedBytesRead: Long = 0
val BUFFER_SIZE = 8 * 1024L // KB
val FLUSH_THRESHOLD = 200 * 1024L // KB
var bytesRead: Long = bufferedSource.read(outputBuffer, BUFFER_SIZE)
var lastProgress: Int = -1
while (bytesRead != -1L) {
// emit/flush
totalBytesRead += bytesRead
toBeFlushedBytesRead += bytesRead
bufferedSink.emitCompleteSegments()
if (toBeFlushedBytesRead >= FLUSH_THRESHOLD) {
toBeFlushedBytesRead = 0L
bufferedSink.flush()
}
// write
bytesRead = bufferedSource.read(outputBuffer, BUFFER_SIZE)
// progress
if (contentLength != -1L) {
val progress = (totalBytesRead * 100 / contentLength).toInt()
if (progress != lastProgress) {
lastProgress = progress
// update UI (using Flow/Observable/Callback)
}
}
}
bufferedSink.flush()
// close resources
outputStream.closeQuietly()
bufferedSink.closeQuietly()
bufferedSource.closeQuietly()
body.closeQuietly()