Java: Can't read a file in my project directory? - java

I'm building a Vaadin(basically Java that compiles to html/javascript) project and am trying to import a template(basically a HTML file). For all intents and purposes thought, I'm just importing a file as an input stream. Here is the offending code:
File file = new File("C:/JavaProjects/VaadinSpikeWorkspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/CISTVaadinClient/VAADIN/themes/layoutsinteractionDetailsTabLayout.html");
InputStream is = null;
CustomLayout custom = null;
try {
is = new FileInputStream(file);
} catch (FileNotFoundException e1) {
System.out.println("mark 1");
e.printStackTrace();
}
try {
custom = new CustomLayout(is);
} catch (IOException e) {
System.out.println("mark 2");
e.printStackTrace();
}
What I'm doing:
Deploying the Vaadin project (basically a dynamic web project with a few extra .jars) to tomcat and accessing thVe aadin Project using my browser
What I'm seeing:
A blank screen in my browser
File not found exception (i.e "mark 1")
And as a result: IOException (i.e. "Mark 2")
What I've checked:
The file definitely does deploy to tomcat with the rest of the project
Outside of the webapps folder, the file i'm trying to import is available via the browser once deployed (i.e. Localhost/myProject/MyFile.html)
The Tomcat install is fine (It was a fresh install and works with this/other projects outside of this problem)
What I've tried
Using a relative URL, or just the name of the file (i.e. New File( "../webapps/vaadin/layouts/MyFile.html") )
Using the absolute Path to the Project directory
Using the absolute path to the deploy directory (as above)
Putting the file somewhere else (read: Every single possible location in the project)
Again, I'm trying to simply read the file, MyFile.html as an input stream. What am I doing wrong/ overlooking?
Thanks for your time.

I had no problems reading files when using VaadinService which points to WebContent directory (with META-INF, VAADIN and WEB-INF inside). If it's run in the test environment then VaadinService is not available, so I use such piece of code:
private static final String BASEDIR;
static {
if (VaadinService.getCurrent() != null) {
BASEDIR = VaadinService.getCurrent().getBaseDirectory().getAbsolutePath();
} else {
BASEDIR = "WebContent";
}
}
then to navigate to VAADIN folder just use
BASEDIR+="/VAADIN/restOfYourPath"

Just in order to make it more portable: have you thought about bringing your templates into your classpath? Something like
yourApp/WEB-INF/classes/templates/layoutsinteractionDetailsTabLayout.html
This way, you only need this line of code, assuming you are into a Servlet or Spring Controller or Struts 1/2 action or whatever called YourClass:
InputStream is = YourClass.class.getClassLoader().getResourceAsStream("templates/layoutsinteractionDetailsTabLayout.html");

If you are really trying to use this file as an HTML template, you'll be much better off to leverage Vaadin's support for this. They have a CustomLayout which loads an HTML template from your theme.
Your template would go into a folder like the following:
VAADIN/themes/mytheme/layout/layoutsinteractionDetailsTabLayout.html
Note that mytheme is the name of your theme and layout is a specially recognized Vaadin directory within themes.
Your custom component would then look like:
public class InteractionDetailsTabLayout extends CustomLayout {
private static final String TEMPLATE = "layoutsinteractionDetailsTabLayout";
public InteractionDetailsTabLayout() {
super(TEMPLATE);
}
}
Note that the super constructor argument excludes the directory and file suffix.
If you actually want to load a file in your webapp, don't bother with it in your VAADIN directory but instead put it in your classpath resources and access it with the ClassLoader.

Related

JavaFX:Editable Configuration Files After Packaging

