Loading multiple properties sets from single file for multiple class instances - java

I have a class of which I need a different instance if one of its attributes changes. These changes are read at runtime from a property file.
I would like to have a single file detailing the properties of all the single instances:
------------
name=Milan
surface=....
------------
name=Naples
surface=....
How can I load each set of properties in a different Property class (maybe creating a Properties[])? Is there a Java built in method to do so?
Should I manually parse it, how could create an InputStream anytime I find the division String among the sets?
ArrayList<Properties> properties = new ArrayList<>();
if( whateverItIs.nextLine() == "----" ){
InputStream limitedInputStream = next-5-lines ;
properties.add(new Properties().load(limitedInputStream));
}
Something like above. And, by the way, any constructor method which directly creates the class from a file?
EDIT: any pointing in the right direction to look it for myself would be fine too.

First of all, read the whole file as a single string. Then use split and StringReader.
String propertiesFile = FileUtils.readFileToString(file, "utf-8");
String[] propertyDivs = propertiesFile.split("----");
ArrayList<Properties> properties = new ArrayList<Properties>();
for (String propertyDiv : propertyDivs) {
properties.add(new Properties().load(new StringReader(propertyDiv)));
}
The example above uses apache commons-io library for file to String one-liner, because Java does not have such a built-in method. However, reading file can be easily implemented using standard Java libraries, see Whole text file to a String in Java

Related

Is using the File class in Java how you create a file?

I need some serious help with concepts. I have been given background context on the class, specifically this:
I just need to understand the purpose of this class? Can I create a text file (or any other type of file) with its constructors? Is this just for handling files, if so, what does that mean?
Any help whatsoever will be greatly appreciated!
Thank you
You could use the java.io.File to create a file on the file system:
File myFile = new File("myFile.txt");
myFile.createNewFile();
Note that invoking the constructor won't create the file on the file system. To create an empty file, the createNewFile() method has to be invoked.
The File simply represents a abstraction of the file location, not the file itself. It comes with operations on the file identified by the path: exists(), delete(), length(), etc.
What you probably want is to use the classes that allow you to write content to a file:
If you are to write text, you should use the Writer interface.
If you are to write binary content, you should use the OutputStream interface.
The classes FileWriter and FileOutputStream are, respectively, the ones that link the File and Writer/OutputStream concepts together. Those classes create the file on the file-system for you.
FileWriter myFileWriter = null;
File myFile = new File("myFile.txt");
try {
// file is created on the file-system here
myFileWriter = new FileWriter(myFile);
myFileWriter.write("hello");
} finally {
if (myFileWriter != null) {
myFileWriter.close();
}
}
You can create a file using the File.createNewFile method, or, if you are using Java 7 or newer, using the newer Files.createFile method.
The difference between the old File and the new Path classes is that the former mixed a reference to a path to a file on the filsystem and operations you can do on it, and the latter is just representing the path itself but allows you to query it and analyze its structure.

Read metadata with ExifTool

I'm trying to read illustrator file metadata value by using Exiftool. I tried as per below.
File[] images = new File("filepath").listFiles();
ExifTool tool = new ExifTool(Feature.STAY_OPEN);
for(File f : images) {
if (f.toString().contains(".ai"))
{
System.out.println("test "+tool.getImageMeta(f, Tag.DATE_TIME_ORIGINAL));
}
}
tool.close();
Above code not printing any value. I even tried this.
public static final File[] IMAGES = new File("filepath").listFiles();
ExifTool tool = new ExifTool(Feature.STAY_OPEN);
for (File f : IMAGES) {
System.out.println("\n[" + f.getName() + "]");
System.out.println(tool.getImageMeta(f, Format.NUMERIC,
Tag.values()));
}
Which only prints {IMAGE_HEIGHT=2245, IMAGE_WIDTH=5393}. How do I call metadata values using Exiftool. Any advices and references links are highly appreciated.
For the given API, it either;
1-does not contain the tag you are looking for
2-the file itself might not have that tag filled
3-you might want to recreate your own using a more general tag command when calling exiftool.exe
Look in the source code and find the enum containing all the tags available to the API, that'll show you what you're restricted to. But yeah, you might want to consider making your own class similar to the one you're using. I'm in the midst of doing the same. That way you can store the tags in perhaps a set or HashMap instead of an enum and therefore be much less limited in tag choice. Then, all you have to do is write the commands for the tags you want to the process's OutputStream and then read the results from the InputStream.

How to increment a Resource?

