How to get absolute path with proper character encoding in Java? - java

I'd like to get the absolute path of a file, so that I can use it further to locate this file. I do it the following way:
File file = new File(Swagger2MarkupConverterTest.class.getResource(
"/json/swagger.json").getFile());
String tempPath = file.getAbsolutePath();
String path = tempPath.replace("\\", "\\\\");
The path irl looks like this:
C:\\Users\\Michał Szydłowski\\workspace2\\swagger2markup\\bin\\json\\swagger.json
However, since it contains Polish characters and spaces, what I get from getAbsolutPath is:
C:\\Users\\Micha%c5%82%20Szyd%c5%82owski\\workspace2\\swagger2markup\\bin\\json\\swagger.json
How can I get it to do it the right way? This is problematic, because with this path, it cannot locate the file (says it doesn't exist).

The URL.getFile call you are using returns the file part of a URL encoded according to the URL encoding rules. You need to decode the string using URLDecoder before giving it to File:
String path = Swagger2MarkupConverterTest.class.getResource(
"/json/swagger.json").getFile();
path = URLDecoder.decode(path, "UTF-8");
File file = new File(path);
From Java 7 onwards you can use StandardCharsets.UTF_8
path = URLDecoder.decode(path, StandardCharsets.UTF_8);

The simplest way, that doesn't involve decoding anything, is this:
URL resource = YourClass.class.getResource("abc");
Paths.get(resource.toURI()).toFile();
// or, equivalently:
new File(resource.toURI());
It doesn't matter now where the file in the classpath physically is, it will be found as long as the resource is actually a file and not a JAR entry.

URI uri = new File(Swagger2MarkupConverterTest.class.getResource(
"/json/swagger.json").getFile()).toURI();
File f = new File(uri);
System.out.println(f.exists());
You can use URI to encode your path, and open File by URI.

You can use simply
File file = new File("file_path");
String charset = "UTF-8";
BufferedReader reader = new BufferedReader(new InputStreamReader(
new FileInputStream(file), charset));
give the charset at the time of read the file.

Related

FileNotFoundException exception when reading from a HTML resource

I try to open and read an HTML file from within class path.
Please find the directory structure in screenshot below
Inside class SendEmail class I want to read that verification.html file.
Code
When using the code below, it is throwing me a java.io.FileNotFoundException exception here:
emailContent = readHTMLFile("../emailTemplate/EmailVerificationTemplate/verification.html");
The readHTMLFile method looks like this:
public String readHTMLFile(String path) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
However, when I use an absolute path everything is working fine.
I am very new to Java world.
Please help me to fix this 🙏🏻.
verification.html looks rather like a "class path resource" than a file...
(A file is very environment dependent (e.g. thinking of its path/location), whereas a "CPR" we package & supply with our application & can refer to it with a known&fixed (absolute or relative) (class path) address.
Nor maven nor gradle (by default) "includes" anything else from src/main/java than *.java files. So please move the according files (including structure/packages) to src/main/resources (or src/test/... accordingly).
When the resource is finally in classpath, since spring:3.2.2, we can do that:
String emailBody = org.springframework.util.StreamUtils.
copyToString(
new org.springframework.core.io.ClassPathResource(
"/full/package/of/emailTemplate/EmailVerificationTemplate/verification.html")
.getInputStream(),
/* you must know(!), better: */
Charset.forName("UTF-8")
);
(..also outside/before spring-boot-application.)
In spring context, the Resource (Classpath-, ServletContext-, File(!)-, URL-, ...) can also be "injected", like:
#Value("classpath:/full/package/...")Resource verificationEmailBody
..instead of calling the constructor.
See also:
Spring Core#Resources reference doc
Resource javadoc
How do I read / convert an InputStream into a String in Java?
How do I load a resource and use its contents as a string in Spring
When you need to refer to verification.html as a File, then please ensure:
It has a distinct (absolute (ok!) or relative (good luck!)) address (in all target environments)!
Files and resources in Java
Your file is located inside the classpath. This is a special location within your source-code (here in package utils.emailTemplate.EmailVerificationTemplate). So we call it a classpath resource or simply resource.
Classpath resources
Usually those resources are destined to be published with your code, although they are actually not code.
In the Maven standard directory layout you would put them inside the special src/main/resources folder, separated from code.
Locating and reading resources
Resources are located relative from classpath using the classpath: schema. Since they are part of the sources, package-tree you can also locate them relative to one of your classes.
From your SendEmail class, the given template has relative path ../. So you can instantiate it as Resource building the URL using this.getClass().getResource(Stirng relativePath) from within your SendEmail class:
class SendEmail {
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
// build the URL for the resource relative from within your class
public URL getVerificaitonEmailTemplateUrl() {
URL templateResourceUrl = this.getClass().getResource(relativePath);
return templateResourceUrl;
}
// load the resource
public InputStream getVerificaitonEmailTemplateStream() {
InputStream is = this.getClass().getResourceAsStream(relativePath);
return is;
}
}
Load a resource as input-stream getResourceAsStream(String name)
using the relative path from inside your class.
Alternative using Spring's special-purpose extension ClassPathResource:
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
public String loadContentAsFile() {
ClassPathResource resource = new ClassPathResource(relativePath);
File file resource.getFile();
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
public InputStream getContentAsStream() {
ClassPathResource resource = new ClassPathResource(relativePath);
InputStream is resource.getInputStream();
return is;
}
Attention: This reading from a file works only if your resource is inside the file system. Not if your resource is inside a JAR:
This implementation returns a File reference for the underlying class path resource, provided that it refers to a file in the file system.
A safer and more robust way to read from the ClassPathResource is resource.getInputStream().
From InputStream to String
To fix your method, you could simply exchange the File related parts to InputStream:
public String readHTML(InputStream is) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
Or even simpler (see Baeldung's tutorial linked below):
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8)) // choose the encoding to fit
.lines()
.collect(Collectors.joining("\n"));
Then re-use it to read from any stream (e.g. a File, a Resource, ClassPathResource, even a URL). For example:
public String loadTemplate(String relativeResourcePath) throws IOException {
InputStream inputStream = this.getClass().getResourceAsStream(relativeResourcePath)
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
return text;
}
See also
Baeldung: Access a File from the Classpath using SpringBaeldung
Baeldung: Java InputStream to String

Resource File Path as String (not streaming)

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.

Loading file from resource gives a wrong path [duplicate]

This question already has answers here:
How to get a path to a resource in a Java JAR file
(17 answers)
Closed 7 years ago.
I have a propeties file with a path to a file inside my jar
logo.cgp=images/cgp-logo.jpg
This file already exists:
I want to load this file within my project so I do this:
String property = p.getProperty("logo.cgp"); //This returns "images/cgp-logo.jpg"
File file = new File(getClass().getClassLoader().getResource(property).getFile());
But then when I do file.exists() I get false. When I check file.getAbsolutePath() it leads to C:\\images\\cgp-logo.jpg
What am I doing wrong?
Well a file inside a jar is simply not a regular file. It is a resource that can be loaded by a ClassLoader and read as a stream but not a file.
According to the Javadocs, getClass().getClassLoader().getResource(property) returns an URL and getFile() on an URL says :
Gets the file name of this URL. The returned file portion will be the same as getPath(), plus the concatenation of the value of getQuery(), if any. If there is no query portion, this method and getPath() will return identical results.
So for a jar resource it is the same as getPath() that returns :
the path part of this URL, or an empty string if one does not exist
So here you get back /images/cgp-logo.jpg relative to the classpath that does not correspond to a real file on your file system. That also explains the return value of file.getAbsolutePath()
The correct way to get access to a resource is:
InputStream istream = getClass().getClassLoader().getResourceAsStream(property)
You can use the JarFile class like this:
JarFile jar = new JarFile("foo.jar");
String file = "file.txt";
JarEntry entry = jar.getEntry(file);
InputStream input = jar.getInputStream(entry);
OutputStream output = new FileOutputStream(file);
try {
byte[] buffer = new byte[input.available()];
for (int i = 0; i != -1; i = input.read(buffer)) {
output.write(buffer, 0, i);
}
} finally {
jar.close();
input.close();
output.close();
}

Where to put a file to read from a class under a package in java?

I have a properties file contains the file name only say file=fileName.dat. I've put the properties file under the class path and could read the file name(file.dat) properly from it in the mainClass. After reading the file name I passed the file name(just name not the path) to another class under a package say pack.myClass to read that file. But the problem is pack.myClass could not get the file path properly. I've put the file fileName.dat both inside and outside the packagepack but couldn't make it work.
Can anybody suggest me that where to put the file fileName.dat so I can read it properly and the whole application would be portable too.
Thanks!
The code I'm using to read the config file and getting the file name:
Properties prop = new Properties();
InputStream in = mainClass.class.getResourceAsStream("config.properties");
prop.load(in);
in.close();
myClass mc = new myClass();
mc.readTheFile(prop.getProperty("file"));
/*until this code is working good*/
Then in myClass which is under package named pack I am doing:
public void readTheFile(String filename) throws IOException {
FileReader fileReader = new FileReader(filename); /*this couldn't get the file whether i'm putting the file inside or outside the package folder */
/*after reading the file I've to do the BufferReader for further operation*/
BufferedReader bufferedReader = new BufferedReader(fileReader);
I assume that you are trying to read properties file using getResource method of class. If you put properties file on root of the classpath you should prefix file name with '/' to indicate root of classpath, for example getResource("/file.dat"). If properties file is under the same folder with the class you on which you invoke getResource method, than you should not use '/' prefix.
When you use a relative file name such as fileName.dat, you're asking for a file with this name in the current directory. The current directory has nothing to do with packages. It's the directory from which the JVM is started.
So if you're in the directory c:\foo\bar when you launch your application (using java -cp ... pack.MyClass), it will look for the file c:\foo\bar\fileName.dat.
Try..
myClass mc = new myClass();
InputStream in = mc.getClass().getResourceAsStream("/pack/config.properties");
..or simply
InputStream in = mc.getClass().getResourceAsStream("config.properties");
..for the last line if the main is in myClass The class loader available in the main() will often be the bootstrap class-loader, as opposed to the class-loader intended for application resources.
Class.getResource will look in your package directory for a file of the specified name.
JavaDocs here
Or getResourceAsStream is sometimes more convenient as you probably want to read the contents of the resource.
Most of the time it would be best to look for the "fileName.dat" somewhere in the "user.home" folder, which is a system property. First create a File path from the "user.home" and then try to find the file there. This is a bit of a guess as you don't provide the exact user of the application, but this would be the most common place.
You are currently reading from the current folder which is determined by
String currentDir = new File(".").getAbsolutePath();
or
System.getProperty("user.dir")
To read a file, even from within a jar archive:
readTheFile(String package, String filename) throws MalformedURLException, IOException
{
String filepath = package+"/"+filename;
// like "pack/fileName.dat" or "fileName.dat"
String s = (new SourceBase()).getSourceBase() + filepath;
URL url = new URL(s);
InputStream ins = url.openStream();
BufferedReader rdr = new BufferedReader(new InputStreamReader(ins, "utf8"));
do {
s = rdr.readLine();
if(s!= null) System.out.println(s);
}
while(s!=null);
rdr.close();
}
with
class SourceBase
{
public String getSourceBase()
{
String cn = this.getClass().getName().replace('.', '/') + ".class";
// like "packagex/SourceBase.class"
String s = this.getClass().getResource('/' + cn).toExternalForm();
// like "file:/javadir/Projects/projectX/build/classes/packagex/SourceBase.class"
// or "jar:file:/opt/java/PROJECTS/testProject/dist/
// testProject.jar!/px/SourceBase.class"
return s.substring(0, s.lastIndexOf(cn));
// like "file:/javadir/Projects/projectX/build/classes/"
// or "jar:file:/opt/java/PROJECTS/testProject/dist/testProject.jar!/"
}
}

URI scheme is not "file"

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);

Categories