I've a JavaFX application that I packaged it using antBuild to build a single installer .exe file, my app have some configuration files that was placed in the root of the project this way i load them from the root of the project in order to they can be place beside the .jar file and could be changable:
try {
File base = null;
try {
base = new File(MainApp.class.getProtectionDomain().getCodeSource().getLocation().toURI())
.getParentFile();
} catch (URISyntaxException e) {
System.exit(0);
}
try {
File configFile = new File(base, "config.properties");
}
so after packaging the app even if I put the files manually in the same place with jar file, again the app can not recognize them and put into error.
So what is the proper way to store and where to store some sort of config files and how to add them to the installer to put it to right place during installation?
If your application is bundled as a jar file, then MainApp.class.getProtectionDomain().getCodeSource().getLocation().toURI() will return a jar: scheme URI. The constructor for File taking a URI assumes it gets a file: scheme URI, which is why you are getting an error here. (Basically, if your application is bundled as a jar file, the resource config.properties is not a file at all, its an entry in an archive file.) There's basically no (reliable) way to update the contents of the jar file bundling the application.
The way I usually approach this is to bundle the default configuration file into the jar file, and to define a path on the user file system that is used to store the editable config file. Usually this will be relative to the user's home directory:
Path configLocation = Paths.get(System.getProperty("user.home"), ".applicationName", "config.properties");
or something similar.
Then at startup you can do:
if (! Files.exists(configLocation)) {
// create directory if needed
if (! Files.exists(configLocation.getParent())) {
Files.createDirectory(configLocation.getParent());
}
// extract default config from jar and copy to config location:
try (
BufferedReader in = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/config.properties")));
BufferedWriter out = Files.newBufferedWriter(configLocation);) {
in.lines().forEach(line -> {
out.append(line);
out.newLine();
});
} catch (IOException exc) {
// handle exception, e.g. log and warn user config could not be created
}
}
Properties config = new Properties();
try (BufferedReader in = Files.newBufferedReader(configLocation)) {
config.load(in);
} catch (IOException exc) {
// handle exception...
}
So this checks to see if the config file already exists. If not, it extracts the default config from the jar file and copies its content to the defined location. Then it loads the config from the defined location. Thus the first time the user runs the application, it uses the default configuration. After that, the user can edit the config file and subsequently it will use the edited version. You can of course create a UI to modify the contents if you like. One bonus of this is that if the user does something to make the config unreadable, they can simply delete it and the default will be used again.
Obviously this can be bullet-proofed against exceptions a little better (e.g. handle case where the directory is unwritable for some reason, make the config file location user-definable, etc) but that's the basic structure I use in these scenarios.

read/copy file inside dynamic web project in java

I create a dynamic web app project using JSP/Servlet with eclipse. And I want to create a copy of "db.xls" file in the same place.
I try to create a copy of the "db.xls", the copy will named out.xls but it won't. These files should be located inside the same folder "files". My code compile, db.xls is correctly read, but file out.xls is not created.
What's wrong with my method ? Please help !
public void readExcel()
{
try{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url1 = classLoader.getResource("");
// read db.xls
wbook = Workbook.getWorkbook(new File(url1.getPath()+"/db.xls"));
// create a copy of db.xls nammed out.xls
wwbCopy = Workbook.createWorkbook(new File(url1.getPath()+"/out.xls"), wbook);
shSheet = wwbCopy.getSheet(0);
}
catch(Exception e)
{
e.printStackTrace();
}
}
I move the file "db.xls" inside WEB-INF and use getServletContext().getRealPath("/WEB-INF") but the output file "out.xls" still not created.
public void readExcel()
{
try{
// ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// URL url1 = classLoader.getResource("");
String tomcatRoot = getServletContext().getRealPath("/WEB-INF");
wbook = Workbook.getWorkbook(new File(tomcatRoot+"/db.xls"));
wwbCopy = Workbook.createWorkbook(new File(tomcatRoot+"/out.xls"), wbook);
shSheet = wwbCopy.getSheet(0);
}
catch(Exception e)
{
e.printStackTrace();
}
}
System.out your files and you'll see what's wrong
System.out.println(new File(tomcatRoot+"/db.xls").getAbsolutePath());
System.out.println(new File(tomcatRoot+"/out.xls").getAbsolutePath());
You expect the file to be you project directory but it isnt read/writen from/to that location because you have set up the files forlder as source folder in eclipse, so it is part our yours assempbly and lands in the classpath where you can read from a resource, i.e. using classloader and getResource / getResourceAsStream but you cannot and should not write to it, for several resons, most obvious is that your web app might not be unpacked from a war files.
In fact, you dont know where you are reading/writing your files to/from.
You might package your file with the war file and read from it, this is correct. But for writing the best is to have an explicite location on the filesystem where you can write your output files. check this answer for how you could go abut it using context init parameter
check the WEB-INF/classes folder, it might be in there
I think your missing write and close statements.
Try:
wwbCopy.write();
wwbCopy.close();
In order to read files within a web application, the files need to be stored somewhere under the WEB-INF folder, otherwise they won't be deployed as part of the application.
Once you've moved the folders into there you can use the following method within a servlet:
String tomcatRoot = getServletContext().getRealPath("/");
This will give you the root of the web application. Then you must build the path (including the WEB-INF folder) from there:
String sourceFile = tomcatRoot + "/WEB-INF/folder/source.file"
String targetFile = tomcatRoot + "/WEB-INF/folder/target.file"
EDIT: I originally stated that getRealPath() would give you the WEB-INF location. It doesn't, it gives the parent folder.

how to access resources(Excel file) in jar file

Hi i have exported my java project as executable jar file. inside my project I am accessing a Excel file containing some data. Now I am not able to access the Excel file when I am trying to access the file.
My project structure is:
Java_Project_Folder
- src_Folder
- resources_Folder(Containing excel file)
I am accessing the excel file like
FileInputStream file=new FileInputStream(new File(System.getProperty("user.dir")
+File.separator+"resources"+File.separator+"Excel.xlsx"));
I have tried accessing this file using getResourceAsStream like:
FileInputStream file=(FileInputStream) this.getClass().getResourceAsStream
("/resources/Excel.xlsx");
But i am getting in is null exception. whats wrong can anyone help?
I bet you have no package called resources in your project.
Trying to use Class.#getResourceAsStream is the way to go. But this method does not return a FileInputStream. It returns an InputStream wich is an interface.
You should be passing the absolute name of the resource
InputStream is = getClass().getResourceAsStream("my/pack/age/Excel.xlsx");
where the excel file is located in the directory
resources/my/pack/age
The first step is to include the excel file itself in your project. You can create a resources folder like you show, but to make sure this gets included in your jar, you add the resources folder in along with your source code files so that it gets built into the jar.
Then
InputStream excelContent = this.getClass().getResourceAsStream("/resources/Excel.xlsx");
should work. From one post at least, the leading forward slash may also mess things up if you use the ClassLoader.
getClass().getResourceAsStream("/a/b/c.xml") ==> a/b/c.xml
getClass().getResourceAsStream("a/b/c.xml") ==> com/example/a/b/c.xml
getClass().getClassLoader().getResourceAsStream("a/b/c.xml") ==> a/b/c.xml
getClass().getClassLoader().getResourceAsStream("/a/b/c.xml") ==> Incorrect
ref: getResourceAsStream fails under new environment?
Also in eclipse you can set the resources folder as a source folder like this:
in the properties of your eclipse project, go to java build path, select sources, and check to see if all needed source fodlers are added (as source folders). If some are missing, just add them manually using add sources... button
ref: Java Resources Folder Error In Eclipse
I tried this and it is working for me.
My Test1 class is in default package, just check where your accessing class is in any package, if it is then go back to exact resource folder from classpath like this "../"
public class Test1 {
public static void main(String[] args) {
new Test1();
}
Test1(){
BufferedInputStream file= (BufferedInputStream) this.getClass().getResourceAsStream("resources/a.txt");
try {
System.out.println((char)file.read());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
FileInputStream file= (FileInputStream)
this.getClass().getResourceAsStream("/resources/Excel.xlsx");
Why do you need FileInputStream? Use
InputStream is = getClass().getResourceAsStream..
Secondly use "resources/Excel.xlsx"
Thirdly when constructing file like this
new
File(System.getProperty("user.dir")+File.separator+"resources"+File.separator+"Excel.xlsx"));
is hard to control slashes. use
new File("parent (userdir property)", "child (resources\Excel.xlsx)")

How do I reference a file that is placed in the WEB-INF folder when using Arquillian?

I am using maven and the standard directory layout. So I have added a testdata.xml file in the src/test/resources folder, and I also added it as:
.addAsWebInfResource("testdata.xml", "testdata.xml")
in the deployment method, and I have confirmed that it is there. This will make the file appear in /WEB-INF/testdata.xml. Now I need to have a reference to this file in my code and I tried several different getClass().getResourceAsStream(...) and failing again and again so I need some advise now.
I need it for my DBUnit integration test. Is this not possible?
Option A) Use ServletContext.getResourceXXX()
You should have a Aquillarian MockHttpSession and a MockServletContext. E.g.:
#Test
public void myTest()
{
HttpSession session = new MockHttpSession(new MockServletContext());
ServletLifecycle.beginSession(session);
..testCode..
// You can obtain a ServletContext (will actually be a MockServletContext
// implementation):
ServletContext sc = session.getServletContext();
URL url = sc.getResource("/WEB-INF/testdata.xml")
Path resPath = new Path(url);
File resFile = new File(url);
FileReader resRdr = new FileReader(resFile);
etc...
..testCode..
ServletLifecycle.endSession(session);
}
You can create resource files & subdirectories in:
the web module document root - resources are accessible from the browser and from classes
WEB-INF/classes/ - resources are accessible to classes
WEB-INF/lib/*.jar source jar - accessible to classes
WEB-INF/lib/*.jar dedicated resource-only jar - accessible to classes
WEB-INF/ directly within directory - accessible to classes. This is what you are asking for.
In all cases the resource can be accessed via:
URL url = sc.getResource("/<path from web doc root>/<resourceFileName>");
OR
InputStream resIS = sc.getResourceAsStream("/<path from web doc root>/<resourceFileName>");
>
These will be packaged into the WAR file and may be exploded into directories on the deployed app server OR they may stay within the WAR file on the app server. Either way - same behaviour for accessing resources: use ServletContext.getResourceXXX().
Note that as a general principle, (5) the top-level WEB-INF directory itself is intended for use by the server. It is 'polite' not to put your web resources directly in here or create your own directory directly in here. Instead, better to use (2) above.
JEE5 tutorial web modules
JEE6 tutorial web modules
Option B): Use Class.getResourceXXX()
First move the resource out of WEB-INF folder into WEB-INF/classes (or inside a jar WEB-INF/lib/*.jar).
If your test class is:
com.abc.pkg.test.MyTest in file WEB-INF/classes/com/abc/pkg/test/MyTest.class
And your resource file is
WEB-INF/classes/com/abc/pkg/test/resources/testdata.xml (or equivalent in a jar file)
Access File using Relative File Location, via the Java ClassLoader - finds Folders/Jars relative to Classpath:
java.net.URL resFileURL = MyTest.class.getResource("resources/testdata.xml");
File resFile = new File(fileURL);
OR
InputStream resFileIS =
MyTedy.class.getResourceAsStream("resources/testdata.xml");
Access File Using full Package-like Qualification, Using the Java ClassLoader - finds Folders/Jars relative to Classpath:
java.net.URL resFileURL = MyTest.class.getResource("/com/abc/pkg/test/resources/testdata.xml");
File resFile = new File(fileURL);
OR
InputStream resFileIS =
MyTest.class.getResourceAsStream("/com/abc/pkg/test/resources/testdata.xml");
OR
java.net.URL resFileURL = MyTest.class.getClassLoader().getResource("com/abc/pkg/test/resources/testdata.xml");
File resFile = new File(fileURL);
OR
InputStream resFileIS =
MyTest.class.getClassLoader().getResourceAsStream("com/abc/pkg/test/resources/testdata.xml");
Hope that nails it! #B)
The way to access files under WEB-INF is via three methods of ServletContext:
getResource("/WEB-INF/testdata.xml") gives you a URL
getResourceAsStream gives you an input stream
getRealPath gives you the path on disk of the relevant file.
The first two should always work, the third may fail if there is no direct correspondence between resource paths and files on disk, for example if your web application is being run directly from a WAR file rather than an unpacked directory structure.
Today I was struggling with the same requirement and haven't found any full source sample, so here I go with smallest self contained test I could put together:
#RunWith(Arquillian.class)
public class AttachResourceTest {
#Deployment
public static WebArchive createDeployment() {
WebArchive archive = ShrinkWrap.create(WebArchive.class).addPackages(true, "org.apache.commons.io")
.addAsWebInfResource("hello-kitty.png", "classes/hello-kitty.png");
System.out.println(archive.toString(true));
return archive;
}
#Test
public void attachCatTest() {
InputStream stream = getClass().getResourceAsStream("/hello-kitty.png");
byte[] bytes = null;
try {
bytes = IOUtils.toByteArray(stream);
} catch (IOException e) {
e.printStackTrace();
}
Assert.assertNotNull(bytes);
}
}
In your project hello-kitty.png file goes to src/test/resources. In the test archive it is packed into the /WEB-INF/classes folder which is on classpath and therefore you can load it with the same class loader the container used for your test scenario.
IOUtils is from apache commons-io.
Additional Note:
One thing that got me to scratch my head was related to spaces in path to my server and the way getResourceAsStream() escapes such special characters: sysLoader.getResource() problem in java
Add this class to your project:
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
public class Init {
private static final String WEB_INF_DIR_NAME="WEB-INF";
private static String web_inf_path;
public static String getWebInfPath() throws UnsupportedEncodingException {
if (web_inf_path == null) {
web_inf_path = URLDecoder.decode(Init.class.getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF8");
web_inf_path=web_inf_path.substring(0,web_inf_path.lastIndexOf(WEB_INF_DIR_NAME)+WEB_INF_DIR_NAME.length());
}
return web_inf_path;
}
}
Now wherever you want to get the full path of the file "testdata.xml" use this or similar code:
String testdata_file_location = Init.getWebInfPath() + "/testdata.xml";

Locating default root folder for an Eclipse project

I am reading a file as follows:
File imgLoc = new File("Player.gif");
BufferedImage image = null;
try {
image = ImageIO.read(imgLoc);
}
catch(Exception ex)
{
System.out.println("Image read error");
System.exit(1);
}
return image;
I do not know where to place my file to make the Eclipse IDE, and my project can detect it when I run my code.
Is there a better way of creating a BufferedImage from an image file stored in your project directory?
Take a look in the comments for Class.getResource and Class.getResourceAsStream. These are probably what you really want to use as they will work whether you are running from within the directory of an Eclipse project, or from a JAR file after you package everything up.
You use them along the lines of:
InputStream in = MyClass.class.getResourceAsStream("Player.gif");
In this case, Java would look for the file "Player.gif" next to the MyClass.class file. That is, if the full package/class name is "com.package.MyClass", then Java will look for a file in "[project]/bin/com/package/Player.gif". The comments for getResourceAsStream indicate that if you lead with a slash, i.e. "/Player.gif", then it'll look in the root (i.e. the "bin" directory).
Note that you can drop the file in the "src" directory and Eclipse will automatically copy it to the "bin" directory at build time.
In the run dialog you can choose the directory. The default is the project root.
From my experience it seems to be the containing projects directory by default, but there is a simple way to find out:
System.out.println(new File(".").getAbsolutePath());
Are you trying to write a plugin for Eclipse or is it a regular project?
In the latter case, wouldn't that depend on where the program is installed and executed in the end?
While trying it out and running it from Eclipse, I'd guess that it would find the file in the project workspace. You should be able to find that out by opening the properties dialog for the project, and looking under the Resource entry.
Also, you can add resources to a project by using the Import menu option.
The default root folder for any Eclipse project is also a relative path of that application.
Below are steps I used for my Eclipse 4.8.0 and Java 1.8 project.
I - Place your file you want to interact with along the BIN and SRS folders of your project and not in one of those folders.
II - Implement below code in your main() method.
public static void main(String [] args) throws IOException {
FileReader myFileReader;
BufferedReader myReaderHelper;
try {
String localDir = System.getProperty("user.dir");
myFileReader = new FileReader(localDir + "\\yourFile.fileExtension");
myReaderHelper = new BufferedReader(myFileReader);
if (myReaderHelper.readLine() != null) {
StringTokenizer myTokens =
new StringTokenizer((String)myReaderHelper.readLine(), "," );
System.out.println(myTokens.nextToken().toString()); // - reading first item
}
} catch (FileNotFoundException myFileException) {
myFileException.printStackTrace(); } } // End of main()
III - Implement a loop to iterate through elements of your file if your logic requires this.

Categories