I have a function that adds instances (and their properties values) of class Person in a RDF file when I click on the Add button. I can add the first instance, but when I try to add the second, it replaces the first instance by the second.
I think it is because I do not increment Resource P1 = model.createResource(personURI+"Name"), after adding the first instance.
How can I increment a Resource in java from P1 to P2 to P3, etc?
public class ActionAjoutPersonne implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
Onto f = new Onto();
Resource p1 = f.model.createResource(f.uriBase+tabTF[0].getText());
p1.addProperty(f.aPourPrenom, tabTF[0].getText());
p1.addProperty(f.aPourNom, tabTF[1].getText());
p1.addProperty(f.aDateNaiss, tabTF[2].getText());
if (tabTF[3].getText().equals("F"))
{
p1.addProperty(f.aGenre, tabTF[3].getText());
p1.addProperty(RDF.type, f.femme);
}
else if (tabTF[3].getText().equals("H"))
{
p1.addProperty(f.aGenre, tabTF[3].getText());
p1.addProperty(RDF.type, f.homme);
}
StringWriter sw = new StringWriter();
f.model.write(sw, "RDF/XML-ABBREV");
String owlCode = sw.toString();
File file = new File("d:/teste20.rdf");
try{
FileWriter fw = new FileWriter(file);
fw.write(owlCode);
fw.close();
} catch(FileNotFoundException fnfe){
fnfe.printStackTrace();}
catch(IOException ioe){
ioe.printStackTrace();
}
}
}
I assume you're using Jena?
The createResource(uri) method will overwrite an existing resource if you call it again with the same URI argument.
So you have to make sure to assign a different URI for each person.
You can achieve this using some sort of auto-incrementing counter, or by making the person's name a part of the URI (using URLEncoder.encode(name, "utf-8") for example).
I'm a little unclear what your precise end goal here is, A.R., but I can see two possibilities:
you want a series of files on disk, with different file names, each containing the RDF fragment from one user's form
you want one file on disk, but which contains multiple RDF subjects, each one representing a different user's form details
In the first case, you would need to change the output file each time. Currently you have:
File file = new File("d:/teste20.rdf");
so the file name is fixed to 'teste20.rdf'. You would have to change that to use a different file name each time. There are various ways to achieve that: one way would be to have a private static int field on your class which you increment each time:
File file = new File("d:/teste_" + fileCounter++ + ".rdf");
There are other ways, which you can see from this question.
If, however, you want the second case: multiple RDF resources in one file, then it's a little hard to diagnose the problem without seeing more of the code. However, if the model in:
Resource p1 = f.model.createResource(...)
is not the same model each time (I can't tell from your code how that model is being created), the each time the listener runs, you create a model containing only the new data from the user's form, and then write that out in place. In that case, you have two choices: either don't keep creating a new model every time (but that means the model will eventually get quite large, and would also reset every time your application restarts), or read the existing contents of d:/teste20.rdf before you write out the contents of the model (not tested, but should work):
File file = new File("d:/teste20.rdf");
f.model.read( new FileReader( file ) );
f.model.write( new FileWriter( file ), "RDF/XML-ABBREV" );
If you're not creating a new model each time, an assuming that the expression f.uriBase+tabTF[0].getText() gives you a unique URI string for each user (otherwise the problem is non-unique subject URI's, as Richard suggested), then we would need to see more of the code to get to the root cause.
You are just rewriting the file four times. I suggest you to use some structured programming practices to avoid this kind of mistakes in the future.

How to read a metadata file efficiently?

My current project is using a metadata file to set properties without having to compile. Currently I have it set up in this way:
metadata.txt
[property] value <br/>
[property2] value2
File f = new File("metadata.txt");
BufferedReader in = new BufferedReader(new FileReader(f));
String variable1 = "";
String variable2 = "";
Now read this file using a BufferedReader and getting the information in a certain order. Such as:
variable1 = in.readLine();
variable2 = in.readLine();
I was wondering is there a better way to do this without having to read line by line? I was trying to think of using a loop but I'm not sure how that would work out since I want to set different String variables to each property.
Also I'm not using a GUI in this program so that is the reason why I'm editing the data raw.
Rather use the java.util.Properties API. It's designed exactly for this purpose.
Create a filename.properties file with key=value entries separated by newlines:
key1=value1
key2=value2
key3=value3
Put the file in the classpath (or add its path to the classpath) and load it as follows:
Properties properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
Then you can obtain values by key as follows:
String key1 = properties.getProperty("key1"); // returns value1
See also:
Properties tutorial
I'm not sure this is an answer to this question.
You can use java.util.Properties and its methods to save or load properties from the file. You metadata file looks like a property file, if you don't target doing something special.

Best practice for storage and retrieval of error messages

What is a best practice for storing user messages in a configuration file and then retrieving them for certain events throughout an application?
I was thinking of having 1 single configuration file with entries such as
REQUIRED_FIELD = {0} is a required field
INVALID_FORMAT = The format for {0} is {1}
etc. and then calling them from a class that would be something like this
public class UIMessages {
public static final String REQUIRED_FIELD = "REQUIRED_FIELD";
public static final String INVALID_FORMAT = "INVALID_FORMAT";
static {
// load configuration file into a "Properties" object
}
public static String getMessage(String messageKey) {
//
return properties.getProperty(messageKey);
}
}
Is this the right way to approach this problem or is there some de-facto standard already in place?
You're on the right track with putting the messages into a property file. Java makes this pretty easy if you use ResourceBundle. You basically create a property file containing your message strings for each locale you want to support (messages_en.properties, messages_ja.properties) and bundle those property files into your jar. Then, in your code, you extract the message:
ResourceBundle bundle = ResourceBundle.getBundle("messages");
String text = MessageFormat.format(bundle.getString("ERROR_MESSAGE"), args);
When you load the bundle, Java will determine what locale you're running in and load the correct message. Then, you pass in your args along with the message string and create the localized message.
Reference for ResourceBundle.
Your approach is almost correct. I want to add one more thing. If you are talking about configuration file, it is always better to have two .properties file.
One for default configuration of the application. (let's say defaultProperties.properties)
Second for user-specific configuration (let's say appProperties.properties)
. . .
// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();
// create application properties with default
Properties applicationProps = new Properties(defaultProps);
// now load properties from last invocation
in = new FileInputStream("appProperties");
applicationProps.load(in);
in.close();
. . .
Spring already has support for doing this kind of thing. http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#context-functionality-messagesource would be a good starting point

Categories