I have a real quick question. I have a Java program in which I use a properties file. The file is used for keeping track of the program's users. My problem is I cannot figure out how to ADD to the file. I know how to set existing properties to a value, but I don't know how to add more properties without over writing the other ones.
I would like the program to 'register' users, so to speak. Whenever a new users 'signs up', I want the program to add a new property containing the new user's information. I run into this problem though:
Example:
File: numOfUsers=0
One user registers. The username is 'c00lGuy'. The program registers this in the file:
File: numOfUsers=1 user1-username=c00lGuy
Another user registers. She decides to call her username 'theGr8Girl'. The program registers this:
File: numOfUsers=2 user2-username=theGr8Girl
The file after the two users registered:
File: numOfUsers=2 user2-username=theGr8Girl
How do I prevent my program from overwriting existing lines in the file? It seems to erase the file's contents, and then add what I tell it to. I don't want it to erase the file's contents.
The code I am using to register the properties:
Properties prop = new Properties();
OutputStream output = null;
int userCount = getUserCount();
userCount++;
try {
output = new FileOutputStream(fileName);
// set the properties value
prop.setProperty("numOfUsers", String.valueOf(userCount));
prop.setProperty("user" + userCount + "-username", username);
// save properties to project root folder
prop.store(output, null);
} catch (IOException io) {
io.printStackTrace();
} finally {
if (output != null)
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Try something like this:
FileOutputStream out = new FileOutputStream(fileName);
props.setProperty("numOfUsers", 2);
...
props.store(out, null);
out.close();
Properties files aren't really intended for this sort of usage, but if you have a small enough data set it'll work.
The step you are missing is that you need to read the properties from disk, make the changes, then save them back to disk.
Properties props = new Properties();
try{
props.load(inputStream);
} finally {
inputStream.close();
}
props.setProperty(....);
try{
props.store(outputStream);
} finally {
outputStream.close();
}
Just bear in mind that this is not at all suitable for any sort of volume processing. Also, there is a race condition if you have two threads trying to make changes to the properties file at the same time.
If you are looking for a lightweight persistent store, I highly recommend mapdb.
You code is creating a new Properties object each time. Make sure to reuse the old instance when adding a user.
The typical format for a line in this file would be
user=hashedPassword
so use the username as the key and the password as a value. The number of users does not need to be stored, it is just the size of the properties map.
Related
My application is a batch process that pulls environment variables from an application.properties file. The password that I use must be updated every few months. I would like to automate the password update process and save the updated password in the properties file so it can be used in future runs, but any updates I try to make are not propagated to the application.config file.
When I run in Intellij, there are no errors, but the file is not updated. When I run the application as a jar, it gives:
java.io.FileNotFoundException: file:{localpath}\application.jar!\BOOT-INF\classes!\application.properties (The filename, directory name, or volume label syntax is incorrect)
How do I dynamically update the application.properties file within the jar or do I need to create a new properties file outside of the jar when the application first runs??
EXAMPLE CODE SNIPPETS BELOW:
properties.config:
username=user
password=password123
Application.java:
//get properties
prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream(f);
// load a properties file
prop.load(input);
} catch (IOException ex) {
logger.error("Error reading application.properties", ex);
ex.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//update properties
prop.setProperty("TESTSTRING", "testvalue");
//write to properties file
OutputStream os = null;
try{
File f = new File(Application.class.getClassLoader().getResource("application.properties").getFile());
os = new FileOutputStream(f);
prop.store(os, comments);
}catch(IOException ex){
logger.error("Error updating application.properties", ex);
ex.printStackTrace();
} finally {
if(os != null){
try{
os.close();
} catch (IOException e){
e.printStackTrace();
}
}
Properties of an application that may change according to the running environment should never be packaged inside the packaged component.
It should be not hard coupled to the component and it should also be modifiable if required without modifying the packaged component.
Besides, properties may contain confidential information (as in your case : username and password).
So it should be preferably stored directly on the target environment.
For example, one of the cloud native application principles from Heroku/twelve factors (that are also good practices in general) is "storing the configuration in the environment".
So updating the properties file inside the packaged component has to be absolutely avoided for the same reasons.
Besides doing it makes the state application more hard to reproduce if an errors occurs.
In your case, simply fill username and password properties in a specific properties file according to the target environment and store this file on the environment.
Then you have just to run the application by specifying this properties file.
For example for windows :
java -jar yourApp-1.0.jar --spring.config.location=file:///D:/application-target-env.properties
Here is the reference documentation about it :
24.2 Accessing command line properties
I am using Kryo to save binary files of user data. The user can open one of their files in my application. I'm not sure if I have a clean approach to detecting whether they tried to open a file of some other type.
Right now, I'm writing a simple FileHeader object to the file before the user's data. The file header has info about what version of the app saved the file.
public void write (UserProject project, File file) throws FileNotFoundException {
OutputStream outputStream = new DeflaterOutputStream(new FileOutputStream(file));
Output output = new Output(outputStream);
kryo.writeObject(output, new FileHeader());
kryo.writeObject(output, project);
output.close();
}
So when I load a file, I can try to deserialize the file header and the user project and catch any Exception that might occur. But doing a catch-all block could hide certain issues I could perhaps react to in a more elegant way that simply showing the user an error no matter the exception. Here's what I'm doing now:
public Project read (File file) throws FileNotFoundException, FileVersionException, UnreadableException {
InputStream inputStream = new InflaterInputStream(new FileInputStream(file));
Input input = new Input(inputStream);
try {
FileHeader fileHeader = kryo.readObject(input, FileHeader.class);
if (fileHeader.fileVersion > CURRENT_FILE_VERSION)
throw new FileVersionException(/* */);
Project project = kryo.readObject(input, Project.class);
return project;
} catch (Exception e){
if (DEBUG) e.printStackTrace();
throw new UnreadableException(e); //caller will show user error msg
} finally {
input.close();
}
}
I suppose there's also a very tiny (infinitesimal?) chance that some file actually loads without throwing an exception, in which case a very unexpected error could happen elsewhere in my application. Not sure if I should worry about this...a user should not expect to open an incorrect file type and have it work correctly.
You could use magic numbers, a set of bytes that describes the type of file. Like .jpg, .pdf, .wav, etc. all have a few bytes at the beginning of each file, so even if these types are saved with different extensions you can check to see if the file's magic number is OK.
Magic Number Description
However, if you're serializing and deserializing you may have to tack on some additional data to the file after serializing and remove it before deserializing.
I am trying to delete a file and then recreate it. First I check to see if the file already exists, then, if it does, I delete it. Then I try to create a new file in the same place with the same name. When I do this I get this error:
java.nio.file.AccessDeniedException: inputLog.txt
However, if the file did not exist before running these three operations, then the file is created without issue.
Here is my code:
final Path INPUTLOGPATH = FileSystems.getDefault().getPath("inputLog.txt");
try {
reader = Files.newBufferedReader(INPUTLOGPATH, charset);
} catch (IOException e) {
reader = null;
}
if (reader != null) {
try {
Files.delete(INPUTLOGPATH);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
Files.createFile(INPUTLOGPATH);
} catch (IOException e) {
e.printStackTrace();
}
First I check to see if the file already exists, then, if it does, I delete it.
Why? Opening the file for output will already do all that. You're just repeating work that the operating system already has to do. Remove all this. You're doing it wrong by not closing the file reader, but it's irrelevant. Don't write unnecessary code.
Then I try to create a new file in the same place with the same name
That is also unnecessary as shown. Just open the file for output when you need it.
As you have it now:
you're opening the file, which is a search, among many other things
you're deleting the file, which is another search
you're creating the file, which is another search
then presumably you're opening the file for output, which requires another search, another deletion, and another creation, internally to the operating system.
Don't do this. Just remove all this code. It accomplishes exactly nothing.
You're also introducing all kinds of timing-window problems by this approach, and you still have to deal with eventual failure at the point where you actually open the file for output.
I need a configuration file (Properties) for this project I'm working on.
The issue is that the Properties instance fails to load from the file (no exceptions, no visible problems) although it can store properly.
Because I have a defaults HashMap, any property that doesn't exist has it's default value placed in the Properties instance, which then stores everything, so that new properties are seamlessly added when the production server is updated.
I've been tracking this bug for hours, and I can't fix it. I've read dozens of questions here on StackOverflow as well as code examples on other sites. Nothing helped.
The one reason I haven't dropped it already and used the DB instead is that the JDBC driver URL, user and password are stored in that file as well. Notice that the file is being read and written to the hard drive.
Since the defaults system puts stuff in place, even if the file doesn't exist when I try to read, after it's saved it appears, but the next run still won't read anything. I noticed the bug after I changed a setting, and checked the file after a few runs, and to my shock, all values were default.
What's currently happening is the following:
1) No matter if the file is there or not, Properties will not load anything.
2) Since there's nothing in the Properties instance, it is filled with defaults.
3) The instance will now save, overwriting the file with the default values.
Here's all the relevant code:
private static Properties getConfig(){
Properties properties = new Properties();
File cfgFile = new File("data/titallus.properties");
try{
if(cfgFile.createNewFile()){
System.out.println("Config file not found. A default config file will be created automatically.");
}
FileReader reader = new FileReader(cfgFile);
FileWriter writer = new FileWriter(cfgFile);
properties.load(reader);
reader.close();
System.out.println(properties); // Debug, always prints '{}'
for(String k : defaults.keySet()){
if(!properties.containsKey(k)){
properties.setProperty(k, defaults.get(k));
}
}
properties.store(writer, "Titallus Configuration File");
writer.close();
}catch(Exception e){
e.printStackTrace();
System.exit(-1);
}
return properties;
}
I have tried everything I could think of, to no avail.
I also have a Properties subclass for multi-language support, which works just fine.
Does anyone have any idea how to fix this, or at least, another approach to this?
FileWriter writer = new FileWriter(cfgFile);
will be erasing your file before you read from it.
You create a FileWriter for the file before you load the file, which clears the existing data.
I hava a tomcat java web application. I want to create a file to store some json data in it. How do I create this file and where will this file be created?
public void insert(UserProfile profile) {
JSONObject jsUser = profile.asJSONObject();
try {
String path = profile.getUsername()+".json";
FileWriter fileWriter = new FileWriter(path);
fileWriter.write(jsUser.toJSONString());
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
How do I create this file ...
Use the standard Java I/O libraries to create and write the file; e.g. you could use a FileWriter.
... and where will this file be created?
It is entirely up to you to decide where you want the file to be created.
However, you need to beware of the possibility that someone might trash your web service by causing it to fill up the file system ... or by causing it to write stuff on top of some (important) existing file. You need a good strategy for dealing with these concerns, but that will depend on the purpose of these files, and the circumstances under which they are written.