You can use apache commons IO library. It's easy. I have used it in many projects.
File dstFile = null;
// check the directory for existence.
String dstFolder = LOCAL_FILE.substring(0,LOCAL_FILE.lastIndexOf(File.separator));
if(!(dstFolder.endsWith(File.separator) || dstFolder.endsWith("/")))
dstFolder += File.separator;
// Creates the destination folder if doesn't not exists
dstFile = new File(dstFolder);
if (!dstFile.exists()) {
dstFile.mkdirs();
}
try {
URL url = new URL(URL_LOCATION);
FileUtils.copyURLToFile(url, dstFile);
} catch (Exception e) {
System.err.println(e);
VeBLogger.getInstance().log( e.getMessage());
}
Answer from bitkot on Stack OverflowYou can use apache commons IO library. It's easy. I have used it in many projects.
File dstFile = null;
// check the directory for existence.
String dstFolder = LOCAL_FILE.substring(0,LOCAL_FILE.lastIndexOf(File.separator));
if(!(dstFolder.endsWith(File.separator) || dstFolder.endsWith("/")))
dstFolder += File.separator;
// Creates the destination folder if doesn't not exists
dstFile = new File(dstFolder);
if (!dstFile.exists()) {
dstFile.mkdirs();
}
try {
URL url = new URL(URL_LOCATION);
FileUtils.copyURLToFile(url, dstFile);
} catch (Exception e) {
System.err.println(e);
VeBLogger.getInstance().log( e.getMessage());
}
Firstly, I'd suggest you use:
FileInputStream in = new FileInputStream(file);
instead of:
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
(To avoid building up memory usage)
try
{
FileInputStream fileInputStream = new FileInputStream(file);
byte[] buf=new byte[8192];
int bytesread = 0, bytesBuffered = 0;
while( (bytesread = fileInputStream.read( buf )) > -1 ) {
out.write( buf, 0, bytesread );
bytesBuffered += bytesread;
if (bytesBuffered > 1024 * 1024) { //flush after 1MB
bytesBuffered = 0;
out.flush();
}
}
}
finally {
if (out != null) {
out.flush();
}
}
how to download large files without memory issues in java - Stack Overflow
url - downloading a large file in java - Stack Overflow
Download large file through java client in HTTP - Stack Overflow
Download Large Files using java - Stack Overflow
There are 2 places where I can see you could potentially be building up memory usage:
- In the buffer reading your input file.
- In the buffer writing to your output stream (HTTPOutputStream?)
For #1 I would suggest reading directly from the file via FileInputStream without the BufferedInputStream. Try this first and see if it resolves your issue. ie:
FileInputStream in = new FileInputStream(file);
instead of:
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
If #1 does not resolve the issue, you could try periodically flushing the output stream after so much data is written (decrease chunk size if necessary):
ie:
try
{
FileInputStream fileInputStream = new FileInputStream(file);
byte[] buf=new byte[8192];
int bytesread = 0, bytesBuffered = 0;
while( (bytesread = fileInputStream.read( buf )) > -1 ) {
out.write( buf, 0, bytesread );
bytesBuffered += bytesread;
if (bytesBuffered > 1024 * 1024) { //flush after 1MB
bytesBuffered = 0;
out.flush();
}
}
}
finally {
if (out != null) {
out.flush();
}
}
Unfortunately you have not mentioned what type out is. If you have memory issues I guess it is ByteArrayOutpoutStream. So, replace it by FileOutputStream and write the byte you are downloading directly to file.
BTW, do not use read() method that reads byte-by-byte. Use read(byte[] arr) instead. This is much faster.
I do not know if this is related to your problem, but it looks like you are not using read() correctly. read() returns -1 upon end of input, and may read less than the specified number of bytes even if more data is available. I would recommend instead using
while ((bytesRead = inputStream.read(buffer, 0, buffer.length)) != -1) {
resp.getOutputStream().write(buffer, 0, bytesRead);
}
Your original code risks terminating the read loop before end of data, or calling write() with bytesRead set to -1. Also, the offset variable in your original code seems unnecessary; the offset should always be 0, since you are trying to fill the entire buffer.
If you're getting a SocketException, the problem isn't with the code here, but with the underlying networking protocol. In this case, "broken pipe" means that you're losing the connection to the server -- either because the server is hanging up, the Internet connection is shaky, or something else -- and read is throwing the exception because it happens to be the method trying to use that connection at the moment.
You can also generate HTML instead of CSV and still set the content type to Excel. This is nice for colouring and styled text.
You can also use gzip compression when the client accepts that compression. Normally there are standard means, like a servlet filter.
Never a StringBuffer or the better StringBuilder. Better streaming it out. If you do not (cannot) call setContentength, the output goes chunked (without predictive progress).
URL url = new URL("http://localhost:8080/Works/images/address.csv");
response.setHeader("Content-Type", "text/csv");
response.setHeader("Content-disposition", "attachment;filename=myFile.csv");
URLConnection connection = url.openConnection();
InputStream stream = connection.getInputStream();
BufferedOutputStream outs = new BufferedOutputStream(response.getOutputStream());
int len;
byte[] buf = new byte[1024];
while ((len = stream.read(buf)) > 0) {
outs.write(buf, 0, len);
}
outs.close();
Have you tried using the copyLarge() methods from IOUtils? For the copy() methods the JavaDoc says:
"For large streams use the copyLarge(InputStream, OutputStream) method."
You should check the response message first, and decide which side fire the problem. As my experience, you should check whether the file was cached by the browser rather than any problems~
@levand:
My actual preference, as a user, in these situations is to download a lightweight .exe file that downloads the file for you.
That's a dealbreaker for many, many sites. Users either are or should be extremely reluctant to download .exe files from websites and run them willy-nilly. Even if they're not always that cautious, incautious behaviour is not something we should encourage as responsible developers.
If you're working on something along the lines of a company intranet, a .exe is potentially an okay solution, but for the public web? No way.
@TonyB:
What is the best way to do this without using FTP.
I'm sorry, but I have to ask why the requirement. Your question reads to me along the lines of "what's the best way to cook a steak without any meat or heat source?" FTP was designed for this sort of thing.
bittorrent?
There have been a few web-based versions already (bitlet, w3btorrent), and Azureus was built using java, so it's definitely possible.
Edit: @TonyB is it limited to port 80?