Download a file through the Internet with RandomAccessFile - java

I was browsing the Internet for random Java code, and I found this source code for a download manager. It uses RandomAccessFile to download the files. The one thing I could not figure out though, was where it would download to. Here is the method that downloads the file:
public void startDownload() {
System.out.println("Starting...");
RandomAccessFile file = null;
InputStream stream = null;
try {
URL downloadLink = new URL("http://www.website.com/file.txt");
// Open the connection to the URL
HttpURLConnection connection = (HttpURLConnection) downloadLink.openConnection();
// Specify what portion of file to download
connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
// Connect to the server
connection.connect();
// Make sure the code is in the 200 range
if (connection.getResponseCode() / 100 != 2) {
error();
}
// Check for valid content length
int contentLength = connection.getContentLength();
if (contentLength < 1) {
error();
}
// Set the size for the download if it hasn't been already set
if (size == -1) {
size = contentLength;
stateChanged();
}
// Open file and seek to the end of it
file = new RandomAccessFile(getFileName(downloadLink), "rw");
// getFileName returns the name of the file mentioned in the URL
file.seek(downloaded);
stream = connection.getInputStream();
while (status == DOWNLOADING) {
System.out.println("Progress: " + getProgress() + "%");
// Size the buffer according to how much of the file is left to download
byte buffer[];
if (size - downloaded > MAX_BUFFER_SIZE) {
buffer = new byte[MAX_BUFFER_SIZE];
} else {
buffer = new byte[size - downloaded];
}
// Read from the server into the buffer
int read = stream.read(buffer);
if (read == -1) {
break;
}
// Write buffer to file
file.write(buffer, 0, read);
downloaded += read;
stateChanged();
}
if (status == DOWNLOADING) {
status = COMPLETE;
stateChanged();
}
} catch (Exception e) {
error();
} finally {
// Close the stream and RAF
}
System.out.println("Done!");
}
I am sorry if this is obvious. I am new to the RandomAccessFile class, as I just learned of it today.

It will download it in the current working directory (i.e. where you run your java command) and the name of the file will be given by getFileName(downloadLink).

I am new to this too. getFileName appears to be a method within the same class and that code is missing.

Related

Memory Consumption by Java Applet

In my applet I have GET call to download file from a remote location. When I am trying to download some large file of around 13MB, then my Applet memory consumption is increasing more than 50MB. I am using the below code to get my memory consumption:
public static long getMemoryUsage()
{
long memory = 0;
// Get the Java runtime
Runtime runtime = Runtime.getRuntime();
memory = runtime.totalMemory() - runtime.freeMemory();
return memory;
}
Code for my get call is
public void getFiles(String filePath, long fileSize)throws MyException
{
InputStream objInputStream = null;
HttpURLConnection conn = null;
BufferedReader br = null;
try
{
URL fileUrl=new URL(filePath);
final String strAPICall=fileUrl.getPath();
final String strHost="some.test.com";
final int iPort=1000;
URL url = null;
url = new java.net.URL
( "https",
strHost, iPort , "/" + strAPICall,
new myHandler() );
conn = (HttpURLConnection)new HttpsURLConn(url);
conn.setRequestMethod("GET");
conn.connect();
if (conn.getResponseCode() != 200) {
objInputStream=conn.getInputStream();
br = new BufferedReader(new InputStreamReader(
(objInputStream)));
String output;
while ((output = br.readLine()) != null) {
System.out.println(output);
}
throw new MyException("Bad response from server",
MyError.BAD_RESPONSE_ERROR);
}
else
{
notifyProgressToObservers(0);
System.out.println("conn.getResponseCode()"+conn.getResponseCode());
System.out.println("conn.getResponseMessage()"+conn.getResponseMessage());
objInputStream = conn.getInputStream();
int count=objInputStream.available();
System.out.println("Stream size: "+count);
System.out.println("fileSize size: "+fileSize);
byte []downloadedData = getBytesFromInputStream
(objInputStream, count,fileSize);
notifyChunkToObservers(downloadedData);
notifyIndivisualFileEndToObservers(true, null);
}
}
catch (MyException pm)
{
throw new MyException
(pm, MyError.CONNECTION_TIMEOUT);
}
catch (IOException pm)
{
throw new MyException
(pm, MyError.CONNECTION_TIMEOUT);
}
catch (Exception e)
{
notifyIndivisualFileEndToObservers(false,new MyException(e.toString()));
}
finally
{
System.out.println("Closing all the streams after getting file");
if(conn !=null)
{
try
{
conn.disconnect();
}
catch(Exception e)
{
}
}
if(objInputStream != null)
{
try {
objInputStream.close();
} catch (IOException e) {
}
}
if (br != null)
{
try {
br.close();
} catch (IOException e) {
}
}
}
}
In the above method, I tried putting the log for memory consumption after each line and found that after conn.connect();, the memory consumption of applet increases by atleast 50MB even though the file I am trying to download is only 13MB.
Is there any memory leak anywhere?
EDIT: Added Implementation for getBytesFromInputStream()
public byte[] getBytesFromInputStream(InputStream is, int len, long fileSize)
throws IOException
{
byte[] readBytes= new byte[8192];
ByteArrayOutputStream getBytes= new ByteArrayOutputStream();
int numRead = 0;
while ((numRead = is.read(readBytes)) != -1) {
getBytes.write(readBytes, 0, numRead);
}
return getBytes.toByteArray();
}
it's because of this line:
byte []downloadedData = getBytesFromInputStream(objInputStream, count,fileSize);
here you are reading the complete amount of bytes of file into the heap. After that you need to track down what happens with this array. Maybe you are copying it somewhere and the GC needs some time to kick in even if you do not use the reference to the object anymore.
Large files should never be read completly to memory, but rather streamed directly to some processor of the data.
The only way to optimize getBytesFromInputStream() is if you know beforehand exactly how many by bytes there are to read. Then you allocate a byte[] of the required size, and read from the input directly into the byte[]. For example:
byte[] buffer = new byte[len];
int pos = 0;
while (pos < len) {
int nosRead = is.read(buffer, pos, len - pos);
if (nosRead == -1) {
throw new IOException("incomplete response");
}
pos += nosRead;
}
return buffer;
(For more information, read the javadoc.)
Unfortunately, your (apparent) attempt at getting the size is incorrect.
int count = objInputStream.available();
This doesn't return the total number of bytes that can be read from the stream. It returns the number of bytes that can be read right now without the possibility of blocking.
If the server is setting the Content-Length header in the response, then you could use that; call getContentLength() (or getContentLengthLong() in other use-cases) once you have the response. But be prepared for the case where that gives you -1.

