How to properly reference image file in java jar? - java

Using java 1.8, I'm working with a Spring Boot jar file in which I'm including an image file into an Excel file using the xlsx4j package. I've got the code working to add the image file into the Excel file locally in my IDE, the problem is that it doesn't work after I compile the code into a jar file and deploy it to the server. I'm getting the following error message:
java.io.FileNotFoundException: File 'file:/opt/app/lib/myjar.jar!/BOOT-INF/classes!/myimage.jpg' does not exist
The image file exists in the src/main/resources folder in the project, and here is the code where I get the path to this file and pass it to the code that attaches the file to the Excel file:
URL imageUrl = Resources.getResource("myimage.jpg");
SpreadsheetMLPackage pkg = SpreadsheetMLPackage.createPackage();
WorksheetPart workSheetPart = pkg.createWorksheetPart(new PartName("/xl/worksheets/sheet1.xml"), "Quote", 1);
Worksheet worksheet = workSheetPart.getContents();
Drawing drawingPart = new Drawing();
Relationship drawingRel = workSheetPart.addTargetPart(drawingPart);
org.xlsx4j.sml.CTDrawing drawing = org.xlsx4j.jaxb.Context.getsmlObjectFactory().createCTDrawing();
workSheetPart.getJaxbElement().setDrawing(drawing);
drawing.setId( drawingRel.getId() );
BinaryPartAbstractImage imagePart
= BinaryPartAbstractImage.createImagePart(pkg, drawingPart,
FileUtils.readFileToByteArray(new File(imageUrl.getPath()) )); // Using path to image file here
String imageRelID = imagePart.getSourceRelationship().getId();
drawingPart.setJaxbElement(
genericExcelUtil.buildDrawingPartContentUsingCode(imageRelID));
Here is the stacktrace that I'm getting on the server:
java.io.FileNotFoundException: File 'file:/opt/app/lib/myapp.jar!/BOOT-INF/classes!/myimage.jpg' does not exist
at org.apache.commons.io.FileUtils.openInputStream(FileUtils.java:292)
at org.apache.commons.io.FileUtils.readFileToByteArray(FileUtils.java:1815)
at com.myco.myapp.util.excel.FileImpl.generateExcel(FileImpl.java:113)
at com.myco.myapp.service.impl.EmailServiceImpl.sendEmailService(EmailingServiceImpl.java:61)
at com.myco.myapp.controller.MyController.sendEmailWithDoc(MyController.java:374)
When doing a System.out.println of imageUrl.getPath(), this is what it looks like in my IDE:
/C:/Users/userid/Documents/workspace-sts-3.9.3.RELEASE/myapp/target/classes/myimage.jpg
This is what it looks like when run on the server:
file:/opt/app/lib/myapp.jar!/BOOT-INF/classes!/myimage.jpg
It seems that "new File(imageUrl.getPath())" is failing because when run from the server it cannot find the file. Any ideas on how I can handle this?

you have to load it via classpath
getClass().getResourceAsStream("/path/in/jar")
https://www.baeldung.com/reading-file-in-java

Using the suggestions provided here, I was able to open an input stream to the image file, put the contents of that input stream to a ByteArrayOutputStream, convert the ByteArrayOutputStream to a byte array, and then provide the byte array to the docx4j method:
URL imageUrl = Resources.getResource("myimage.jpg");
InputStream imageInputStream = imageUrl.openStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = imageInputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] byteArray = buffer.toByteArray();
BinaryPartAbstractImage imagePart
= BinaryPartAbstractImage.createImagePart(pkg, drawingPart, byteArray);
String imageRelID = imagePart.getSourceRelationship().getId();
drawingPart.setJaxbElement(
genericExcelUtil.buildDrawingPartContentUsingCode(imageRelID));
Thanks for the help!

Related

Zipping pdf files and downloading is giving corrupted file in java

I have tried this code for other files like .txt and excel files and they all are working fine. Same code if I use for pdf files, it will not show any error but when the file is downloaded, the zip folder will be corrupted. Is there any separate reading and writing process for pdf files?
//create byte buffer
byte[] buffer = new byte[1024];
ZipOutputStream zout = new
ZipOutputStream(response.getOutputStream());
Files[] files = new File(location).listFiles();
for(File pdfFile: files)
{
FileInputStream fin = new FileInputStream(pdfFile);
zout.putNextEntry(new ZipEntry(pdfFile);
int length;
while((length = fin.read(buffer)) > 0)
{
zout.write(buffer, 0, length);
}
zout.closeEntry();
fin.close();
}
zout.close();
This issue is resolved now. In the previous loop where I was creating the pdf files, the output stream was not closed and hence it was causing issue.

Convert Byte Array To File And Download

I am getting byte array from web service. this byte array is the pdf file. Below code execute well and download file on browser. But this file is seems corrupt. Also additional copy of file gets created on server which I am trying to avoid.
byte[] rawFile = myService.getDocument(param1, param2);
try (BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(rawFile));
FileOutputStream fileOutputStream = new FileOutputStream("myfile-1.pdf")) {
byte dataBuffer[] = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
response.setContentType("application/pdf");
response.setHeader("Content-Disposition","attachment;filename=myfile-1.pdf");
response.flushBuffer();
} catch (final Exception ex) {
ex.printStackTrace();
}
}
In a nutshell, below are 2 issue.
Downloaded file (on browser) is seems corrupt and not open. Generic pdf error message appears.
File which created on server is opening fine and shows content. But this file should not be physically present on server.
Downloaded file (on browser) is seems corrupt and not open.
Because you never sent the file content to the browser.
this file should not be physically present on server.
Then why did you explicitly write it there using FileOutputStream?
You need to write the file content to the response.
byte[] rawFile = myService.getDocument(param1, param2);
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment;filename=myfile-1.pdf");
OutputStream out = response.getOutputStream();
out.write(rawFile);
// no need to close or flush, that happens automatically when you return

