I am not all that knowledgeable in Java, and I'm trying to use some Java in a Processing.org 3 project. I have managed to reconstruct the problem in a small Processing example project called testprocjavapath - and I am posting a bash script (called testProcJavaLoadpath.sh) that reconstructs the example project files at the end of this post, and runs the project once. The testprocjavapath project files look like this:
~/sketchbook/testprocjavapath
├── testprocjavapath.pde
├── myprops.properties
└── MyJavaClass.java
When running the script, I get this:
$ bash testProcJavaLoadpath.sh
...
There was an exception myprops.properties: java.lang.NullPointerException : null
The properties file content is 'null';
Finished.
Debugging in Processing 3 IDE GUI, this error occurs on exactly the line properties.load(in);:
... because the line InputStream in = MyJavaClass.class.getResourceAsStream(inFileName); failed, and as a result, in is a null pointer.
That much I understand - what I don't understand is this: how do I load a, say, .properties text file, in the same directory as the .pde Processing sketch file and the .java file (that is, this particular sketch folder)?
As far as I gather the Java getResourceAsStream() actually is used to load from a Java application packed as a .jar file - so can it work for reading files from hard disk, that are not yet packed as .jar files?
If not - I have also tried to do:
InputStream in = new FileInputStream( new File(PROPERTIES_FILENAME));
... but this didn't work either (in is again null).
So, what command can I use in the .java file, to load the myprops.properties file? And if I should end up packing the whole Processing app as a .jar file (not sure if Processing can do this, haven't looked it up yet), would I have to change that command?
Here is the testProcJavaLoadpath.sh file (make sure you change PROCBINPATH to your Processing install path):
PROCSKETCHDIR="~/sketchbook"
PROCSKETCHDIR="${PROCSKETCHDIR/#\~/$HOME}" # expand home dir ~
echo "$PROCSKETCHDIR"
PROCBINPATH="/PATH/TO/processing-3.3.6" # path/location of Processing executable `processing-java`
MYSKETCH="testprocjavapath"
MYSKETCHDIR="$PROCSKETCHDIR/$MYSKETCH"
# reconstruct folder:
rm -rfv "$MYSKETCHDIR"
mkdir -v "$MYSKETCHDIR"
echo "generating $MYSKETCHDIR/$MYSKETCH.pde"
cat > "$MYSKETCHDIR/$MYSKETCH.pde" <<'EOF'
void setup() {
size(640, 360); // Size should be the first statement
MyJavaClass myjc = new MyJavaClass();
String thefilecontents = myjc.GetPropsFileContent();
System.out.format("The properties file content is '%s';%n", thefilecontents);
}
EOF
echo "generating $MYSKETCHDIR/myprops.properties"
cat > "$MYSKETCHDIR/myprops.properties" <<'EOF'
teststr=HelloWorld
EOF
echo "generating $MYSKETCHDIR/MyJavaClass.java"
cat > "$MYSKETCHDIR/MyJavaClass.java" <<'EOF'
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.io.FileInputStream;
import java.io.File;
import java.io.ByteArrayOutputStream;
public class MyJavaClass {
private static final String PROPERTIES_FILENAME = "myprops.properties";
/**
* add a constructor
*/
public static void MyJavaClass() {
}
public static String GetPropsFileContent() {
String myret = null;
myret = readgetFileContent(PROPERTIES_FILENAME);
return myret;
}
public static String readgetFileContent(String inFileName) {
String result = null;
Properties properties = new Properties();
try {
InputStream in = MyJavaClass.class.getResourceAsStream(inFileName);
properties.load(in);
ByteArrayOutputStream resultbaos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) != -1) {
resultbaos.write(buffer, 0, length);
}
result = resultbaos.toString();
} catch (IOException e) {
System.err.println("There was an error reading " + inFileName + ": " + e.getCause()
+ " : " + e.getMessage());
} catch (Exception e) {
System.err.println("There was an exception " + inFileName + ": " + e
+ " : " + e.getMessage());
}
return result;
}
}
EOF
# run once:
"$PROCBINPATH"/processing-java --sketch="$MYSKETCHDIR" --run
Ok, I managed to get somewhere - but I'd still like a more qualified answer.
First of all, it turns out, Processing as such expect files to be read (like myprops.properties in the OP example), to be stored in a data subfolder of the sketch folder:
https://processing.org/tutorials/data/
And just as with image files, these text files should be placed in the sketch’s “data” directory in order for them to be recognized by the Processing sketch.
So far so good - and indeed, inside the Processing .pde sketch, we can use (say) loadStrings("myprops.properties");, and the file at data/myprops.properties will be read. However, I don't need to read the file there - I need to read it in the supporting .java class.
Now, when you run the Processing patch (either from IDE, or from the command line), what happens is that Processing copies the source files from the sketch folder, inside a temporary folder in the /tmp folder (at least on Linux); here's how that file structure looks like:
/tmp/testprocjavapath9179591342074530534temp/
├── MyJavaClass.class
├── source
│ ├── MyJavaClass.java
│ └── testprocjavapath.java
└── testprocjavapath.class
Notice that we have .java source files, and .class "compiled" files, but there is no data subfolder or myprops.properties file anywhere!
Now, notice also that what used to be testprocjavapath.pde in the source sketch folder, becomes testprocjavapath.java (and corresponding .class) in the temporary folder; notice that testprocjavapath.java defines:
public class testprocjavapath extends PApplet {
Now, the loadStrings is actually a method of the PApplet class; so if we read through it a bit:
https://github.com/processing/processing/blob/master/core/src/processing/core/PApplet.java
dataPath(String where): .... The data path is handled differently on each platform, and should not be considered a location to write files. It should also not be assumed that this location can be read from or listed. ... Libraries should use createInput() to get an InputStream or createOutput() to get an OutputStream. sketchPath() can be used to get a location relative to the sketch. Again, do not use this to get relative locations of files. ...
... we can see a method dataPath, however it's usage is not recommended. On the other hand, there is a method sketchPath - however, this method will only return the correct path (i.e. a sketch in ~/sketchbook in this example) if called from the top-level .pde file! If you try to have the class in the .java file defined as extends PApplet, and then call sketchPath from there - it will simply return the current working directory!
So the solution for now is:
Have the .java class accept an input argument in the constructor, which will be used to record the proper sketch path: public MyJavaClass(String inSketchPath) {
Then, have the sketchPath() passed to the .java class instance during instantiation in the .pde file: MyJavaClass myjc = new MyJavaClass( sketchPath() );
Finally, use the passed sketch path inside the .java class, to calculate the absolute path of the .properties file, and then load it with new FileInputStream( new File(theFilePath) ); (not with getResourceAsStream!)
Below a changed testProcJavaLoadpath.sh is pasted, that has these modifications, and in principle, works - this is the terminal output:
$ bash testProcJavaLoadpath.sh
...
Sketch first lines: 'teststr=HelloWorld';
Sketch dataFile: '~/sketchbook/testprocjavapath/data/myprops.properties';
Sketch sketchPath: '~/sketchbook/testprocjavapath';
:: mySketchPath: '~/sketchbook/testprocjavapath'
:: The URL is 'file:/tmp/testprocjavapath4709659129218148940temp/';
:: name: MyJavaClass.class
:: resourcePath: file:/tmp/testprocjavapath4709659129218148940temp/MyJavaClass.class
:: theFilePath: '~/sketchbook/testprocjavapath/data/myprops.properties'
:: properties: key 'teststr' => value 'HelloWorld'
The properties file content is 'teststr=HelloWorld
';
... however, I imagine if I should want to pack this code in a .jar or executable application/file, this approach would likely fail - which is why I'd still like a more qualified answer.
The changed testProcJavaLoadpath.sh is this:
PROCSKETCHDIR="~/sketchbook"
PROCSKETCHDIR="${PROCSKETCHDIR/#\~/$HOME}" # expand home dir ~
echo "$PROCSKETCHDIR"
PROCBINPATH="/PATH/TO/processing-3.3.6" # path/location of Processing executable `processing-java`
MYSKETCH="testprocjavapath"
MYSKETCHDIR="$PROCSKETCHDIR/$MYSKETCH"
# reconstruct folder:
rm -rfv "$MYSKETCHDIR"
mkdir -v "$MYSKETCHDIR"
# https://processing.org/tutorials/data/
# "And just as with image files, these text files should be placed in the sketch’s “data” directory in order for them to be recognized by the Processing sketch."
# processing.core.PApplet.loadStrings - https://processing.github.io/processing-javadocs/core/
# https://github.com/processing/processing/blob/master/core/src/processing/core/PApplet.java
# "dataPath(String where): The data path is handled differently on each platform, and should not be considered a location to write files. It should also not be assumed that this location can be read from or listed. ... Libraries should use createInput() to get an InputStream or createOutput() to get an OutputStream. sketchPath() can be used to get a location relative to the sketch. Again, <b>do not</b> use this to get relative locations of files."
echo "generating $MYSKETCHDIR/$MYSKETCH.pde"
cat > "$MYSKETCHDIR/$MYSKETCH.pde" <<'EOF'
void setup() {
size(640, 360); // Size should be the first statement
String[] lines = loadStrings("myprops.properties"); // reads from data/myprops.properties
System.out.format("Sketch first lines: '%s';%n", lines[0]);
System.out.format("Sketch dataFile: '%s';%n", dataFile("myprops.properties")); // ~/sketchbook/testprocjavapath/data/myprops.properties
System.out.format("Sketch sketchPath: '%s';%n", sketchPath()); // ~/sketchbook/testprocjavapath
MyJavaClass myjc = new MyJavaClass( sketchPath() );
String thefilecontents = myjc.GetPropsFileContent();
System.out.format("The properties file content is '%s';%n", thefilecontents);
}
EOF
mkdir -v "$MYSKETCHDIR/data"
echo "generating $MYSKETCHDIR/data/myprops.properties"
cat > "$MYSKETCHDIR/data/myprops.properties" <<'EOF'
teststr=HelloWorld
EOF
echo "generating $MYSKETCHDIR/MyJavaClass.java"
cat > "$MYSKETCHDIR/MyJavaClass.java" <<'EOF'
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream; // "InputStream is by definition not seekable."
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.io.FileInputStream; // is seekable
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.net.URL;
//import processing.core.*;
import java.nio.file.Path;
import java.nio.file.Paths;
public class MyJavaClass {
private static final String PROPERTIES_FILENAME = "myprops.properties";
public String mySketchPath;
/**
* add a constructor
*/
public MyJavaClass(String inSketchPath) {
mySketchPath = inSketchPath;
}
public String GetPropsFileContent() {
//System.out.format(":: sketchPath: '%s'%n", sketchPath()); // if `MyJavaClass extends PApplet`, then sketchPath() just prints current working directory!
System.out.format(":: mySketchPath: '%s'%n", mySketchPath);
getLocations();
String myret = null;
myret = readgetFileContent(PROPERTIES_FILENAME);
return myret;
}
public String readgetFileContent(String inFileName) {
String result = null;
Properties properties = new Properties();
try {
//String theFilePath = inFileName; // verbatim relative path fails
Path inFileNameSketchPath = Paths.get(mySketchPath, "data", inFileName); // OS path join
String theFilePath = inFileNameSketchPath.toString();
System.out.format(":: theFilePath: '%s'%n", theFilePath);
//InputStream in = MyJavaClass.class.getResourceAsStream(theFilePath); // no can do, is 'null', also w/ abs path
//InputStream in = new FileInputStream( new File(theFilePath) ); // OK, but not seekable
FileInputStream in = new FileInputStream( new File(theFilePath) );
properties.load(in);
// double-check loaded properties:
for(String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
System.out.format(":: properties: key '%s' => value '%s'%n", key, value);
}
ByteArrayOutputStream resultbaos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
in.getChannel().position(0); // do reset - seek 0 (start), to reset stream again for reading
while ((length = in.read(buffer)) != -1) {
resultbaos.write(buffer, 0, length);
}
result = resultbaos.toString();
} catch (IOException e) {
System.err.println("There was an error reading " + inFileName + ": " + e.getCause()
+ " : " + e.getMessage());
} catch (Exception e) {
System.err.println("There was an exception " + inFileName + ": " + e
+ " : " + e.getMessage());
}
return result;
}
public void getLocations() {
URL classURL = getClass().getProtectionDomain().getCodeSource().getLocation();
System.out.format(":: The URL is '%s';%n", classURL); // file:/tmp/testprocjavapath3056820301028631180temp/
String s = getClass().getName();
int i = s.lastIndexOf(".");
if(i > -1) s = s.substring(i + 1);
s = s + ".class";
System.out.println(":: name: " + s);
Object resourcePath = this.getClass().getResource(s);
System.out.println(":: resourcePath: " + resourcePath); // file:/tmp/testprocjavapath9185318125154993853temp/MyJavaClass.class
}
}
EOF
# run once:
"$PROCBINPATH"/processing-java --sketch="$MYSKETCHDIR" --run
Related
I am trying to read a text file which is set in CLASSPATH system variable. Not a user variable.
I am trying to get input stream to the file as below:
Place the directory of file (D:\myDir) in CLASSPATH and try below:
InputStream in = this.getClass().getClassLoader().getResourceAsStream("SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("/SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("//SomeTextFile.txt");
Place full path of file (D:\myDir\SomeTextFile.txt) in CLASSPATH and try the same above 3 lines of code.
But unfortunately NONE of them are working and I am always getting null into my InputStream in.
With the directory on the classpath, from a class loaded by the same classloader, you should be able to use either of:
// From ClassLoader, all paths are "absolute" already - there's no context
// from which they could be relative. Therefore you don't need a leading slash.
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("SomeTextFile.txt");
// From Class, the path is relative to the package of the class unless
// you include a leading slash, so if you don't want to use the current
// package, include a slash like this:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
If those aren't working, that suggests something else is wrong.
So for example, take this code:
package dummy;
import java.io.*;
public class Test
{
public static void main(String[] args)
{
InputStream stream = Test.class.getResourceAsStream("/SomeTextFile.txt");
System.out.println(stream != null);
stream = Test.class.getClassLoader().getResourceAsStream("SomeTextFile.txt");
System.out.println(stream != null);
}
}
And this directory structure:
code
dummy
Test.class
txt
SomeTextFile.txt
And then (using the Unix path separator as I'm on a Linux box):
java -classpath code:txt dummy.Test
Results:
true
true
When using the Spring Framework (either as a collection of utilities or container - you do not need to use the latter functionality) you can easily use the Resource abstraction.
Resource resource = new ClassPathResource("com/example/Foo.class");
Through the Resource interface you can access the resource as InputStream, URL, URI or File. Changing the resource type to e.g. a file system resource is a simple matter of changing the instance.
This is how I read all lines of a text file on my classpath, using Java 7 NIO:
...
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
...
Files.readAllLines(
Paths.get(this.getClass().getResource("res.txt").toURI()), Charset.defaultCharset());
NB this is an example of how it can be done. You'll have to make improvements as necessary. This example will only work if the file is actually present on your classpath, otherwise a NullPointerException will be thrown when getResource() returns null and .toURI() is invoked on it.
Also, since Java 7, one convenient way of specifying character sets is to use the constants defined in java.nio.charset.StandardCharsets
(these are, according to their javadocs, "guaranteed to be available on every implementation of the Java platform.").
Hence, if you know the encoding of the file to be UTF-8, then specify explicitly the charset StandardCharsets.UTF_8
Please try
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
Your tries didn't work because only the class loader for your classes is able to load from the classpath. You used the class loader for the java system itself.
To actually read the contents of the file, I like using Commons IO + Spring Core. Assuming Java 8:
try (InputStream stream = new ClassPathResource("package/resource").getInputStream()) {
IOUtils.toString(stream);
}
Alternatively:
InputStream stream = null;
try {
stream = new ClassPathResource("/log4j.xml").getInputStream();
IOUtils.toString(stream);
} finally {
IOUtils.closeQuietly(stream);
}
To get the class absolute path try this:
String url = this.getClass().getResource("").getPath();
Somehow the best answer doesn't work for me. I need to use a slightly different code instead.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("SomeTextFile.txt");
I hope this help those who encounters the same issue.
If you use Guava:
import com.google.common.io.Resources;
we can get URL from CLASSPATH:
URL resource = Resources.getResource("test.txt");
String file = resource.getFile(); // get file path
or InputStream:
InputStream is = Resources.getResource("test.txt").openStream();
Ways to convert an InputStream to a String
To read the contents of a file into a String from the classpath, you can use this:
private String resourceToString(String filePath) throws IOException, URISyntaxException
{
try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filePath))
{
return IOUtils.toString(inputStream);
}
}
Note:
IOUtils is part of Commons IO.
Call it like this:
String fileContents = resourceToString("ImOnTheClasspath.txt");
You say "I am trying to read a text file which is set in CLASSPATH system variable." My guess this is on Windows and you are using this ugly dialog to edit the "System Variables".
Now you run your Java program in the console. And that doesn't work: The console gets a copy of the values of the system variables once when it is started. This means any change in the dialog afterwards doesn't have any effect.
There are these solutions:
Start a new console after every change
Use set CLASSPATH=... in the console to set the copy of the variable in the console and when your code works, paste the last value into the variable dialog.
Put the call to Java into .BAT file and double click it. This will create a new console every time (thus copying the current value of the system variable).
BEWARE: If you also have a User variable CLASSPATH then it will shadow your system variable. That is why it is usually better to put the call to your Java program into a .BAT file and set the classpath in there (using set CLASSPATH=) rather than relying on a global system or user variable.
This also makes sure that you can have more than one Java program working on your computer because they are bound to have different classpaths.
My answer is not exactly what is asked in the question. Rather I am giving a solution exactly how easily we can read a file into out java application from our project class path.
For example suppose a config file name example.xml is located in a path like below:-
com.myproject.config.dev
and our java executable class file is in the below path:-
com.myproject.server.main
now just check in both the above path which is the nearest common directory/folder from where you can access both dev and main directory/folder (com.myproject.server.main - where our application’s java executable class is existed) – We can see that it is myproject folder/directory which is the nearest common directory/folder from where we can access our example.xml file. Therefore from a java executable class resides in folder/directory main we have to go back two steps like ../../ to access myproject. Now following this, see how we can read the file:-
package com.myproject.server.main;
class Example {
File xmlFile;
public Example(){
String filePath = this.getClass().getResource("../../config/dev/example.xml").getPath();
this.xmlFile = new File(filePath);
}
public File getXMLFile() {
return this.xmlFile;
}
public static void main(String args[]){
Example ex = new Example();
File xmlFile = ex.getXMLFile();
}
}
If you compile your project in jar file:
you can put your file in resources/files/your_file.text or pdf;
and use this code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
public class readFileService(){
private static final Logger LOGGER = LoggerFactory.getLogger(readFileService.class);
public byte[] getFile(){
String filePath="/files/your_file";
InputStream inputStreamFile;
byte[] bytes;
try{
inputStreamFile = this.getClass().getResourceAsStream(filePath);
bytes = new byte[inputStreamFile.available()];
inputStreamFile.read(bytes);
} catch(NullPointerException | IOException e) {
LOGGER.error("Erreur read file "+filePath+" error message :" +e.getMessage());
return null;
}
return bytes;
}
}
I am using webshpere application server and my Web Module is build on Spring MVC. The Test.properties were located in the resources folder, i tried to load this files using the following:
this.getClass().getClassLoader().getResourceAsStream("Test.properties");
this.getClass().getResourceAsStream("/Test.properties");
None of the above code loaded the file.
But with the help of below code the property file was loaded successfully:
Thread.currentThread().getContextClassLoader().getResourceAsStream("Test.properties");
Thanks to the user "user1695166".
Use org.apache.commons.io.FileUtils.readFileToString(new File("src/test/resources/sample-data/fileName.txt"));
Don't use getClassLoader() method and use the "/" before the file name. "/" is very important
this.getClass().getResourceAsStream("/SomeTextFile.txt");
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile
{
/**
* * feel free to make any modification I have have been here so I feel you
* * * #param args * #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// thread pool of 10
File dir = new File(".");
// read file from same directory as source //
if (dir.isDirectory()) {
File[] files = dir.listFiles();
for (File file : files) {
// if you wanna read file name with txt files
if (file.getName().contains("txt")) {
System.out.println(file.getName());
}
// if you want to open text file and read each line then
if (file.getName().contains("txt")) {
try {
// FileReader reads text files in the default encoding.
FileReader fileReader = new FileReader(
file.getAbsolutePath());
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader = new BufferedReader(
fileReader);
String line;
// get file details and get info you need.
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
// here you can say...
// System.out.println(line.substring(0, 10)); this
// prints from 0 to 10 indext
}
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '"
+ file.getName() + "'");
} catch (IOException ex) {
System.out.println("Error reading file '"
+ file.getName() + "'");
// Or we could just do this:
ex.printStackTrace();
}
}
}
}
}
}
you have to put your 'system variable' on the java classpath.
Is there a way to access the file inside archive while ignoring file name case using TrueZip?
Imagine following zip archive with content:
MyZip.zip
-> myFolder/tExtFile.txt
-> anotherFolder/TextFiles/file.txt
-> myFile.txt
-> anotherFile.txt
-> OneMOREfile.txt
This is how it works:
TPath tPath = new TPath("MyZip.zip\\myFolder\\tExtFile.txt");
System.out.println(tPath.toFile().getName()); //prints tExtFile.txt
How to do the same but ignore all case, like this:
// note "myFolder" changed to "myfolder" and "tExtFile" to "textfile"
TPath tPath = new TPath("MyZip.zip\\myfolder\\textfile.txt");
System.out.println(tPath.toFile().getName()); // should print tExtFile.txt
Code above throws FsEntryNotFoundException ... (no such entry)
It works for regular java.io.File, not sure why not for TFile of TrueZip or I am missing something?
My goal is to access each file just using only lowercase for files and folders.
Edit: 24-03-2017
Let's say I would like to read bytes from file inside mentioned zip archive MyZip.zip
Path tPath = new TPath("...MyZip.zip\\myFolder\\tExtFile.txt");
byte[] bytes = Files.readAllBytes(tPath); //returns bytes of the file
This snippet above works, but this one below does not (throws mentioned -> FsEntryNotFoundException). It is the same path and file just in lowercase.
Path tPath = new TPath("...myzip.zip\\myfolder\\textfile.txt");
byte[] bytes = Files.readAllBytes(tPath);
You said:
My goal is to access each file just using only lowercase for files and folders.
But wishful thinking will not get you very far here. As a matter of fact, most file systems (except Windows types) are case-sensitive, i.e. in them it makes a big difference if you use upper- or lower-case characters. There you can even have the "same" file name in different case multiple times in the same directory. I.e. it actually makes a difference if the name is file.txt, File.txt or file.TXT. Windows is really an exception here, but TrueZIP does not emulate a Windows file system but a general archive file system which works for ZIP, TAR etc. on all platforms. Thus, you do not have a choice whether you use upper- or lower-case characters, but you have to use them exactly as stored in the ZIP archive.
Update: Just as a little proof, I logged into a remote Linux box with an extfs file system and did this:
~$ mkdir test
~$ cd test
~/test$ touch file.txt
~/test$ touch File.txt
~/test$ touch File.TXT
~/test$ ls -l
total 0
-rw-r--r-- 1 group user 0 Mar 25 00:14 File.TXT
-rw-r--r-- 1 group user 0 Mar 25 00:14 File.txt
-rw-r--r-- 1 group user 0 Mar 25 00:14 file.txt
As you can clearly see, there are three distinct files, not just one.
And what happens if you zip those three files into an archive?
~/test$ zip ../files.zip *
adding: File.TXT (stored 0%)
adding: File.txt (stored 0%)
adding: file.txt (stored 0%)
Three files added. But are they still distince files in the archive or just stored under one name?
~/test$ unzip -l ../files.zip
Archive: ../files.zip
Length Date Time Name
--------- ---------- ----- ----
0 2017-03-25 00:14 File.TXT
0 2017-03-25 00:14 File.txt
0 2017-03-25 00:14 file.txt
--------- -------
0 3 files
"3 files", it says - quod erat demonstrandum.
As you can see, Windows is not the whole world. But if you copy that archive to a Windows box and unzip it there, it will only write one file to a disk with NTFS or FAT file system - which one is a matter of luck. Very bad if the three files have different contents.
Update 2: Okay, there is no solution within TrueZIP for the reasons explained in detail above, but if you want to work around it, you can do it manually like this:
package de.scrum_master.app;
import de.schlichtherle.truezip.nio.file.TPath;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
public class Application {
public static void main(String[] args) throws IOException, URISyntaxException {
TPathHelper tPathHelper = new TPathHelper(
new TPath(
"../../../downloads/powershellarsenal-master.zip/" +
"PowerShellArsenal-master\\LIB/CAPSTONE\\LIB\\X64\\LIBCAPSTONE.DLL"
)
);
TPath caseSensitivePath = tPathHelper.getCaseSensitivePath();
System.out.printf("Original path: %s%n", tPathHelper.getOriginalPath());
System.out.printf("Case-sensitive path: %s%n", caseSensitivePath);
System.out.printf("File size: %,d bytes%n", Files.readAllBytes(caseSensitivePath).length);
}
}
package de.scrum_master.app;
import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.nio.file.TPath;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
public class TPathHelper {
private final TPath originalPath;
private TPath caseSensitivePath;
public TPathHelper(TPath tPath) {
originalPath = tPath;
}
public TPath getOriginalPath() {
return originalPath;
}
public TPath getCaseSensitivePath() throws IOException, URISyntaxException {
if (caseSensitivePath != null)
return caseSensitivePath;
final TPath absolutePath = new TPath(originalPath.toFile().getCanonicalPath());
TPath matchingPath = absolutePath.getRoot();
for (Path subPath : absolutePath) {
boolean matchFound = false;
for (TFile candidateFile : matchingPath.toFile().listFiles()) {
if (candidateFile.getName().equalsIgnoreCase(subPath.toString())) {
matchFound = true;
matchingPath = new TPath(matchingPath.toString(), candidateFile.getName());
break;
}
}
if (!matchFound)
throw new IOException("element '" + subPath + "' not found in '" + matchingPath + "'");
}
caseSensitivePath = matchingPath;
return caseSensitivePath;
}
}
Of course, this is a little ugly and will just get you the first matching path if there are multiple case-insensitive matches in an archive. The algorithm will stop searching after the first match in each subdirectory. I am not particularly proud of this solution, but it was a nice exercise and you seem to insist that you want to do it this way. I just hope you are never confronted with a UNIX-style ZIP archive created on a case-sensitive file system and containing multiple possible matches.
BTW, the console log for my sample file looks like this:
Original path: ..\..\..\downloads\powershellarsenal-master.zip\PowerShellArsenal-master\LIB\CAPSTONE\LIB\X64\LIBCAPSTONE.DLL
Case-sensitive path: C:\Users\Alexander\Downloads\PowerShellArsenal-master.zip\PowerShellArsenal-master\Lib\Capstone\lib\x64\libcapstone.dll
File size: 3.629.294 bytes
I dont have TrueZip installed but I was also wondering how it would work in normal Path, so I implemented below way quite similar #kriegaex solution, you can try using caseCheck(path):
public class Main {
/**
* #param args
* #throws Exception
*/
public static void main(String[] args) throws Exception {
Path path = Paths.get("/home/user/workspace/JParser/myfolder/yourfolder/Hisfolder/a.txt");
Instant start = Instant.now();
Path resolution;
try{
resolution = caseCheck(path);
}catch (Exception e) {
throw new IllegalArgumentException("Couldnt access given path", e);
}
Instant end = Instant.now();
Duration duration = Duration.between(start, end);
System.out.println("Path is: " + resolution + " process took " + duration.toMillis() + "ms");
}
/**
* #param path
* #return
* #throws IOException
*/
private static Path caseCheck(Path path) throws IOException {
Path entryPoint = path.isAbsolute() ? path.getRoot() : Paths.get(".");
AtomicInteger counter = new AtomicInteger(0);
while (counter.get() < path.getNameCount()) {
entryPoint = Files
.walk(entryPoint, 1)
.filter(s -> checkPath(s, path, counter.get()))
.findFirst()
.orElseThrow(()->new IllegalArgumentException("No folder found"));
counter.getAndIncrement();
}
return entryPoint;
}
/**
* #param s
* #param path
* #param index
* #return
*/
private static final boolean checkPath(Path s, Path path, int index){
if (s.getFileName() == null) {
return false;
}
return s.getFileName().toString().equalsIgnoreCase(path.getName(index).toString());
}
}
I was hoping someone could explain why this will not work and what my solution might be.
I have tried the following to learn what happens:
String s = "\\users\\udc8\\a4471\\My Documents\\MATLAB\\blockdiagram.xml";
String st = "\\";
String st2 = st + s;
System.out.println(st2);
Giving me the following output:
\\users\udc8\a4471\My Documents\MATLAB\blockdiagram.xml
Which is the correct path to the file.
Then I try to parse this file using SAX and I get an IOEXception saying the file does not exist. I have tried using File and getPath(),getCanonicalPath() and getAbsolutePath().
When running the parser i get the msg:
Due to an IOException, the parser could not check \\users\udc8\a4471\My Documents\MATLAB\\blockdiagram.xml
This is the code starting the parsing:
try {
XMLReader parser = XMLReaderFactory.createXMLReader();
parser.parse(st2);
System.out.println(s + " is well-formed.");
}
catch (SAXException e) {
System.out.println(s + " is not well-formed.");
}
catch (IOException e) {
System.out.println(
"Due to an IOException, the parser could not check "
+ s
);
}
Running a similar program that does not have its own messege the following error messege is returned:
java.io.FileNotFoundException: \\users\udc8\a4471\workspace\SAX Intro\users\udc8\a4471\My Documents\MATLAB\blockdiagram.xml (The system cannot find the file specified)
The file has no special restrictions (as far as I can see), Nothing ticked in looking at file properties and I can manually re-write the content.
Any ideas?
Maybe it is just because of your path has two \-signs too much in it. I recomend you give it a try with your variable s instead of s2 that has the additional \-signs added.
To be honest i just realized how less i know about paths in java, expecially when it comes to different OS.
I however managed to get it to run on a Windows machine like so:
import java.io.File;
import java.io.IOException;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class SaXSample {
public static void main(String[] args) {
new SaXSample().run();
}
public void run() {
System.out.println("This class is located under: "+getAbsolutePath());
// using absolut pathd
String absolutPath = "D:\\temp\\Oki.xml";
File f = new File(absolutPath);
System.out.println("Does the file exist using the absolut path? -> "+f.exists());
runSaX(absolutPath);
// using relative path (i dont know why it knows which drive C:/, D:/ to take but my .class is running from the same drive as the .xml is in)
String relativePath = "\\temp\\Oki.xml";
File f2 = new File(relativePath);
System.out.println("Does the file exist using the relative path? -> "+f2.exists());
runSaX(relativePath);
// using a "wrong" relative path:
String wrongRelativePath = "\\\\temp\\Oki.xml";
File f3 = new File(wrongRelativePath);
System.out.println("File relative path: "+f3.getPath()+" , File absolut path: "+f3.getAbsolutePath());
runSaX(wrongRelativePath);
}
private void runSaX(String path) {
try {
XMLReader parser = XMLReaderFactory.createXMLReader();
parser.parse(path);
System.out.println(path + " is well-formed.");
} catch (SAXException e) {
System.out.println(path + " is not well-formed.");
} catch (IOException e) {
System.out
.println("Due to an IOException, the parser could not check "
+ path);
}
}
private String getAbsolutePath() {
java.security.ProtectionDomain pd = SaXSample.class
.getProtectionDomain();
if (pd == null)
return null;
java.security.CodeSource cs = pd.getCodeSource();
if (cs == null)
return null;
java.net.URL url = cs.getLocation();
if (url == null)
return null;
java.io.File f = new File(url.getFile());
if (f == null)
return null;
return f.getAbsolutePath();
}
}
Which in my case leads to this output (sorry i dont know how to format console output):
This class is located under: D:\devjba\jba\bin
Does the file exist using the absolut path? -> true
D:\temp\Oki.xml is well-formed.
Does the file exist using the relative path? -> true
\temp\Oki.xml is well-formed.
File relative path: \\temp\Oki.xml , File absolut path: \\temp\Oki.xml
Due to an IOException, the parser could not check \\temp\Oki.xml
Since you implied in the comments that you wish to be able to select certain files or directorys i recomend you have a look at the JFileChooser. It is a simple way to let the user choose something that actually exists and will provide you the absolute path to the selected file/files.
NOTE: i have no clue why in the relative path-case the correct drive D:/ is used and not the other C:/
I'm running a program to list info of all files stored in folder.
I want to obtain properties of a file (the most important for me is file size, but i would like to get also other properties, like date of modification, etc.).
My problem is when I get to the file which is actually used by another program, I can't get BasicFileAtrributtes of file. I've tried to use File, URL, RandomFileAcces, but all of these requiese to open a file, and throw Exception like:
java.io.FileNotFoundException: C:\pagefile.sys (Access is denied)
Is there any option in java to obtain this properties? I prefer not to use any extra libraries, to keep small size of the application.
App is based on java JRE7.
I'm using java.nio.file.SimpleFileVisitor to visit all the files.
Here is fragment of my code, where I got the error:
#Override
public FileVisitResult visitFileFailed(Path file, IOException exc){
FileInfo temp=new FileInfo(new FileInfo().repairName(file.toString()));
temp.isLeaf=true;
temp.fName=temp.fName.replace(strIn, "");
File fis=null;
try {
fis=new File(file.toAbsolutePath().toString());
if(fis.exists())
System.out.println("exists");
if(fis.isFile())
System.out.println("isFile");
System.out.println(file.toAbsolutePath().toString());
temp.fSize=new BigInteger(new Long(fis.length()).toString());
} catch(Exception e){
e.printStackTrace();
}
node.add(temp, true);
FileListCreator.jProgressBar.setValue(++count);
return CONTINUE;
}
This works just fine for me:
File temp = new File("c:\\pagefile.sys");
System.err.println(temp.length());
System.err.println(temp.lastModified());
If the method java.io.File.exists() returns false, and the file C:\pagefile.sys exists in your file system, you specified the incorrect file path then.
The following code works on my machine:
package q10025482;
import java.io.File;
public class TestFile {
public static void main(String[] args) {
String fileName = "C:/System Volume Information";//"C:/pagefile.sys"
File file = new File(fileName);
System.out.println("\nFile " + file.getAbsolutePath() + " info:");
System.out.println("Exists: " + file.exists());
System.out.println("Is file: " + file.isFile());
System.out.println("Is dir: " + file.isDirectory());
System.out.println("Length: " + file.length());
System.out.println();
}
}
Here is the result output:
File C:\System Volume Information info:
Exists: true
Is file: false
Is dir: true
Length: 24576
I am trying to read a text file which is set in CLASSPATH system variable. Not a user variable.
I am trying to get input stream to the file as below:
Place the directory of file (D:\myDir) in CLASSPATH and try below:
InputStream in = this.getClass().getClassLoader().getResourceAsStream("SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("/SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("//SomeTextFile.txt");
Place full path of file (D:\myDir\SomeTextFile.txt) in CLASSPATH and try the same above 3 lines of code.
But unfortunately NONE of them are working and I am always getting null into my InputStream in.
With the directory on the classpath, from a class loaded by the same classloader, you should be able to use either of:
// From ClassLoader, all paths are "absolute" already - there's no context
// from which they could be relative. Therefore you don't need a leading slash.
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("SomeTextFile.txt");
// From Class, the path is relative to the package of the class unless
// you include a leading slash, so if you don't want to use the current
// package, include a slash like this:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
If those aren't working, that suggests something else is wrong.
So for example, take this code:
package dummy;
import java.io.*;
public class Test
{
public static void main(String[] args)
{
InputStream stream = Test.class.getResourceAsStream("/SomeTextFile.txt");
System.out.println(stream != null);
stream = Test.class.getClassLoader().getResourceAsStream("SomeTextFile.txt");
System.out.println(stream != null);
}
}
And this directory structure:
code
dummy
Test.class
txt
SomeTextFile.txt
And then (using the Unix path separator as I'm on a Linux box):
java -classpath code:txt dummy.Test
Results:
true
true
When using the Spring Framework (either as a collection of utilities or container - you do not need to use the latter functionality) you can easily use the Resource abstraction.
Resource resource = new ClassPathResource("com/example/Foo.class");
Through the Resource interface you can access the resource as InputStream, URL, URI or File. Changing the resource type to e.g. a file system resource is a simple matter of changing the instance.
This is how I read all lines of a text file on my classpath, using Java 7 NIO:
...
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
...
Files.readAllLines(
Paths.get(this.getClass().getResource("res.txt").toURI()), Charset.defaultCharset());
NB this is an example of how it can be done. You'll have to make improvements as necessary. This example will only work if the file is actually present on your classpath, otherwise a NullPointerException will be thrown when getResource() returns null and .toURI() is invoked on it.
Also, since Java 7, one convenient way of specifying character sets is to use the constants defined in java.nio.charset.StandardCharsets
(these are, according to their javadocs, "guaranteed to be available on every implementation of the Java platform.").
Hence, if you know the encoding of the file to be UTF-8, then specify explicitly the charset StandardCharsets.UTF_8
Please try
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
Your tries didn't work because only the class loader for your classes is able to load from the classpath. You used the class loader for the java system itself.
To actually read the contents of the file, I like using Commons IO + Spring Core. Assuming Java 8:
try (InputStream stream = new ClassPathResource("package/resource").getInputStream()) {
IOUtils.toString(stream);
}
Alternatively:
InputStream stream = null;
try {
stream = new ClassPathResource("/log4j.xml").getInputStream();
IOUtils.toString(stream);
} finally {
IOUtils.closeQuietly(stream);
}
To get the class absolute path try this:
String url = this.getClass().getResource("").getPath();
Somehow the best answer doesn't work for me. I need to use a slightly different code instead.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("SomeTextFile.txt");
I hope this help those who encounters the same issue.
If you use Guava:
import com.google.common.io.Resources;
we can get URL from CLASSPATH:
URL resource = Resources.getResource("test.txt");
String file = resource.getFile(); // get file path
or InputStream:
InputStream is = Resources.getResource("test.txt").openStream();
Ways to convert an InputStream to a String
To read the contents of a file into a String from the classpath, you can use this:
private String resourceToString(String filePath) throws IOException, URISyntaxException
{
try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filePath))
{
return IOUtils.toString(inputStream);
}
}
Note:
IOUtils is part of Commons IO.
Call it like this:
String fileContents = resourceToString("ImOnTheClasspath.txt");
You say "I am trying to read a text file which is set in CLASSPATH system variable." My guess this is on Windows and you are using this ugly dialog to edit the "System Variables".
Now you run your Java program in the console. And that doesn't work: The console gets a copy of the values of the system variables once when it is started. This means any change in the dialog afterwards doesn't have any effect.
There are these solutions:
Start a new console after every change
Use set CLASSPATH=... in the console to set the copy of the variable in the console and when your code works, paste the last value into the variable dialog.
Put the call to Java into .BAT file and double click it. This will create a new console every time (thus copying the current value of the system variable).
BEWARE: If you also have a User variable CLASSPATH then it will shadow your system variable. That is why it is usually better to put the call to your Java program into a .BAT file and set the classpath in there (using set CLASSPATH=) rather than relying on a global system or user variable.
This also makes sure that you can have more than one Java program working on your computer because they are bound to have different classpaths.
My answer is not exactly what is asked in the question. Rather I am giving a solution exactly how easily we can read a file into out java application from our project class path.
For example suppose a config file name example.xml is located in a path like below:-
com.myproject.config.dev
and our java executable class file is in the below path:-
com.myproject.server.main
now just check in both the above path which is the nearest common directory/folder from where you can access both dev and main directory/folder (com.myproject.server.main - where our application’s java executable class is existed) – We can see that it is myproject folder/directory which is the nearest common directory/folder from where we can access our example.xml file. Therefore from a java executable class resides in folder/directory main we have to go back two steps like ../../ to access myproject. Now following this, see how we can read the file:-
package com.myproject.server.main;
class Example {
File xmlFile;
public Example(){
String filePath = this.getClass().getResource("../../config/dev/example.xml").getPath();
this.xmlFile = new File(filePath);
}
public File getXMLFile() {
return this.xmlFile;
}
public static void main(String args[]){
Example ex = new Example();
File xmlFile = ex.getXMLFile();
}
}
If you compile your project in jar file:
you can put your file in resources/files/your_file.text or pdf;
and use this code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
public class readFileService(){
private static final Logger LOGGER = LoggerFactory.getLogger(readFileService.class);
public byte[] getFile(){
String filePath="/files/your_file";
InputStream inputStreamFile;
byte[] bytes;
try{
inputStreamFile = this.getClass().getResourceAsStream(filePath);
bytes = new byte[inputStreamFile.available()];
inputStreamFile.read(bytes);
} catch(NullPointerException | IOException e) {
LOGGER.error("Erreur read file "+filePath+" error message :" +e.getMessage());
return null;
}
return bytes;
}
}
I am using webshpere application server and my Web Module is build on Spring MVC. The Test.properties were located in the resources folder, i tried to load this files using the following:
this.getClass().getClassLoader().getResourceAsStream("Test.properties");
this.getClass().getResourceAsStream("/Test.properties");
None of the above code loaded the file.
But with the help of below code the property file was loaded successfully:
Thread.currentThread().getContextClassLoader().getResourceAsStream("Test.properties");
Thanks to the user "user1695166".
Use org.apache.commons.io.FileUtils.readFileToString(new File("src/test/resources/sample-data/fileName.txt"));
Don't use getClassLoader() method and use the "/" before the file name. "/" is very important
this.getClass().getResourceAsStream("/SomeTextFile.txt");
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile
{
/**
* * feel free to make any modification I have have been here so I feel you
* * * #param args * #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// thread pool of 10
File dir = new File(".");
// read file from same directory as source //
if (dir.isDirectory()) {
File[] files = dir.listFiles();
for (File file : files) {
// if you wanna read file name with txt files
if (file.getName().contains("txt")) {
System.out.println(file.getName());
}
// if you want to open text file and read each line then
if (file.getName().contains("txt")) {
try {
// FileReader reads text files in the default encoding.
FileReader fileReader = new FileReader(
file.getAbsolutePath());
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader = new BufferedReader(
fileReader);
String line;
// get file details and get info you need.
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
// here you can say...
// System.out.println(line.substring(0, 10)); this
// prints from 0 to 10 indext
}
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '"
+ file.getName() + "'");
} catch (IOException ex) {
System.out.println("Error reading file '"
+ file.getName() + "'");
// Or we could just do this:
ex.printStackTrace();
}
}
}
}
}
}
you have to put your 'system variable' on the java classpath.