Java File Download - Downloaded file size is always zero Kb

I have written a java controller which handles any download request from the server. My files are present in the server however I am getting 0 kB file downloaded every time. The file is getting downloaded but the size is always 0 Kb. Please help me. Here is my code -
#RequestMapping(value="/downloadFile/{docId}")
public void getDownloadFile(#PathVariable(value = "docId") Integer docId, HttpServletResponse response) throws Exception {
String userName = getUserName();
try {
DocVault documentsVault = documentsVaultRepository.findDocumentAttachment(docId);
String fileName = documentsVault.getDocumentName();
int customerId = documentsVault.getCustomerId();
Map<Integer, String> customerInfo = cspUtils.getCustomersInfo(userName);
Set<Integer> customerIds = customerInfo.keySet();
for (int custId : customerIds) {
if (custId == customerId) {
String path = env.getProperty("doc.rootfolder") + File.separator + documentsVault.getFileName();
service.downloadFile(fileName, path, response);
} else {
logger.info("Customer not linked to user");
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
Implementation -
public void downloadFile(String fileName, String path, HttpServletResponse response) {
try {
File downloadFile = new File(path);
FileInputStream inputStream = new FileInputStream(downloadFile);
response.setContentLength((int) downloadFile.length());
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
// get output stream of the response
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
// write bytes read from the input stream into the output stream
while ((bytesRead = inputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I am not getting any exceptions. Please help.
Thank you in advance.
response.setContentLength((int) downloadFile.length());
Remove this. The container will set it automatically.
int bytesRead = -1;
You don't need to initialize this variable. It gets assigned in the very next line.
Thank you for your help. What I figured out was there was a problem with my Content Disposition header. I was passing only the file name without extension. When I passed the full file name then it worked perfectly. Size and Extension of the file were proper.

java : corrupted zip file created when copy using nio

I have implement following code to copy file(binary file)
code
private void copyFileWithChannels(File aSourceFile, File aTargetFile) {
log("Copying files with channels.");
FileChannel inChannel = null;
FileChannel outChannel = null;
FileInputStream inStream = null;
FileOutputStream outStream = null;
try {
inStream = new FileInputStream(aSourceFile);
inChannel = inStream.getChannel();
outStream = new FileOutputStream(aTargetFile);
outChannel = outStream.getChannel();
long bytesTransferred = 0;
while(bytesTransferred < inChannel.size()){
bytesTransferred += inChannel.transferTo(0, inChannel.size(), outChannel);
}
}
catch(FileNotFoundException e){
log.error("FileNotFoundException in copyFileWithChannels()",e);
}
catch (IOException e) {
log.error("IOException in copyFileWithChannels()",e);
}
catch (Exception e) {
log.error("Exception in copyFileWithChannels()",e);
}
finally {
try{
if (inChannel != null) inChannel.close();
if (outChannel != null) outChannel.close();
if (inStream != null) inStream.close();
if (outStream != null) outStream.close();
}catch(Exception e){
log.error("Exception in copyFileWithChannels() while closing the stream",e);
}
}
}
I have test code with one zip file. when i verify file I found that file which generated is corrupt(size was increased).
Source zip file is about 9GB.
Try this:
while(bytesTransferred < inChannel.size()){
bytesTransferred += inChannel.transferTo(bytesTransferred, inChannel.size() - bytesTransferred, outChannel);
}
Also, I would refer to IOUtils implementation, as a reference
https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/FileUtils.java
specifically
private static void doCopyFile(final File srcFile, final File destFile, final boolean preserveFileDate)
The transferTo method's first argument gives the position from which to transfer, not relative to where the stream left off, but relative to the start of the file. Since you put 0 there it will always transfer from the start of the file. So that line needs to be
bytesTransferred += inChannel.transferTo(bytesTransferred , inChannel.size(), outChannel);
mavarazy mentioned in his answer he's not sure if you need a loop when using inChannel.size(), since the expectation is that if you supply the whole size it will copy the entire file. However, the actual transfer might be less than the requested number of bytes if the output channel's buffer has less room available. So you do need the loop as in his second code snippet.
Unless you have a good reason best to use Files.copy(Path, Path, CopyOption...).

Java. Save File to Client side not working

I want to save File to a client side. How it can be done ?
When i start server localy all is good Files are saved # needed place, when run on server then files are saved on server side :( . Because System.getProperty("user.home") are returning :/root .
User select File from system and wants to open it. Code example:
mylog.pl("Blob in use + stop counter:" + stop);
File file = new File(SU.userHome + "/" + fileName);
mylog.pl("File maked ! Path:" + file.getAbsolutePath());
in = blob.getBinaryStream();
out = new FileOutputStream(file);
byte[] buff = new byte[4096];
int len = 0;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
try {
mylog.pl("Desktop Open!");
if (Desktop.isDesktopSupported())
{
Desktop.getDesktop().open(file);
}
else
{
mylog.pl("Desktop is not suported!");
//For other IS
DesktopApi.open(file);
}
}
catch (Exception e) {
mylog.pl("err # runtime" + e.getMessage());
}
Thanks ! Correct answers guaranteed !
//From server to client
final FileResource res = new FileResource(file);
FileDownloader fd = new FileDownloader(res);
p.open(res, "MyWindow", false);
file.delete();

Android - Download File From The Internet to SDCard - Safest Approach

I'm developing an APP that needs to download a file from the Internet and store it on the SDCard.
I've noticed that some devices report errors while downloading, such as "Parsing Error". I'm assuming that some devices don't have SDCard or the path that I'm getting in my class isn't correct. What's the safest approach to support all devices if there's no SDCard or isn't mounted ?
This is my code:
/**
* Downloading file in background thread
* */
#Override
protected String doInBackground(String... f_url) {
int count;
try {
URL url = new URL(f_url[0]);
URLConnection conection = url.openConnection();
conection.connect();
// getting file length
int lenghtOfFile = conection.getContentLength();
// input stream to read file - with 8k buffer
InputStream input = new BufferedInputStream(url.openStream(), 8192);
// Output stream to write file
OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()+"/Download/file.apk");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
// After this onProgressUpdate will be called
publishProgress(""+(int)((total*100)/lenghtOfFile));
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
return null;
}
I think the problem may be on this line:
OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()+"/Download/file.apk");
Should I use the getExternalStorageDirectory() and download ? or is there any "safest" location that is common to all devices ?
First, you don't want to use AsyncTask to download a file. Because if the user kills that screen that hosts the Task, the download will be killed too. Look into IntentService.
Second, familiarize yourself with the Android code examples here: http://developer.android.com/guide/topics/data/data-storage.html#filesExternal
You can check for what's available and then get the appropriate directory.

Categories

Resources