Can a byte array be passed to an outbound file transport in mule ESB

I have a java component that is zipping a csv file and returning an array of bytes from a ByteArrayOutputStream. I'm attempting to pass this to a file transport to be written to the OS. A file is written to the OS, but Windows reports that the file is invalid when I attempt to open it. First, is it possible to send a byte array to the file transport? If so, then I think I will likely have to post another question about what I am doing wrong zipping the contents of the csv...
Here's a snippet of the java:
List<String> csvFiles = (List<String>)message.getPayload();
InputStream originalFile = null;
ByteArrayOutputStream dest = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(dest);
File temp = new File("users.csv");
originalFile = new
ByteArrayInputStream((csvFiles.get(0)).toString().getBytes());
ZipEntry entry = new ZipEntry(temp.getPath());
out.putNextEntry(entry);
int count;
while((count = originalFile.read()) != -1) {
out.write(count);
}
originalFile.close();
byte[] zipFileByteArray = dest.toByteArray();
out.close();
dest.close();
return zipFileByteArray;
Here's the relevant part of my flow:
<flow name="zip-csv">
<component class="edu.ucdavis.iet.canvas.ZipFiles" doc:name="Java"/>
<file:outbound-endpoint path="${message_archive.dir}" responseTimeout="10000" doc:name="save message to dir" outputPattern="temp.zip"/>
</flow>
I would suggest using the ZipTransformer class #anupambhusari submitted for this question:
Mule Zip File and send zipped file towards FTP server

Java : download file outside server context

I need to save a file and download file in directory outside server context.
I am using Apache Tomacat
I am able to do this in directory present in webapps directory of application
If my directory structure is as follows,
--src
--WebContent
-- uploaddir
-- myfile.txt
Then I am able to download in by simply.
download
But, problem is when file is in some other directory say d:\\uploadedfile\\myfile.txt
then I wont be able to download it, as resource is not in server context as above.
I have file path to uuid mapping,
like,
d:\\uploadedfiles\\myfile.txt <-> some_uuid
then I want file should be downloaded, on click of following,
download
So, How to make file downloadable when it is outside the server context,
I heard about getResourceAsStream() method which would do this , But would any one help me on how to do this, probably with simple code snippet?
Try the below code which you can write in filedownloadservet. Fetch the file name from the request parameter and then read and write the file.
If you need to do some security checks then do that before processing the request.
File file = new File("/home/files", "file name which user wants to download");
response.setContentType(getServletContext().getMimeType(file.getName()));
response.setContentLength(file.length());
BufferedInputStream inputStream = null;
BufferedOutputStream outputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(file));
outputStream = new BufferedOutputStream(response.getOutputStream());
byte[] buf = new byte[2048];
int len;
while ((len = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, len);
}
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
//log it
}
}
// do the same for input stream also
}
here i found the answer,
response.setContentType("application/msword");
response.setHeader("Content-Disposition","attachment;filename=downloadname.doc");
File file=new File("d:\\test.doc");
InputStream is=new FileInputStream(file);
int read=0;
byte[] bytes = new byte[BYTES_DOWNLOAD];
OutputStream os = response.getOutputStream();
while((read = is.read(bytes))!= -1){
os.write(bytes, 0, read);
}
os.flush();
os.close();
Base path will not work that is for HTML and it works if the base path is also exposed by your web server which does not look like case here.
To download an arbitary file you need to open the file using a FileInputStream (and surround it by a buffered input stream), read a byte, then send that byte from your servlet to the client.
Then there are security concerns, so should google that (basically not give access to any file but only file that is to be shared, audit download etc as needed.
Again in your servlet set the mime type etc and then open a input stream and write the bytes to the output stream to client

Create a file object from a resource path to an image in a jar file

I need to create a File object out of a file path to an image that is contained in a jar file after creating a jar file. If tried using:
URL url = getClass().getResource("/resources/images/image.jpg");
File imageFile = new File(url.toURI());
but it doesn't work. Does anyone know of another way to do it?
To create a file on Android from a resource or raw file I do this:
try{
InputStream inputStream = getResources().openRawResource(R.raw.some_file);
File tempFile = File.createTempFile("pre", "suf");
copyFile(inputStream, new FileOutputStream(tempFile));
// Now some_file is tempFile .. do what you like
} catch (IOException e) {
throw new RuntimeException("Can't create temp file ", e);
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
Don't forget to close your streams etc
This should work.
String imgName = "/resources/images/image.jpg";
InputStream in = getClass().getResourceAsStream(imgName);
ImageIcon img = new ImageIcon(ImageIO.read(in));
Usually, you can't directly get a java.io.File object, since there is no physical file for an entry within a compressed archive. Either you live with a stream (which is best most in the cases, since every good API can work with streams) or you can create a temporary file:
URL imageResource = getClass().getResource("image.gif");
File imageFile = File.createTempFile(
FilenameUtils.getBaseName(imageResource.getFile()),
FilenameUtils.getExtension(imageResource.getFile()));
IOUtils.copy(imageResource.openStream(),
FileUtils.openOutputStream(imageFile));
You cannot create a File object to a reference inside an archive. If you absolutely need a File object, you will need to extract the file to a temporary location first. On the other hand, most good API's will also take an input stream instead, which you can get for a file in an archive.

Categories