下载一个非常大的文件静静地死了
Downloading a Very Large file silently dies
所以我正在尝试通过 Retrofit2 下载一个非常大的文件。文件的范围可达 5-10 GB。我正在从 activity/fragment 启动一个异步结构(我已经尝试过 AsyncTask 和 IntentService)并流式传输文件并将字节写入内部存储上的文件。每次读取缓冲区后,我都会发布文件写入的进度。
最大 150 MB 左右的文件工作正常,但当我尝试 5 GB 的文件时,流在大约 1 GB 后静默消失。我看不到日志或 logcat,没有抛出任何异常。
有没有人知道发生了什么,或者我写错了什么?
public interface IFileshareDownload {
@Streaming
@GET("File/Download/{guid}")
Call<ResponseBody> downloadFileByGuid(@Path("guid") String guid);
}
public class FileshareDownloadService extends IntentService {
private static final String TAG = "[FileDownloadService]";
private static final String PATH = "/ftp/";
private static final int FILE_CHUNK_SIZE = 2 * 1024 * 1024; //2MB buffer
private String mFilename;
private String mFileshareDirectory;
private String mAbsoluteFilePath;
private String mBaseUrl;
private String mGuid;
private Long mFileSize;
private Retrofit mRetrofit;
private IFileshareDownload mDownloader;
private ResultReceiver mReceiver;
public FileshareDownloadService() {
super("FileshareDownload");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
this.mBaseUrl = intent.getStringExtra("baseUrl");
this.mGuid = intent.getStringExtra("guid");
this.mFilename = intent.getStringExtra("fileName");
this.mFileSize = intent.getLongExtra("fileSize", -1);
this.mFileshareDirectory = getApplicationContext().getFilesDir().getAbsolutePath() + PATH;
this.mAbsoluteFilePath = mFileshareDirectory + mFilename;
this.mRetrofit = new Retrofit.Builder()
.baseUrl(mBaseUrl)
.callbackExecutor(Executors.newSingleThreadExecutor())
.build();
this.mDownloader = mRetrofit.create(IFileshareDownload.class);
this.mReceiver = intent.getParcelableExtra("listener");
downloadFile();
}
public void downloadFile() {
Call<ResponseBody> call = mDownloader.downloadFileByGuid(mGuid);
try {
Response<ResponseBody> response = call.execute();
if(response.isSuccessful()) {
File file = new File(mAbsoluteFilePath);
file.createNewFile();
try(FileOutputStream fos = new FileOutputStream(file)) {
InputStream is = response.body().byteStream();
setUpdateProgress(SHOW_PROGRESS);
int count = 0;
long bytesRead = 0;
byte[] buffer = new byte[FILE_CHUNK_SIZE];
try {
while ((count = is.read(buffer)) != -1) {
fos.write(buffer, 0, count);
fos.flush();
bytesRead += count;
int progress = getPercent(bytesRead, mFileSize);
Log.d(TAG, String.format("Read %d out of %d bytes.", bytesRead, mFileSize));
setUpdateProgress(UPDATE_PROGRESS, progress);
}
} catch (Throwable t)
{
Log.e(TAG, "What happened?", t);
}
}
setUpdateProgress(HIDE_PROGRESS);
} else {
setUpdateProgress(HIDE_PROGRESS);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里有一个关于下载文件的很棒的教程。它可能会提到你需要什么:
https://futurestud.io/tutorials/retrofit-2-how-to-download-files-from-server
如果没有,请查看@Multipart 注释以及@Part。我不确定您是否可以将它与 GET 一起使用,但由于您还没有答案,我将 post 放在这里,以便您可以根据需要进行拍摄。
这是我的一个项目的示例,在该项目中我们创建了一个多部分正文来上传图像。我知道你想要一个 GET,但这个例子应该仍然是相关的:
// Setting up the multipart file
File newAvatar = new File(getRealPathFromURI(avatarUri)); // the new avatar
RequestBody filePart = RequestBody.create(MediaType.parse(getActivity().getContentResolver().getType(avatarUri)), newAvatar);
你的请求(本例中的 POST)应该是这样的:
@Multipart
@POST("/api/v1/me/account/upload-cover") // upload avatar
Call<ResponseChangeAvatar> sendChangeAvatarRequest(@Part MultipartBody.Part file, @Header("Authorization") String token);
改装文档(只需搜索 multipart):
http://square.github.io/retrofit/
教程,其中他创建了一个多部分正文以将文件上传到服务器:
https://futurestud.io/tutorials/retrofit-2-how-to-upload-files-to-server
希望这对您有所帮助。如果您找到解决方案,请告诉我。
所以我正在尝试通过 Retrofit2 下载一个非常大的文件。文件的范围可达 5-10 GB。我正在从 activity/fragment 启动一个异步结构(我已经尝试过 AsyncTask 和 IntentService)并流式传输文件并将字节写入内部存储上的文件。每次读取缓冲区后,我都会发布文件写入的进度。
最大 150 MB 左右的文件工作正常,但当我尝试 5 GB 的文件时,流在大约 1 GB 后静默消失。我看不到日志或 logcat,没有抛出任何异常。
有没有人知道发生了什么,或者我写错了什么?
public interface IFileshareDownload {
@Streaming
@GET("File/Download/{guid}")
Call<ResponseBody> downloadFileByGuid(@Path("guid") String guid);
}
public class FileshareDownloadService extends IntentService {
private static final String TAG = "[FileDownloadService]";
private static final String PATH = "/ftp/";
private static final int FILE_CHUNK_SIZE = 2 * 1024 * 1024; //2MB buffer
private String mFilename;
private String mFileshareDirectory;
private String mAbsoluteFilePath;
private String mBaseUrl;
private String mGuid;
private Long mFileSize;
private Retrofit mRetrofit;
private IFileshareDownload mDownloader;
private ResultReceiver mReceiver;
public FileshareDownloadService() {
super("FileshareDownload");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
this.mBaseUrl = intent.getStringExtra("baseUrl");
this.mGuid = intent.getStringExtra("guid");
this.mFilename = intent.getStringExtra("fileName");
this.mFileSize = intent.getLongExtra("fileSize", -1);
this.mFileshareDirectory = getApplicationContext().getFilesDir().getAbsolutePath() + PATH;
this.mAbsoluteFilePath = mFileshareDirectory + mFilename;
this.mRetrofit = new Retrofit.Builder()
.baseUrl(mBaseUrl)
.callbackExecutor(Executors.newSingleThreadExecutor())
.build();
this.mDownloader = mRetrofit.create(IFileshareDownload.class);
this.mReceiver = intent.getParcelableExtra("listener");
downloadFile();
}
public void downloadFile() {
Call<ResponseBody> call = mDownloader.downloadFileByGuid(mGuid);
try {
Response<ResponseBody> response = call.execute();
if(response.isSuccessful()) {
File file = new File(mAbsoluteFilePath);
file.createNewFile();
try(FileOutputStream fos = new FileOutputStream(file)) {
InputStream is = response.body().byteStream();
setUpdateProgress(SHOW_PROGRESS);
int count = 0;
long bytesRead = 0;
byte[] buffer = new byte[FILE_CHUNK_SIZE];
try {
while ((count = is.read(buffer)) != -1) {
fos.write(buffer, 0, count);
fos.flush();
bytesRead += count;
int progress = getPercent(bytesRead, mFileSize);
Log.d(TAG, String.format("Read %d out of %d bytes.", bytesRead, mFileSize));
setUpdateProgress(UPDATE_PROGRESS, progress);
}
} catch (Throwable t)
{
Log.e(TAG, "What happened?", t);
}
}
setUpdateProgress(HIDE_PROGRESS);
} else {
setUpdateProgress(HIDE_PROGRESS);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里有一个关于下载文件的很棒的教程。它可能会提到你需要什么:
https://futurestud.io/tutorials/retrofit-2-how-to-download-files-from-server
如果没有,请查看@Multipart 注释以及@Part。我不确定您是否可以将它与 GET 一起使用,但由于您还没有答案,我将 post 放在这里,以便您可以根据需要进行拍摄。
这是我的一个项目的示例,在该项目中我们创建了一个多部分正文来上传图像。我知道你想要一个 GET,但这个例子应该仍然是相关的:
// Setting up the multipart file
File newAvatar = new File(getRealPathFromURI(avatarUri)); // the new avatar
RequestBody filePart = RequestBody.create(MediaType.parse(getActivity().getContentResolver().getType(avatarUri)), newAvatar);
你的请求(本例中的 POST)应该是这样的:
@Multipart
@POST("/api/v1/me/account/upload-cover") // upload avatar
Call<ResponseChangeAvatar> sendChangeAvatarRequest(@Part MultipartBody.Part file, @Header("Authorization") String token);
改装文档(只需搜索 multipart):
http://square.github.io/retrofit/
教程,其中他创建了一个多部分正文以将文件上传到服务器:
https://futurestud.io/tutorials/retrofit-2-how-to-upload-files-to-server
希望这对您有所帮助。如果您找到解决方案,请告诉我。