I don't get it - I'm trying to get the path of a file so that the file (an image) can be included as an attachment in an email.
My system consists of two parts - a web app and a jar. (actually three parts - a common shared jar containing DAOs etc.)
They're both built using maven.
They both contain this image in this path:
src/main/resources/logo_48.png
WebApp:
String logo1 = getClass().getClassLoader().getResource("logo_48.png").getPath();
This works perfectly - both on local (Windows) and Linux
Jar Application:
String logo1 = getClass().getClassLoader().getResource("logo_48.png").getPath(); //doesn't work
I've taken advice from here:
How to access resources in JAR file?
here:
Reading a resource file from within jar
here:
http://www.coderanch.com/t/552720/java/java/access-text-file-JAR
and others
Most answers offer to load the file as a stream etc. but I'm only wishing to get the path assigned to the String. Other resources have led me to hacking the code for hours only to find the end result doesn't work.
After so many instances of /home/kalton/daily.jar!logo_48.png does not exist errors I was frustrated and settled on the following workaround:
Copy the logo_48.png directly to the folder where the jar resides (/home/kalton/)
Alter my jar application code to:
String logo1 = "/home/kalton/logo_48.png";
And it works.
Could anyone show me the right way to get the PATH (as a String) of a file in the resources folder from a JAR that is not unpacked?
This issue was driving me crazy for weeks!
Thanks in advance.
KA.
Adding actual use code of 'path' for clarity of use:
public static MimeMultipart assemble4SO(String logoTop, String emailHTMLText) throws MessagingException, IOException {
MimeMultipart content = new MimeMultipart("related");
String cid = Long.toString(System.currentTimeMillis());
String cidB = cid + "b";
String cssStyle = "";
String body = "<html><head>" + cssStyle + "</head><body><div>" + "<img src='cid:" + cid + "'/>" + emailHTMLText + "<img src='cid:" + cidB + "'/></div></body></html>";
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(body, "text/html; charset=utf-8");
content.addBodyPart(textPart);
//add an inline image
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.attachFile(logoTop);
imagePart.setContentID("<" + cid + ">");
imagePart.setDisposition(MimeBodyPart.INLINE);
content.addBodyPart(imagePart);
.............
From the top…
A .jar file is actually a zip file. A zip file is a single file that acts as an archive. The entries in this archive are not separate files, they're just sequences of compressed bytes within the zip file. They cannot be accessed as individual file names or File objects, ever.
Also important: The getPath method of the URL class does not convert a URL to a file name. It returns the path portion of the URL, which is just the part after the host (and before any query and/or fragment). Many characters are illegal in URLs, and need to be “escaped” using percent encoding, so if you just extract the path directly from a URL, you'll often end up with something containing percent-escapes, which therefore is not a valid file name at all.
Some examples:
String path = "C:\\Program Files";
URL url = new File(path).toURI().toURL();
System.out.println(url); // prints file:/C:/Program%20Files
System.out.println(url.getPath()); // prints /C:/Program%20Files
File file = new File(url.getPath());
System.out.println(file.exists()); // prints false, because
// "Program%20Files" ≠ "Program Files"
String path = "C:\\Users\\VGR\\Documents\\résumé.txt";
URL url = new File(path).toURI().toURL();
// Prints file:/C:/Users/VGR/Documents/r%C3%A9sum%C3%A9.txt
System.out.println(url);
// Prints /C:/Users/VGR/Documents/r%C3%A9sum%C3%A9.txt
System.out.println(url.getPath());
File file = new File(url.getPath());
System.out.println(file.exists()); // prints false, because
// "r%C3%A9sum%C3%A9.txt" ≠ "résumé.txt"
Based on your edit, I see that the real reason you want a String is so you can call MimeBodyPart.attachFile. You have two options:
Do the work of attachFile yourself:
URL logo = getClass().getLoader().getResource("logo_48.png");
imagePart.setDataHandler(new DataHandler(logo));
imagePart.setDisposition(Part.ATTACHMENT);
Copy the resource to a temporary file, then pass that file:
Path logoFile = Files.createTempFile("logo", ".png");
try (InputStream stream =
getClass().getLoader().getResourceAsStream("logo_48.png")) {
Files.copy(stream, logoFile, StandardCopyOption.REPLACE_EXISTING);
}
imagePart.attachFile(logoFile.toFile());
As you can see, the first option is easier. The second option also would require cleaning up your temporary file, but you don't want to do that until you've sent off your message, which probably requires making use of a TransportListener.
Related
My Java application requires access to a large excel file (1GB+ in size) saved on remote shared folder. I'm using SmbFile to get the file with authentication.
Note: Downloading of the file is not an option mainly for size reasons.
The problem is that I need the excel file to be a Java IO File and not SmbFile since the other libraries that I'm using to parse the excel only accepts Java IO File.
Is there any way to convert this SmbFile into a Java compatible File?
See implementation details of your library:
This library will take a provided InputStream and output it to the file system. (...) Once the file is created, it is then streamed into memory from the file system.
The reason for needing the stream being outputted in this manner has to do with how ZIP files work. Because the XLSX file format is basically a ZIP file, it's not possible to find all of the entries without reading the entire InputStream.
(...) This library works by reading out the stream into a temporary file. As part of the auto-close action, the temporary file is deleted.
If you need more control over how the file is created/disposed of, there is an option to initialize the library with a java.io.File. This file will not be written to or removed
So it doesn't matter if you use the File or InputStream API - the whole file will need to be downloaded anyhow.
The simplest solution is to pass the SmbFile.getInputStream() to
StreamingReader.builder().read(smbFile.getInputStream())
but alternatively you can first download the file eg. by means of IOUtils.copy() or Files.copy()
File file = new File("...");
try (
in = smbFile.getInputStream();
out = new FileOutputStream(file)
) {
IOUtils.copy(in, out);
}
or
try (in = smbFile.getInputStream()) {
Files.copy(smbFile.getInputStream(), file.toPath());
}
and pass file to
StreamingReader.builder().read(file)
Using Apache Commons IO library
https://mvnrepository.com/artifact/commons-io/commons-io
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", "user", "key");
SmbFile smbFile = new SmbFile("smb://IP/pitoka.tmp", auth)
InputStream initialStream = smbFile.getInputStream();
File targetFile = new File("/tmp/pitoka.tmp");
FileUtils.copyInputStreamToFile(initialStream, targetFile);
I hope help you.
jcifs.smb.SmbFile smbFile = new SmbFile("smb://host/fileShare/.../file");
java.io.File javaFile = new File(smbFile.getUncPath());
System.out.println(smbFile);
System.out.println(javaFile);
Output
smb://host/fileShare/.../file
\\host\fileShare\...\file
javadoc of smbFile.getUncPath() says
Retuns the Windows UNC style path with backslashs intead of forward
slashes.
I am using jcifs-1.3.17.jar on Windows 10.
Recently i had a similar situation, however, I hadn't found a good solution in the internet, but I wrote a basic code that did what I need easily.
In your case, you will need to copy the excel file from the source (Remote Directory) using SmbFile with authentication to the destination (Local Directory) and only after, convert the excel file path of the destination (getCanonicalPath() function) and convert it from SmbFile format to File format with the code below.
After, create your File object with the file destination path and do what you want.
I use JCIFS to work with remote shared directories using the SMBFILE class.
First, you need to import the main libraries:
import java.io.File;
import java.io.IOException;
import jcifs.smb.SmbFile;
Second, you need to create a static method to convert from SmbFile format to File format:
/**
* This method convert a directory path from SmbFile format to File format.<br />
* <p><strong>Sintax:</strong> <br /> convertSmbFileToFile("Canonical Path")</p>
* <p><strong>Example:</strong> <br /> convertSmbFileToFile("smb://localhost/D$/DOCUMENTOS/workspace/tests2/access")</p>
* #param smbFileCanonicalPath String
* #see String
*/
public static String convertSmbFileToFile(String smbFileCanonicalPath) {
String[] tempVar = smbFileCanonicalPath.substring(6).replace("$", ":").split("/");
String bar = "\\";
String finalDirectory = "";
for (int i = 1; i < tempVar.length; i++) {
finalDirectory += tempVar[i] + bar;
if (i == tempVar.length - 1) {
finalDirectory = finalDirectory.substring(0,finalDirectory.length()-1);
}
}
return finalDirectory;
}
Opcional, you could also create a static method to convert from File format to SmbFile format:
/**
* This method convert a directory path from File format to SmbFile format.<br />
* <p><strong>Sintax:</strong> <br /> convertFileToSmbFile("Canonical Path")</p>
* <p><strong>Example:</strong> <br /> convertFileToSmbFile("D:\DOCUMENTOS\workspace\tests2\access")</p>
* #param fileCanonicalPath String
* #see String
*/
public static String convertFileToSmbFile(String fileCanonicalPath) {
return "smb://localhost/" + fileCanonicalPath.toString().replace(":", "$").replace("\\", "/");
}
Finally, you can call the methods like the below example:
String dirDest = "access/";
try {
File localDirFile = new File(dirDest);
SmbFile localSmbDirFile = new SmbFile(convertFileToSmbFile(localDirFile.getCanonicalPath()));
File localDirFile2 = new File(convertSmbFileToFile(localSmbDirFile.getCanonicalPath()));
System.out.println("Original File Format: " + localDirFile.getCanonicalPath());
System.out.println("Original File Format to SmbFile Format: " + localSmbDirFile.getCanonicalPath());
System.out.println("Converted SmbFile Format to File Format: " + localDirFile2.getCanonicalPath());
} catch (IOException e) {
System.err.println("[ERR] IO Exception - " + e);
}
Result of previous code run:
Original File Format: D:\DOCUMENTOS\workspace\tests2\access
Original File Format to SmbFile Format: smb://localhost/D$/DOCUMENTOS/workspace/tests2/access
Converted SmbFile Format to File Format: D:\DOCUMENTOS\workspace\tests2\access
Extra Information: getCanonicalPath()
Maybe this code will help you and I am available to talk about if you want.
Good Luck!
It's just a matter of structure I guess, with SmbFile we have two arguments while with File we have just one argument.
So, my Idea is to declare a File with the same path of the SmbFile and try to handle your file.
For example, in my I want to delete recursively the content of my folder :
SmbFile sFile = new SmbFile(path, auth)
if (sFile.exists()) {
File file = new File(path);
deleteDirectory(file);
}
boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}
I hope this peace of code help you, and sorry for my english !
assuming that we have a folder with path:
path="C:\\Users\\me\\Desktop\\here"
also, consider a File[] named readFrom has different files. as an example, consider following path which refering to a file:
C:\\Users\\me\\Desktop\\files\\1\\sample.txt"
my question is, how can i have a string with following value:
String writeHere= "C:\\Users\\me\\Desktop\\here\\files\\1\\sample.txt"
EDIT
I should have mentioned that this path is unknown, we need first to read a file and get its path then write it into another folder, so for the path of writing I need writeHere as input. in conclusion , the answer should contains the way to get the path from the file too.
String s1="C:\\Users\\me\\Desktop\\here";
String s2="C:\\Users\\me\\Desktop\\files\\1\\sample.txt";
String s3=s2.substring(s2.indexOf("\\files"));
System.out.println(s1+s3);
OUTPUT
C:\Users\me\Desktop\here\files\1\sample.txt
To get Absolute Path of file
File f=new File("C:\\Users\\me\\Desktop\\files\\1\\sample.txt");
System.out.println(f.getAbsolutePath());
Split the into arrays and merge the path with split-ted string
String path="C:\\Users\\me\\Desktop\\here";
String [] splt = yourPath.split("\\");
finalPath = path + "\\" + splt[3] + "\\" + splt[4] + "\\" + splt[5];
yourPath is the path refering to a file
Changing the folder's path
File afile =new File("C:\\Users\\me\\Desktop\\files\\1\\sample.txt");
afile.renameTo(new File(finalPath))
If you just need the String and do not need to read the file, use string concatenation with is just str1 + str2. If you need the File object create a base File object on the initial path and then two new File objects from that:
File path = new File("C:\\Users\\me\\Desktop\\here");
String[] files = { "files\\1\\sample.txt", "files\\3\\this.avi" };
for (filename in files) {
File f = new File(path, filename);
...
}
Oh, I think I see better what you want to do. You want to "reparent" the files:
// Note:
// newParent I assume would be a parameter, not hardcoded
// If so, there is no hardcoding of the platform specific path delimiter
// the value, start, is also assumed to be a parameter
File newParent = new File("C:\\Users\\me\\Desktop\\here");
File[] readFrom = ...;
for (File f in readFrom) {
String[] parts = f.list();
String[] needed = Arrays.copyOfRange(parts, start, parts.length);
File newFile = new File(newParent);
for (String part in needed) {
newFile = new File(newFile, part);
}
...
}
I think you could do something like:
String name = "Rafael";
String lastname = " Nunes";
String fullname = name + lastname;
Here you can see the string concatenation working, and you can often visit the Java documentation.
How to pass multiple files to another class?
I am developing an application which first compresses the image and after that it'll convert it into pdf.
The program which i have written works well seperately ie; it compresses the image and then in another project i use the path where the image are stores to convert it to pdf.
Now i want to have both these codes in the same project and i am encountering the problem where i am creating a loop where i pass the path name one by one. The source path works well but i need to specify the destination path which changes the name dynamically this where i am facing the problem. I have attached the code below please tell me what to do.
System.out.println("before convert");
Conversion cc = new Conversion();
File directory = new File(Success);
File[] files = directory.listFiles();
if(files!=null)
{
for(File f:files){
String path = f.getName();
System.out.println("The Name of file is="+path);
cc.createPdf("path" , "output", true);
System.out.println("the file is ="+output+".pdf");
System.out.println("after convert");
}
}
In the above code i need to change the output file name dynamically here cc.createPdf("path" , "output", true);
A simple implementation would be to keep a counter outside loop and increment it before appending it to output file name
int counter = 0;
for(File f:files){
String path = f.getName();
System.out.println("The Name of file is="+path);
counter++; //increment the counter
cc.createPdf("path" , "output"+counter, true); // append it to output
System.out.println("the file is ="+output+".pdf");
System.out.println("after convert");
}
For more robustness, counter can be replaced by UUID generator, System time in milliseconds etc
Im guessing your having trouble getting a File object with a newly created .pdf extension, you will have to adapt this to your code but it should be pretty straight forward.
File inputFile = new File("c:\\myimage.png");
String fileName = inputFile.getName();
File pdfFile = new File(inputFile.getParent(), fileName.substring(0, fileName.indexOf(".")) +".pdf");
System.out.println(inputFile + " " + pdfFile);
I think you should keep things simple by just appending ".pdf" to the names. The fact that you are processing a directory ensures that the source file names are unique. Hence, the new ".pdf" names would also be unique.
Assuming your output files land in the same directory, it also becomes much easier to sort files by names and know immediately which ".pdf" files correlate to which source files.
So, your output file name simply becomes
String path = f.getName();
String output = path.substring(0, path.lastIndexOf('.')) + ".pdf";
In my Java Spring web app I am creating an image file. This file gets a temporary name and later on I try to rename it using:
public void rename(String productFilename){
String newProductFilename = "newfile.jpg";
File input = new File(imageDir + "/products/" + productFilename);
File output = new File(imageDir + "/products/" + newProductFilename);
Boolean checkRename = input.renameTo(output);
}
For creating the temp file, I'm using:
public String generate(){
String productFilename = "filename.jpg";
ImageIO.write(out, imageFileType, new File(imageDir + "/products/" + productFilename));
return productFilename;
}
the value of imageDir is: /var/images
Throughout the class, the imageDir variable is set to an absolute path. The strange thing is that this all works great on Windows, but when running on Linux, I get a FileNotFoundException.
I'm 100% sure that the file exists. Any clue on what I'm doing wrong?
I found the solution. The filenames needed to be trimmed to be recognised in Linux. This, however, worked without trimming in Windows.
I get the exception: "URI scheme is not file"
What I am doing is trying to get the name of a file and then save that file (from another server) onto my computer/server from within a servlet.
I have a String called "url", from thereon here is my code:
url = Streams.asString(stream); //gets the URL from a form on a webpage
System.out.println("This is the URL: "+url);
URI fileUri = new URI(url);
File fileFromUri = new File(fileUri);
onlyFile = fileFromUri.getName();
URL fileUrl = new URL(url);
InputStream imageStream = fileUrl.openStream();
String fileLoc2 = getServletContext().getRealPath("pics/"+onlyFile);
File newFolder = new File(getServletContext().getRealPath("pics"));
if(!newFolder.exists()){
newFolder.mkdir();
}
IOUtils.copy(imageStream, new FileOutputStream("pics/"+onlyFile));
}
The line causing the error is this one:
File fileFromUri = new File(fileUri);
I have added the rest of the code so you can see what I am trying to do.
The URI "scheme" is the thing that comes before the ":", for example "http" in "http://stackoverflow.com".
The error message is telling you that new File(fileUri) works only on "file:" URI's (ones referring to a pathname on the current system), not other schemes like "http".
Basically, the "file:" URI is another way of specifying a pathname to the File class. It is not a magic way of telling File to use http to fetch a file from the web.
Your assumption to create File from URL is wrong here.
You just don't need to create a File from URL to the file in the Internet, so that you get the file name.
You can simply do this with parsing the URL like that:
URL fileUri = new URL("http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/domefisheye/ladybug/fish4.jpg");
int startIndex = fileUri.toString().lastIndexOf('/');
String fileName = fileUri.toString().substring(startIndex + 1);
System.out.println(fileName);