Update only the new content in a file all five minutes - java

I get a file personHashMap.ser with a HashMap in it. Here's the code how i create it:
String file_path = ("//releasearea/ToolReleaseArea/user/personHashMap.ser");
public void createFile(Map<String, String> newContent) {
try{
File file = new File(file_path);
FileOutputStream fos=new FileOutputStream(file);
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(newContent);
oos.flush();
oos.close();
fos.close();
}catch (Exception e){
System.err.println("Error in FileWrite: " + e.getMessage());
}
}
Now i want, when the program is running, that all five minutes update the file personHashMap.ser only with the content which changed. So the method i called:
public void updateFile(Map<String, String> newContent) {
Map<String, String> oldLdapContent = readFile();
if(!oldLdapContent.equals(ldapContent)){ // they arent the same,
// so i must update the file
}
}
But now i haven't any ideas how i can realise that.
And is it better for the performance to update only the new content or should i clean the full file and insert the new list again?
Hope you can Help me..
EDIT:
The HashMap includes i.e street=Example Street.
But now, the new street called New Example Street. Now i must update the HashMap in the File. So i can't just append the new content...

Firstly HashMap isn't really an appropriate choice. It's designed for in-memory usage, not serialization (though of course it can be serialized in the standard way). But if it's just 2kb, then go ahead and write the whole thing rather than the updated data.
Second, you seem to be overly worried about performance of this rather trivial method (for 2kb the write will take mere milliseconds). I would be worried more about consistency and concurrency issues. I suggest you look into using a lightweight database such as JavaDB or h2.

Use the constructor FileOutputStream(File file, boolean append), set the boolean append to true. It will append the text in the existing file.

You can call the updateFile method in a loop and then call sleep for 5 minutes (5*60*1000 ms).
Thread.Sleep(300000); // sleep for 5 minutes
To append to your already existing file you can use :
FileOutputStream fooStream = new FileOutputStream(file, true);

Related

Java 11 handle unmodifiable map

