I'm writing a program to download a PDF file from server. I'm using some program given here Download file by passing URL using java code, this solution works fine for the sample URL provided in the first answer, but not for PDF, I'm replacing just the URL. Below is my code.
import java.io.*;
import java.net.*;
public class FileDownloadTest {
final static int size = 1024;
public static void fileUrl(String fAddress, String localFileName, String destinationDir) {
// localFileName = "Hello World";
OutputStream outStream = null;
URLConnection uCon = null;
InputStream is = null;
try {
URL url;
byte[] buf;
int byteRead, byteWritten = 0;
url = new URL(fAddress);
outStream = new BufferedOutputStream(new FileOutputStream(destinationDir + "\\" + localFileName));
uCon = url.openConnection();
is = uCon.getInputStream();
buf = new byte[size];
while ((byteRead = is.read(buf)) != -1) {
outStream.write(buf, 0, byteRead);
byteWritten += byteRead;
}
System.out.println("Downloaded Successfully.");
System.out.println("File name:\"" + localFileName + "\"\nNo ofbytes :" + byteWritten);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void fileDownload(String fAddress, String destinationDir) {
int slashIndex = fAddress.lastIndexOf('/');
int periodIndex = fAddress.lastIndexOf('.');
String fileName = fAddress.substring(slashIndex + 1);
if (periodIndex >= 1 && slashIndex >= 0 && slashIndex < fAddress.length() - 1) {
fileUrl(fAddress, fileName, destinationDir);
} else {
System.err.println("path or file name.");
}
}
public static void main(String[] args) {
String fAddress = "http://singztechmusings.files.wordpress.com/2011/09/maven_eclipse_and_osgi_working_together.pdf";
String destinationDir = "D:\\FileDownload";
fileDownload(fAddress, destinationDir);
}
}
Here, This pdf has 73 pages, and in my folder, it is download as a PDF of 1KB, when opened in Acrobat Reader, it says that the file might be corrupted.
I've also tried the code provided here https://dzone.com/articles/java-how-save-download-file, but the result is same.
please let me know how can I fix this.
Thanks
If you check the downloaded file content, you can see it is html. The server is redirecting the original request to https url. Use url https://singztechmusings.files.wordpress.com/2011/09/maven_eclipse_and_osgi_working_together.pdf instead.
Or use http client with automatic redirect handling, ala http-commons
You define a Variable size = 1024 and use this to define your Buffer.
So logically you can only write 1 KB into it.
But if the input Stream reads more at once it will be lost ... So change your Buffer size to a value which would be able to contain most documents or try to determine the necessary size
Related
How we can push multiple files from our local folder to smb share folder using java. I can do with my single file using smbFile and it is working. I am looking for pushing multiple file push to smb share.
Any reference links and sample code would be helpful.
Thanks.
EDIT, Reference of code :
SmbFile[] files = getSMBListOfFiles(sb, logger, domain, userName, password, sourcePath, sourcePattern);
if (files == null)
return false;
output(sb, logger, " Source file count: " + files.length);
String destFilename;
FileOutputStream fileOutputStream;
InputStream fileInputStream;
byte[] buf;
int len;
for (SmbFile smbFile: files) {
destFilename = destinationPath + smbFile.getName();
output(sb, logger, " copying " + smbFile.getName());
try {
fileOutputStream = new FileOutputStream(destFilename);
fileInputStream = smbFile.getInputStream();
buf = new byte[16 * 1024 * 1024];
while ((len = fileInputStream.read(buf)) > 0) {
fileOutputStream.write(buf, 0, len);
}
fileInputStream.close();
fileOutputStream.close();
} catch (SmbException e) {
OutputHandler.output(sb, logger, "Exception during copyNetworkFilesToLocal stream to output, SMP issue: " + e.getMessage(), e);
e.printStackTrace();
return false;
}
This works fine if i try to send one single file of anyformat. But if would like to send multiple file to smb share fromocal folder. For This i need thr help please. Thanks.
Try to declare a SmbFile object that is a root folder of your folder, that you want to upload to the shared folder. Then iterate through the root.listFiles() array.
Put the uploadable files in that folder.
I assume that, your SmbFile[] files array only contains one file if it's only uploading one file.
Or another possible solution is that, try to use SmbFileOutputStream and SmbFileInputStream instead of FileOutputStream and FileInputStream.
I'm guessing you are using jcifs-library (which is quite outdated), so firstly I would recommend you to switch library. I switched to SMBJ and here is how I'm uploading file:
private static void upload(File source, DiskShare diskShare, String destPath, boolean overwrite) throws IOException {
try (InputStream is = new java.io.FileInputStream(source)) {
if (destPath != null && is != null) {
// https://learn.microsoft.com/en-us/windows/win32/fileio/creating-and-opening-files
Set<AccessMask> accessMask = new HashSet<>(EnumSet.of(
AccessMask.FILE_READ_DATA,
AccessMask.FILE_WRITE_DATA, AccessMask.DELETE));
Set<SMB2ShareAccess> shareAccesses = new HashSet<>(
EnumSet.of(SMB2ShareAccess.FILE_SHARE_WRITE));
Set<FileAttributes> createOptions = new HashSet<>(
EnumSet.of(FileAttributes.FILE_ATTRIBUTE_NORMAL));
try (com.hierynomus.smbj.share.File file = diskShare
.openFile(destPath, accessMask, createOptions,
shareAccesses,
(overwrite
? SMB2CreateDisposition.FILE_OVERWRITE_IF
: SMB2CreateDisposition.FILE_CREATE),
EnumSet.noneOf(SMB2CreateOptions.class))) {
int bufferSize = 2048;
if (source.length() > 20971520l) {
bufferSize = 131072;
}
byte[] buffer = new byte[bufferSize];
long fileOffset = 0;
int length = 0;
while ((length = is.read(buffer)) > 0) {
fileOffset = diskShare.getFileInformation(destPath)
.getStandardInformation().getEndOfFile();
file.write(buffer, fileOffset, 0, length);
}
file.flush();
file.close();
} finally {
is.close();
}
}
}
}
Of course takes a little effort on connecting the SMB-server and authenticating before this, but that's another case...
I have two services first frontend_service and second backend_service and I'm getting the large file from backend_service and trying to forward to user via frontend_service using
response.getBodyAsStream() but this is causing "java.lang.OutOfMemoryError: GC overhead limit exceeded" in frontend_service.
code for backend_service:
`
public static Result downloadLargeFile(String filePath){
File file = new File(filePath);
InputStream inputStream = new FileInputStream(file);
return ok(inputStream);
}
`
code for frontend_service:
`
public static F.Promise<Result> downloadLargeFile(String filePath) {
//this will call backend_service downloadLargeFile method.
String backEndUrl = getBackEndUrl(filePath);
return getInputStream(backEndUrl);
}
`
`
public static Promise<Result> getInputStream(String url) {
return WS.url(url).get().map(
response -> {
InputStream inputStream = response.getBodyAsStream();
return ok(inputStream);
}
);
}
`
I tried the solution suggested here by reading few bytes at a time from inputStream and creating tmp file in frontend_service and sending the tmp file as output from frontend_service.
`
public static Promise<Result> getInputStream(String url) {
return WS.url(url).get().map(
response -> {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = response.getBodyAsStream();
//write input stream to tmp file
final File tmpFile = new File("/tmp/tmp.txt");
outputStream = new FileOutputStream(tmpFile);
int read = 0;
byte[] buffer = new byte[500];
while((read = inputStream.read(buffer)) != -1){
outputStream.write(buffer, 0 , read);
}
return ok(tmpFile);
} catch (IOException e) {
e.printStackTrace();
return badRequest();
} finally {
if (inputStream != null) {inputStream.close();}
if (outputStream != null) {outputStream.close();}
}
}
);
`
Above code also throwing java.lang.OutOfMemoryError. I'm trying 1 GB file.
I do not have the implementation "under the hand", so I will write the algorithm.
1. Play uses the AsyncHttpClient under the WS. You need to get it, or create it as described in the https://www.playframework.com/documentation/2.3.x/JavaWS#Using-WSClient
2. Then, you need to implement the AsyncCompletionHandler, like in the description of the class https://static.javadoc.io/org.asynchttpclient/async-http-client/2.0.0/org/asynchttpclient/AsyncHttpClient.html
3. In the onBodyPartReceived method of the AsyncCompletionHandler class, you need to push the body part to the chunked play response. Chanked responses described here: https://www.playframework.com/documentation/2.3.x/JavaStream#Chunked-responses
P.S.
The discussion of the similar solution but in oposite direction - streaming uploading to the "backend" (Amazon) service through the "frontend" (play 2) service:
https://groups.google.com/d/msg/asynchttpclient/EpNKLSG9ymM/BAGvwl0Wby8J
When I upload files to local system's temp directory from Mozilla Browser I get Access denied error. But if I do the same thing from Eclipse Browser I dont see any error, means it is uploading without any error:
Code:
for (Part part : request.getParts()) {
fileName = getFileName(part);
part.write(System.getProperty("java.io.tmpdir") + fileName);
}
private String getFileName(Part part) {
String contentDisp = part.getHeader("content-disposition");
System.out.println("content-disposition header= "+contentDisp);
String[] tokens = contentDisp.split(";");
for (String token : tokens) {
if (token.trim().startsWith("filename")) {
return token.substring(token.indexOf("=") + 2, token.length()-1);
}
}
return "";
Error:
java.io.IOException: java.io.FileNotFoundException: C:\Users\user\AppData\Local\Temp (Access is denied)
Allan, this is the code:
final String path = System.getProperty("java.io.tmpdir");
OutputStream out = null;
InputStream filecontent = null;
final PrintWriter writer = response.getWriter();
try {
for (Part part : request.getParts()) {
String fileName = getFileName(part);
out = new FileOutputStream(new File(path , fileName));
filecontent = part.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = filecontent.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
File UploadedFile = new File(path + File.separator + fileName);
UploadedFile.delete();
}
} catch (FileNotFoundException fne) {
writer.println("You either did not specify a file to upload or are "
+ "trying to upload a file to a protected or nonexistent "
+ "location.");
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
if (writer != null) {
writer.close();
}
}
See this example, when create the file use two parameter as the example:
File scratchFile = new File(System.getProperty("java.io.tmpdir"), "filename.tmp");
Example:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// Create path components to save the file
final String path = System.getProperty("java.io.tmpdir");
final Part filePart = request.getPart("file");
final String fileName = getFileName(filePart);
OutputStream out = null;
InputStream filecontent = null;
final PrintWriter writer = response.getWriter();
try {
//File Temp here with two parameters
out = new FileOutputStream(new File(path , "filename.tmp"));
filecontent = filePart.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while ((read = filecontent.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
writer.println("New file " + fileName + " created at " + path);
} catch (FileNotFoundException fne) {
writer.println("You either did not specify a file to upload or are "
+ "trying to upload a file to a protected or nonexistent "
+ "location.");
writer.println("<br/> ERROR: " + fne.getMessage());
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
if (writer != null) {
writer.close();
}
}
}
And your method:
private String getFileName(final Part part) {
final String partHeader = part.getHeader("content-disposition");
LOGGER.log(Level.INFO, "Part Header = {0}", partHeader);
for (String content : part.getHeader("content-disposition").split(";")) {
if (content.trim().startsWith("filename")) {
return content.substring(content.indexOf('=') + 1).trim().replace("\"", "");
}
}
return null;
}
References:
Permission
Upload Method
In case of a web application, the Webcontainer might have set some SecurityManager (https://docs.oracle.com/javase/8/docs/api/java/lang/SecurityManager.html) to block write access to the local file system.
Check if this has been the case...
Same problem I was facing few minutes ago.
Your code won't work for file upload with other request parameter together.
when you're calling getParts() it takes other parameters also as parts.
Now in case of file taken as part content-dipsosition header has
form-data; name="<file-parameter-name>"; filename="<filename>"
A thing to be noted <filename> may be different if submitted from
different browser. Try to submit it from eclipse's in built browser.
Try to print and see content-disposition header by
System.out.println(part.getHeader("content-disposition"));
In case of your loop runs for other parameters taken as part, content-disposition has
form-data; name=""
Now see there is nothing like filename="", so your function to get filename returns null.
Now you calls part.write() but inside only path is passed not filename as function you called to get filename returns null. So you get exception even thought it actually uploads file.
After getting filename put a condition
if(filename.equals("")){continue;}
But that's also not a good solution as loop iterate for no reason for other parameter.
I have a method to download image from URL. As like below..
public static byte[] downloadImageFromURL(final String strUrl) {
InputStream in;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
URL url = new URL(strUrl);
in = new BufferedInputStream(url.openStream());
byte[] buf = new byte[2048];
int n = 0;
while (-1 != (n = in.read(buf))) {
out.write(buf, 0, n);
}
out.close();
in.close();
}
catch (IOException e) {
return null;
}
return out.toByteArray();
}
I have an image url and it is valid. for example.
https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTxfYM-hnD-Z80tgWdIgQKchKe-MXVUfTpCw1R5KkfJlbRbgr3Zcg
My problem is I don't want to download if image is really not exists.Like ....
https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTxfYM-hnD-Z80tgWdIgQKchKe-MXVUfTpCw1R5KkfJlbRbgr3Zcgaaaaabbbbdddddddddddddddddddddddddddd
This image shouldn't be download by my method. So , how can I know the giving image URL is not really exists. I don't want to validate my URL (I think that may not my solution ).
So, I googled for that. From this article ...
How to check if a URL exists or returns 404 with Java? and
Check if file exists on remote server using its URL
But this con.getResponseCode() will always return status code "200". This mean my method will also download invalid image urls. So , I output my bufferStream as like...
System.out.println(in.read(buf));
Invalid image URL produces "43". So , I add these lines of codes in my method.
if (in.read(buf) == 43) {
return null;
}
It is ok. But I don't think that will always satisfy. Has another way to get it ? am I right? I would really appreciate any suggestions. This problem may struct my head. Thanks for reading my question.
*UPDATE
I call this download method and save downloaded image in some directory as..
// call method to save image
FileSupport.saveFile(filePath+".JPG", data);
After that I tried to output as...
File file = new File(filePath+".JPG);
System.err.println(file.length());
that may also produces "43" for invalid image urls. I want to know why that return "43" for all of invalid urls. what is "43" ?
Try this,
Open an image in notepad or something and check the first 3-4 characters, it will tell you the format of the image..
When downloading check the first 3 or 4 characters, that should tell you if this image is valid or not.
Note: Here, I'm assuming that your requirement is specific to certain types of images and not all possible images.
some samples:
‰PNG for PNG images
����JFIF for JPG images.
byte[] tenBytes=new byte[10];
// fill this array with the first 10 bytes.
String str = new String(tenBytes);
if(str.contains("JIFF")){
// JPG
}
if(str.contains("PNG"){
// PNG
} ...
if nothing matches, its either an invalid image or an image you don't want.
Note this is untested code.. you might have to make adjustments for it to work properly. you should look at this as an psuedo code to build your implementation...
Update:
Instead of checking for file size 43, you should be looking for the content (as described above).
If
con.setRequestMethod("HEAD");
does not help you, you should do something like this (read from connection's input strean will fail if the image does not exist.
HttpUrlConnection con = (HttpUrlConnection)url.openConnection;
con.setRequestMethod("GET");
con.addRequestProperty("User-Agent", "Mozilla/4.0");
int responseCode = con.getResponseCode(); //if you do not get 200 here, you can stop
if(responseCode != HttpUrlConnection.HTTP_OK) {
return;
}
// Now, read image buffer
byte[] image = null;
try{
InputStream in = new BufferedInputStream(con.getInputStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n = 0;
while (-1!=(n=in.read(buf)))
{
out.write(buf, 0, n);
}
out.close();
in.close();
image = out.toByteArray();
} catch (IOException ioe){
// do whatever you need
} finally {
con.disconnect();
}
Also, this code
if (in.read(buf) == 43) {
return null;
}
does not look good. Some magic number, not clear what is it.
This is how I would do it:
//By Nishanth Chandradas
import java.awt.Image;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.activation.MimetypesFileTypeMap;
import javax.swing.ImageIcon;
import java.io.File;
public class downloadimagefromurl {
/**
* #param args
* #throws IOException
*/
public static byte[] downloadImageFromURL(final String strUrl) throws IOException {
InputStream in;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
URL url = new URL(strUrl);
in = new BufferedInputStream(url.openStream());
byte[] buf = new byte[2048];
int n = 0;
while (-1 != (n = in.read(buf))) {
out.write(buf, 0, n);
}
out.close();
in.close();
}
catch (IOException e) {
return null;
}
byte[] response = out.toByteArray();
FileOutputStream fos = new FileOutputStream("/Users/Nish/Desktop/image.jpg");
fos.write(response);
fos.close();
return response;
}
static boolean isImage(String image_path){
Image image = new ImageIcon(image_path).getImage();
if(image.getWidth(null) == -1){
return false;
}
else{
return true;
}
}
public static void main(String[] args) throws IOException {
downloadImageFromURL("https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcTxfYM-hnD-Z80tgWdIgQKchKe-MXVUfTpCw1R5KkfJlbRbgr3Zcg");
System.out.println(isImage("/Users/Nish/Desktop/image.jpg"));
}
The output will be true or false depending if the download was an image or not.
You can add a second catch statement to catch java.io.FileNotFoundException
catch (FileNotFoundException e) {
// Failed
}
I wonder if there is any other way to move files from one directory to another, a snippet of my program is below. I believe there should be an efficient way to move files in java. Please take a look and respond if possible. Thanks!
public static void movFile(File pathFromMove,File pathToMove,File fileToMove) //helper method 2
{
String absPathFile2= pathToMove.getAbsolutePath() + "\\"+fileToMove.getName(); //{
InputStream inStream = null;
OutputStream outStream = null;
try
{
//System.out.println("i am here no1");
inStream= new FileInputStream(fileToMove);
outStream=new FileOutputStream(absPathFile2);
byte[] buffer = new byte[1024];
int length;
while (( length = inStream.read(buffer)) > 0)
{
outStream.write(buffer, 0, length);
//System.out.println("i am here no2");
}
inStream.close();
outStream.close();
fileToMove.delete(); //to delete the original files
// System.out.println("i am here no3");
}
catch(IOException e)
{
//System.out.println("i am here no4");
e.printStackTrace();
}
}
If it's on the same disk, the File.renameTo would be efficient
I'm not sure why you would need 3 File references, two should be enough...but it's your code...
For example...
public static void movFile(File pathFromMove,File pathToMove,File fileToMove) throws IOException {
File from = new File(pathFromMove + File.separator + fileToMove);
File to = new File(pathToMove+ File.separator + fileToMove);
if (!from.renameTo(to)) {
throw new IOException("Failed to move " + from + " to " + to);
}
}
You can alos have a look at Moving a File or Directory which uses the new Paths API available in Java 7