Загрузить бинарный файл с охтпп из ресурсов
Мне нужно загрузить бинарный файл в apk на сервер, используя okhttp. Используя urlconnection, вы можете просто получить входной поток для актива и затем добавить его в свой запрос. Тем не менее, okhttp дает вам возможность загружать байтовые массивы, строки или файлы. Поскольку вы не можете получить путь к файлу для актива, связанного в apk, единственный вариант - скопировать файл в локальный каталог файлов (я бы предпочел этого не делать) и затем передать файл в okhttp? Нет ли способа просто сделать запрос, используя assetinputstream прямо на веб-сервере?
РЕДАКТИРОВАТЬ: я использовал принятый ответ, но вместо создания статического служебного класса я просто подклассифицировал RequestBody
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);
}
}
}
Моя единственная проблема с этим подходом - ненадежность inputtream.available() для длины содержимого. Статический конструктор должен соответствовать внутренней реализации okhttp
1 ответ
Возможно, вы не сможете сделать это напрямую с помощью библиотеки, но вы можете создать небольшой служебный класс, который сделает это за вас. Затем вы можете просто использовать его везде, где вам это нужно.
public class RequestBodyUtil {
public static RequestBody create(final MediaType mediaType, final InputStream inputStream) {
return new RequestBody() {
@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);
}
}
};
}
}
Тогда просто используйте это так
OkHttpClient client = new OkHttpClient();
MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
InputStream inputStream = getAssets().open("README.md");
RequestBody requestBody = RequestBodyUtil.create(MEDIA_TYPE_MARKDOWN, inputStream);
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
Log.d("POST", response.body().string());
Этот пример кода был основан на этом коде. Заменить Assets
имя файла и MediaType
с вашим собственным.
Я знаю, что уже поздно, но лучше, чем никогда.
Уловка здесь, если вы не знаете размер ваших данных, вы можете пропустить заголовок длины содержимого и заменить его кодировкой передачи Http1.1: Chuncked
Для получения дополнительной информации прочтите https://www.oracle.com/technical-resources/articles/javame/chunking.html.
Слишком просто использовать snoopy api: одна строчка кода, если исключить определение идентификаторов:)
URI uri = ...;
Path fileToUpload = ...;
Snoopy.builder()
.config(SnoopyConfig.defaults())
.build()
.post(uri)
.followRedirects(true)
.failIfNotSuccessfulResponse(true)
.body(fileToUpload)
.consumeAsString();
https://bitbucket.org/abuwandi/snoopy
До сих пор нет релиза для Android, но он скоро появится...