I have a class to process some files which is uploaded zipped.
And a method to unzip and fill a HashMap and convert to an Collection.unmodifiableMap.
public class MyClass extends HttpServlet {
...
private Map<String, String> rnaseqfiles = new HashMap<>();
...
private void processZipFile(String zipfile) throws Exception {
String fileName = zipfile;
byte[] buffer = new byte[1024];
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(fileName))) {
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
File newFile = new File(diretorio, zipEntry.toString());
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory " + newFile);
}
} else {
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
rnaseqfiles.put(zipEntry.toString(), newFile.getAbsolutePath());
}
zipEntry = zis.getNextEntry();
}
rnaseqfiles = Collections.unmodifiableMap(rnaseqfiles);
zis.closeEntry();
zis.close();
}
}
...
}
When I test with a small example, it works nicely, but when I try with the real case I got this kind of error.
java.lang.UnsupportedOperationException
at java.base/java.util.Collections$UnmodifiableMap.put(Collections.java:1457)
I found some hints to deal with it but I don't know exactly what to do.
Any help is appreciated
servlets are quite annoying. Think of the notion that any given servlet is likely going to run many times, and probably many times simultaneously, as various users hit your site.
They are the worst of both worlds: The servlet spec does not guarantee that the system initializes a new object for every request (meaning, it is possible that many different requests, some even simultaneous, are all using the same fields), but it als does not guarantee the opposite either: The system is free to do so.
Conclusion: Fields in servlets are pretty much useless. But you have one, and it's causing troubles: One 'run' overwrites your mutable hashmap with an immutable one, and then the next servlet tries to add stuff to this now immutable map.
The fix is generally to just get rid of servlets. There are better ways to write web apps these days, such as spark, DropWizard, Spring, and many others.
If you insist, then your servlets should not have any fields. If you desire them, your servlet code should simply make a new object and then invoke whatever you want there - your doGet and friends are mostly just oneliners of the form new ActualHandler(req, res).go() or similar. Now you actually have one instance per request.
Or, just.. write the code so that no fields are needed. I don't see why you need a field here, for example. Your current code does;
Receive the request and parse stuff out (you didn't paste this part)
That code evidently invokes processZipFile which returns nothing, but conveys data back using a field. (This does not work in servlets).
Your request handling code then uses that field for stuff.
Seems easy to replace that - don't have a field, have the processZipFile method return that map instead.

Save JList into Txt File

After searching for an answer for hours I decided to ask it here, since the solutions I found didn't work.
I have a simple GUI to register a persons first/last name and date of birth. After entering the values, the data is listed in a JList. Now I want to save the data from the JList into a Txt file. But I can't find a way to get the data from the JList.
public void save(){
try(BufferedWriter bw = new BufferedWriter(new FileWriter("jlist.txt")))
{
/* Here should be the part, where I get the data from the JList */
bw.write(person.getNachname() + " ; " + person.getVorname() + " ; " + person.getDate() + "\n");
} catch (Exception speichern) {
speichern.printStackTrace();
}
}
Later I want to take the created Txt file and load it back into the same JList.
Maybe there is even a better way to do this but I haven't found something.
Some tips would be helpful :)
There is no JList method that does this for you.
You need to get the data from the ListModel.
You get the ListModel from the JList using the getModel() method.
You need to write a loop to:
get each element from the ListModel using the getElementAt(...) method.
convert the element to a String and write the data to your file.
Some tips would be helpful
Not related to your question, but typically data like this would be displayed in a JTable. Then you have a separate column for each of the first name, last name and date. Read the section from the Swing tutorial on How to Use Tables for more information.
As camickr point out there is no method implemented for what you a trying to achieve, instead there is a combination of things that you could do for archiving your goal.
You are facing the problem of data persistence. In now-a-days for small|medium|big size industrial applications the recommended approach is to relay on databases. I guess that is out the scope for one person that is starting to code, so using files for storing info is OK but is not straightforward.
In your case, if your application is for non-commercial purposes I would suggest to use the default mechanism for serializing and deserializing objects that comes bundled with the platform. With this you could write an entire object (including its data, a.k.a. its state) to a file on a disk, and later retrieve it with few lines codes. There are details about how the object gets serialize ("translate object to bits") and deserialized ("translate bits to object") that doesn't comes into place right now, but is well to advice to study them in the future if you planning to use this method in a commercial application.
So I suggest that you load and store the information of your application on start-up and shutdown respectively, thus only one load and store per application instance, while the application is active work with the data on memory. THIS is the simplest approach you could have in any application, and for that reason I suggest to start with this ideal scenario.
So, I say a lot of things but let's goes to the code that shows an example of storing (serialize) and loading (deserialize)
import java.io.*;
import java.util.*;
class Person implements Serializable {
String name;
int birthDate;
public Person(String name, int birthDate) {
this.name = name;
this.birthDate = birthDate;
}
}
class Main {
public static void main(String[] args) {
Collection<Person> collection = createExampleCollection();
System.out.println(collection);
storeCollection(collection, "persons.data");
Collection<Person> otherCollection = loadCollection("persons.data");
System.out.println(otherCollection);
}
private static Collection<Person> createExampleCollection() {
Collection<Person> collection = new ArrayList<Person>();
collection.add(new Person("p1",0));
collection.add(new Person("p2",10));
collection.add(new Person("p2",20));
return collection;
}
// here I'm doing two separated things that could gone in separate functions, 1) I'm converting into bytes and object of an specific class, 2) saving those bytes into a file on the disk. The thing is that the platform offers us convenient objects to do this work easily
private static void storeCollection(Collection<Person> collection, String filename) {
try {
FileOutputStream fos = new FileOutputStream(filename);
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject(collection);
out.close();
fos.close();
} catch (IOException i) {
i.printStackTrace();
}
}
// again there two things going on inside, 1) loading bytes from disk 2) converting those bits into a object of a specific class.
private static Collection<Person> loadCollection(String filename) {
try {
FileInputStream fis = new FileInputStream(filename);
ObjectInputStream in = new ObjectInputStream(fis);
Collection<Person> persons = (Collection<Person>) in.readObject();
in.close();
fis.close();
return persons;
} catch (Exception i) {
i.printStackTrace();
return null;
}
}
}
You should try to use the functions of loadCollection and storeCollection on start-up and shutdown respectively.
I made this code with comments for jButton and jList in jFrame, Button saves text Items to File from jList.
private void btnSaveActionPerformed(java.awt.event.ActionEvent evt) { //jButton name: "btnSave"
try { //trying to save file
BufferedWriter bw = new BufferedWriter(new FileWriter("data.txt")); //file where I store the data of jList1 (file will be stored at: C:\Users\%username%\Documents\NetBeansProjects\<ThisProjectName>\data.txt) (if You use NetBeans)
for (int i=0; i<jList1.getModel().getSize(); i++){ //opens a cycle to automatically store data of all items
bw.write(jList1.getModel().getElementAt(i)); //writing a line from jList1
bw.newLine(); //making a new line for the next item (by removing this line, You will write only one line of all items in file)
} //cycle closes
bw.close(); //file writing closes
} catch (IOException ex) { //catching the error when file is not saved
Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex); //showing the error
} //Exception closes
} //Action closes

