Servlet: Make a download resummable - java

I am creating a servlet that makes files to client downloadable. I achieved this but not able to make that resumable downloads to the client.
Here is my code
private void startDownloadProcess(File file) {
this.response.addHeader("Accept-Ranges", "bytes");
this.response.setContentType("APPLICATION/OCTET-STREAM");
this.response.setContentLength((int) file.length());
this.response.setHeader("Content-disposition", String.format("attachment; filename=%s", file.getName()));
try (ServletOutputStream outputStream = this.response.getOutputStream()) {
try (FileInputStream inputStream = new FileInputStream(file)) {
byte[] buffer = new byte[8072];
int len;
while ((len = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, len);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
This code will make the download available but the client is not able to pause and resume the downloads.

Related

Incomplete Downloading in Java

I want to download an MP3 file using this API
https://api.vevioz.com/#api/button/mp3/AKX91G0qNFM
I'm using Jsoup to get download URL from buttons. The problem is when I try to download, it downloads only 1.13MB of the MP3 and exits my app.
I've tried all of downloading methods like: Java IO, NIO, AsyncHttpClient, Apache Commons IO.
I really don't know how to successfully download my file and I didn't find any solution on internet for this problem.
My Code:
JSoup:
Document doc = Jsoup.connect("https://api.vevioz.com/#api/button/mp3/AKX91G0qNFM").get();
Element body=doc.body();
Elements elements=body.getElementsByClass("download flex flex-wrap sm:inline-flex text-center items-center justify-center");
elements=elements.get(0).children();
String FILE_URL=elements.get(0).attributes().get("href");
String FILE_NAME="./downloads/1.mp3";
Java IO:
try (BufferedInputStream in = new BufferedInputStream(new URL(FILE_URL).openStream());
FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME)) {
byte[] dataBuffer = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
} catch (IOException e) {
// handle exception
}
NIO:
ReadableByteChannel readableByteChannel = Channels.newChannel(new URL(FILE_URL).openStream());
FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME);
FileChannel fileChannel = fileOutputStream.getChannel();
fileOutputStream.getChannel()
.transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
AsyncHttpClient:
AsyncHttpClient client = Dsl.asyncHttpClient();
FileOutputStream stream = new FileOutputStream(FILE_NAME);
client.prepareGet(link).execute(new AsyncCompletionHandler<FileOutputStream>() {
#Override
public State onBodyPartReceived(HttpResponseBodyPart bodyPart)
throws Exception {
stream.getChannel().write(bodyPart.getBodyByteBuffer());
return State.CONTINUE;
}
#Override
public FileOutputStream onCompleted(org.asynchttpclient.Response response) throws Exception {
return stream;
}
});
Apache Commons IO:
FileUtils.copyURLToFile(new URL(FILE_URL),new File(FILE_NAME));

Download File from Direct Download URL

I'm trying to download the following the following file, with this link that redirects you to a direct download: http://www.lavozdegalicia.es/sitemap_sections.xml.gz
I've done my own research, but all the results I see are related to HTTP URL redirections
[3xx] and not to direct download redirections (maybe I'm using the wrong terms to do the research).
I've tried the following pieces of code (cite: https://programmerclick.com/article/7719159084/ ):
// Using Java IO
private static void downloadFileFromUrlWithJavaIO(String fileName, String fileUrl) {
BufferedInputStream inputStream = null;
FileOutputStream outputStream = null;
try {
URL url = new URL(fileUrl);
inputStream = new BufferedInputStream(url.openStream());
outputStream = new FileOutputStream(fileName);
byte data[] = new byte[1024];
int count;
while ((count = inputStream.read(data, 0, 1024)) != -1) {
outputStream.write(data, 0, count);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Using Apache common IO
private static void downloadFileFromUrlWithCommonsIO(String fileName, String fileUrl) {
try {
FileUtils.copyURLToFile(new URL(fileUrl), new File(fileName));
} catch (IOException e) {
e.printStackTrace();
}
}
// Using NIO
private static void downloadFileFromURLUsingNIO(String fileName, String fileUrl) {
try {
URL url = new URL(fileUrl);
ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(fileName);
fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
fileOutputStream.close();
readableByteChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
But the result I get with any of the three options is an empty file, my thoughts are that the problem is related to the file being a .xml.gz because when I debug it the inputStream doesn't seem to have any content.
I ran out of options, anyone has an idea of how to handle this case, or what would be the correct terms I should use to research about this specific case?
I found a solution, there's probably a more polite way of achieving the same result but this worked fine for me:
//Download the file and decompress it
filecount=0;
URL compressedSitemap = new URL(urlString);
HttpURLConnection con = (HttpURLConnection) compressedSitemap.openConnection();
con.setRequestMethod("GET");
if (con.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP || con.getResponseCode() == HttpURLConnection.HTTP_MOVED_PERM) {
String location = con.getHeaderField("Location");
URL newUrl = new URL(location);
con = (HttpURLConnection) newUrl.openConnection();
}
String file = "/home/user/Documentos/Decompression/decompressed" + filecount + ".xml";
GZIPInputStream gzipInputStream = new GZIPInputStream(con.getInputStream());
FileOutputStream fos = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = gzipInputStream.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
filecount++;
Two things to note:
When I was trying to do HTTPGet the url that was a redirect, the response code was 301 or 302 (depending on the example I used), I overcame this problem with the if check, that follows the redirect and aims to the downloaded file.
Once aiming the file, to get the content of the compressed file I found the GZIPInputStream package, that allowed me to get an inputStream directly from the compressed file and dump it on an xml file, that saved me the time of doing it on three steps (decompress, read, copy).

After downloading whole (84M) file from dropbox it turning into 0 bytes

I am downloading a zip file from dropbox. When it keeps downloading I measure the file size and get it is increasing its size with the Below code. It downloads whole 84M and after finishing download it turns into 0 bytes. What wrong am I actually doing?
public static void downloadDropBox(File file) {
String url = "https://www.dropbox.com/sh/jx4b2wvqg8d4ze1/AAA0J3LztkRc6FJ5tKy4dUKha?dl=1";
int bytesRead;
byte[] bytesArray = new byte[1024];
InputStream is = null;
FileOutputStream outputStream = null;
long progres = 0;
try {
URL fileUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection)fileUrl.openConnection();
connection.connect();
is = connection.getInputStream();
outputStream = new FileOutputStream(file);
while ((bytesRead = is.read(bytesArray, 0, 1024)) != -1) {
outputStream.write(bytesArray, 0, bytesRead);
}
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
During download file:
After Finishing download file:

Download CSV file in Java Servlet

String fileName = "/CSVLogs/test";
String fileType = "csv";
resp.setContentType(fileType);
resp.setHeader("Content-disposition","attachment; filename=test.csv");
File my_file = new File(fileName);
OutputStream out = resp.getOutputStream();
FileInputStream in = new FileInputStream(my_file);
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
in.close();
out.flush();
I need to download a csv file but it seems to return "java.lang.IllegalStateException: WRITER"
<form enctype="multipart/form-data" action="/TestServlet/ConfigServlet?do=downloadLogs" method="post" style="height:68px;">
UPDATE
resp.setContentType("application/octet-stream");
try
{
OutputStream outputStream = resp.getOutputStream();
InputStream in = StorageUtil.getInstance().getFile("/CSVLogs/test.csv").getInputStream();
/* InputStream in = StorageUtil.getInstance().getCSVLogsZip().getInputStream();*/
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0){
outputStream.write(buffer, 0, length);
in.close();
outputStream.flush();
}
}
catch(Exception e) {
System.out.println(e.toString());
}
I still get the same error.
java.lang.IllegalStateException: WRITER
(drunk) Why am I getting this error >_<
Try this:
public void doGet(HttpServletRequest request, HttpServletResponse response)
{
response.setContentType("text/csv");
response.setHeader("Content-Disposition", "attachment; filename=\"test.csv\"");
try
{
OutputStream outputStream = response.getOutputStream();
FileInputStream in = new FileInputStream(my_file);
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0){
outputStream.write(buffer, 0, length);
in.close();
outputStream.flush();
}
}
catch(Exception e)
{
model.closeConnection();
System.out.println(e.toString());
}
}
public void downloadFile(HttpServletResponse response){
String sourceFile = "c:\\source.csv";
try {
FileInputStream inputStream = new FileInputStream(sourceFile);
String disposition = "attachment; fileName=outputfile.csv";
response.setContentType("text/csv");
response.setHeader("Content-Disposition", disposition);
response.setHeader("content-Length", String.valueOf(stream(inputStream, response.getOutputStream())));
} catch (IOException e) {
logger.error("Error occurred while downloading file {}",e);
}
}
And the stream method should be like this.
private long stream(InputStream input, OutputStream output) throws IOException {
try (ReadableByteChannel inputChannel = Channels.newChannel(input); WritableByteChannel outputChannel = Channels.newChannel(output)) {
ByteBuffer buffer = ByteBuffer.allocate(10240);
long size = 0;
while (inputChannel.read(buffer) != -1) {
buffer.flip();
size += outputChannel.write(buffer);
buffer.clear();
}
return size;
}
}
java/servlet code you supplied works perfectly fine.
i call the servlet CSVD as below:
< form enctype="multipart/form-data" action="CSVD" method="post" style="height:68px;">
<input type="submit" value="submit" />
< /form>
or through anchor this way < a href="/CSVDownloadApp/CSVD">click here to download csv< /a>
possibly your error is coming for a different reason.
Try this:
response.setContentType("application/x-rar-compressed");
response.setHeader("Content-Disposition", "attachment; filename=\"test.csv\"");
For writing the file in OutputStream, try following
FileInputStream fis = new FileInputStream("your_csv_file.csv");
byte[] b = new byte[fis.available()];
outputStream.write(b);
outputStream.flush();
outputStream.close();

Google Cloud Storage createOrReplace file is broken (different size, ...)

I tried to upload a stream (restlet memoryfile) to gcs. But the file has another filesize and is a little different so that the file is marked as "broken".
I tried is local and on google app engine. While debugging to this part the stream looks good in size InputStream inputStream = item.getInputStream();
But the result in the store isn't that size. There are 4 Bits at the beginning: ’[NUL][ENQ]
Where are they from?
List<FileItem> items;
try {
MemoryFileItemFactory factory = new MemoryFileItemFactory();
RestletFileUpload restletFileUpload = new RestletFileUpload(factory);
items = restletFileUpload.parseRequest(req);
//items = restletFileUpload.parseRepresentation(entity);
for (FileItem item : items) {
if (!item.isFormField()) {
MediaType type = MediaType.valueOf(item.getContentType());
GcsFileOptions options = new GcsFileOptions.Builder().mimeType(type.getName()).acl("public-read").build();
GcsOutputChannel outputChannel = gcsService.createOrReplace(fileName, options);
ObjectOutputStream oout = new ObjectOutputStream(Channels.newOutputStream(outputChannel));
InputStream inputStream = item.getInputStream();
copy(inputStream, oout);
//oout.close();
}
}
} catch (FileUploadException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
private void copy(InputStream input, OutputStream output) throws IOException {
try {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = input.read(buffer);
while (bytesRead != -1) {
output.write(buffer, 0, bytesRead);
bytesRead = input.read(buffer);
}
} finally {
input.close();
output.close();
}
}
private final GcsService gcsService = GcsServiceFactory.createGcsService(new RetryParams.Builder()
.initialRetryDelayMillis(10)
.retryMaxAttempts(10)
.totalRetryPeriodMillis(15000)
.build());
Remove the finally close statements from the copy-function and close the GcsOutputChannel instead. Further you don't need to do this: ObjectOutputStream oout = new ObjectOutputStream(Channels.newOutputStream(outputChannel));
Maybe that adds the extra-bits
Something like that:
GcsOutputChannel outputChannel = gcsService.createOrReplace(fileName, options);
InputStream inputStream = item.getInputStream();
try {
copy(inputStream, Channels.newOutputStream(outputChannel));
} finally {
outputChannel.close();
inputStream.close();
}
private void copy(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = input.read(buffer);
while (bytesRead != -1) {
output.write(buffer, 0, bytesRead);
bytesRead = input.read(buffer);
}
}

Categories

Resources