Serialization Overwriting Data

I have a program I'm making for a small business which is implementing serializable on a linkedList to save data. This all works fine, until I have two staff members try and add more data to the list and one ends up overwriting the other.
JButton btnSaveClientFile = new JButton("Save Client File");
btnSaveClientFile.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
// add new items to list
jobList.add(data);
.
.
.
Controller.saveData();
}
});
btnSaveClientFile.setBounds(10, 229, 148, 23);
frame.getContentPane().add(btnSaveClientFile);
This method results in one overwriting the other, so I tried doing it like this
JButton btnSaveClientFile = new JButton("Save Client File");
btnSaveClientFile.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
Controller.retrieveData();
// add new items to list
jobList.add(data);
.
.
.
Controller.saveData();
}
});
btnSaveClientFile.setBounds(10, 229, 148, 23);
frame.getContentPane().add(btnSaveClientFile);
And when I use this one, I get no data added to the list at all. Here are my Serialization methods. This one is used to save my data.
// methods to serialize data
public static void saveData() {
System.out.println("Saving...");
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream("Data.bin");
oos = new ObjectOutputStream(fos);
oos.writeObject(myOLL);
oos.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
And this one is used to collect my data
public static void retrieveData() {
// Get data from disk
System.out.println("Loading...");
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream("Data.bin");
ois = new ObjectInputStream(fis);
myOLL = (OrderedLinkedList) ois.readObject();
ois.close();
} catch (Exception ex) {
System.err.println("File cannot be found");
ex.printStackTrace();
}
}
How do I make it so I can save data to my file from two different computers at a similar time, without one overwriting the other?
This is a demo (and not meant to be used in this crude way) how to acquire a lock on file /tmp/data.
RandomAccessFile raf = new RandomAccessFile( "/tmp/data", "rw" );
FileChannel chan = raf.getChannel();
FileLock lock = null;
while( (lock = chan.tryLock() ) == null ){
System.out.println( "waiting for file" );
Thread.sleep( 1000 );
}
System.out.println( "using file" );
Thread.sleep( 3000 );
System.out.println( "done" );
lock.release();
Clearly, reading a sequential file, mulling over it for some time and then rewriting or not is prohibitive if you require a high level of concurrency. That's why such applications typically use database systems, the client-server paradigm. A free-for-all on the file system isn't tolerable except in rare circumstances. Your organization may be able to assign updates of the data to one person at a time, which would simplify matters.
add more data to the list and one ends up overwriting the other.
This is how files work by default, in fact the ObjectOutputStream doesn't support an "append" mode. Once you have closed the stream, you can't alter it.
How do I make it so I can save data to my file from two different computers at a similar time, without one overwriting the other?
You have two problems here
how to write to a file twice without losing information.
how to co-ordinate writes between processes without one impacting the other.
For the first part, you need to read the contents of the list first, add the entries you wand to add, and write out the contents again. OR you can change the file format to one which supports appending.
For the second part, you need to use locking of some kind. A simple way to do this is to create a lock file. You can create a second file atomically e.g. file.lock and the one which succeeds in creating the file holds the lock, that process alters the file and deletes the lock which finished. Some care needs to be taken to ensure you always remove the lock.
Another approach is to use file locks. You have to take care not to delete the file in the process however this has the benefit that the OS will clean up the lock if your process dies.

Add comment to an ARFF file

this is my first question in this forum....
I'm making adata-mining application in java with the WEKA API.
I make first a pre-processing stage and when I save the ARFF file i would like to add a couple of lines (as comments) specifing the preprocessing task that i have done to the file...
the problem is that i don't know how to add comments to an ARFF file from the java WEKA API.
To save the file i use the class ArffSaver like this...
try {
ArffSaver saver = new ArffSaver();
saver.setInstances(dataPost);
saver.setFile(arffFile);
saver.writeBatch();
return true;
} catch (IOException ex) {
Logger.getLogger(Preprocesamiento.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
I would be really greatfull if someone could give some idea...
thanks!
You should AVOID writting comments on an .arff file, even more when writting it from Java. These files are very "parser-sensitive". The Weka API to create these files is restrictive for this particular reason.
Even though, you can always add your comments manually with the % symbol. This said, I wouldn't recommend you writting anything more than instances, attributes and values into an .arff file. ;-)
I don't see a reason to not write comments into the header of an ARFF file. The specification clearly says:
Lines that begin with a % are comments.
So while it is technically valid, it can be difficult if you want to use the ArffSaver#setFile method. This method does a lot of (convenient, but somewhat arbitrary and unspecified) work internally, until it finally calls
setDestination(new FileOutputStream(m_outputFile));
If this is not required, the easiest option is to write directly to an OutputStream, which then can simply be set as the destination for the ArffSaver. This can be wrapped in a small helper method, for example, like this:
static void writeArff(
Instances instances,
List<String> commentLines,
OutputStream outputStream) throws IOException
{
ArffSaver saver = new ArffSaver();
saver.setInstances(instances);
if (commentLines != null && !commentLines.isEmpty())
{
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(outputStream));
for (String commentLine : commentLines)
{
bw.write("% " + commentLine + "\n");
}
bw.write("\n");
bw.flush();
}
saver.setDestination(outputStream);
saver.writeBatch();
}
When calling it like this
List<String> comments = Arrays.asList("A comment", "Another one");
writeArff(instances, comments, outputStream);
then the given comments will be inserted at the top of the ARFF file.

Writing multiple files with Spring Batch

I'm a newbie in Spring Batch, and I would appreciate some help to resolve this situation: I read some files with a MultiResourceItemReader, make some marshalling work, in the ItemProcessor I receive a String and return a Map<String, List<String>>, so my problem is that in the ItemWriter I should iterate the keys of the Map and for each one of them generate a new file containing the value associated with that key, can someone point me out in the right direction in order to create the files?
I'm also using a MultiResourceItemWriter because I need to generates files with a maximum of lines.
Thanks in advance
Well, finaly got a solution, I'm not really excited about it but it's working and I don't have much more time, so I've extended the MultiResourceItemWriter and redefined the "write" method, processing the map's elements and writing the files by myself.
In case anyone out there needs it, here it is.
#Override
public void write(List items) throws Exception {
for (Object o : items) {
//do some processing here
writeFile(anotherObject);
}
private void writeFile (AnotherObject anotherObject) throws IOException {
File file = new File("name.xml");
boolean restarted = file.exists();
FileUtils.setUpOutputFile(file, restarted, true, true);
StringBuffer sb = new StringBuffer();
sb.append(xStream.toXML(anotherObject));
FileOutputStream os = new FileOutputStream(file, true);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(os, Charset.forName("UTF-8")));
bufferedWriter.write(sb.toString());
bufferedWriter.close();
}
And that's it, I want to believe that there is a better option that I don't know, but for the moment this is my solution. If anyone knows how can I enhance my implementation, I'd like to know it.

Categories

Resources