Writing in same file from different classes in java - java

How do I write in same text file from different classes in java.
One of the class call method from another class.
I do not want to open BufferedWriter in each class, so thinking if there is a cleaner way to do this ?
So essentially, I want to avoid writing the following code in each class
Path path = Paths.get("c:/output.txt");
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
writer.write("Hello World !!");
}

A good way of doing this is to create a central writing class, that maps from a file name to a reader/writer-object. For example:
public class FileHandler {
private static final Map<String, FileHandler> m_handlers = new HashMap<>();
private final String m_path;
private final BufferedWriter m_writer;
// private final BufferedReader m_reader; this one is optional, and I did not instantiate in this example.
public FileHandler (String path) {
m_path = path;
try {
m_writer = Files.newBufferedWriter(path);
} catch (Exception e) {
m_writer = null;
// some exception handling here...
}
}
public void write(String toWrite) {
if (m_writer != null) {
try {
m_writer.write(toWrite);
} catch (IOException e) {
// some more exception handling...
}
}
}
public static synchronized void write(String path, String toWrite) {
FileHandler handler = m_handlers.get(path);
if (handler == null) {
handler = new FileHandler(path);
m_handlers.put(path, toWrite);
}
handler.write(toWrite);
}
}
Be aware that this behavior does not close the file writers at any point, because you don't know who else is currently (or later on) writing. This is not a complete solution, just a strong hint in a good direction.
This is cool, because now you can "always" call FileHandler.write("c:output.txt", "Hello something!?$");. The FileHandler class could be extended (as hinted) to read files too, and to do other stuff for you, that you might need later (like buffer the content, so you don't have to read a file every time you access it).

Related

How to write data in file in specific format with FileOutputStream and PrintWriter

I have class Artical:
first variable is code of artical, second variable is name of article and third is price of article.
public class Artical {
private final String codeOfArtical;
private final String nameOfArtical;
private double priceOfArtical;
public Artical(String codeOfArtical, String nameOfArtical, double priceOfArtical) {
this.codeOfArtical= codeOfArtical;
this.nameOfArtical= nameOfArtical;
this.priceOfArtical= priceOfArtical;
}
public void setPriceOfArtical(double priceOfArtical) {
this.priceOfArtical= priceOfArtical;
}
public String getCodeOfArtical() {
return codeOfArtical;
}
public String getNameOfArtical() {
return nameOfArtical;
}
public double getPriceOfArtical() {
return priceOfArtical;
}
}
I want in main class to write something like:
Artical a1 = new Artical("841740102156", "LG Monitor", 600.00);
new ShowArticalClass(a1).do();
new WriteArticalInFileClass(new File("baza.csv"), a1).do();
so that data in file will be written in format like this:
841740102156; Monitor LG; 600.00;
914918414989; Intel CPU; 250.00;
Those 2 classes ShowArticalClass and WriteArticalInFileClass arent important, those are abstract classes.*
So my question is: How do I set format to look like this, where every line is new Artical.
A very naive implementation can be the following:
Create a class that in turn creates a CSVWriter (assuming you want to write to a CSV). That class will expose a public method allowing you to pass in a path where the desired csv file lives as well as the Artical object you want to write to this file. Using that class you will format your data and write them to the file. An example of this could be:
public class CsvWriter {
private static final Object LOCK = new Object();
private static CsvWriter writer;
private CsvWriter() {}
public static CsvWriter getInstance() {
synchronized (LOCK) {
if (null == writer) {
writer = new CsvWriter();
}
return writer;
}
}
public void writeCsv(String filePath, Artical content) throws IOException {
try (var writer = createWriter(filePath)) {
writer.append(getDataline(content)).append("\n");
}
}
private String getDataline(Artical content) {
return String.join(",", content.getCode(), content.getName(), Double.toString(content.getPrice()));
}
private PrintWriter createWriter(String stringPath) throws IOException {
var path = Paths.get(stringPath);
try {
if (Files.exists(path)) {
System.out.printf("File under path %s exists. Will append to it%n", stringPath);
return new PrintWriter(new FileWriter(path.toFile(), true));
}
return new PrintWriter(path.toFile());
} catch (Exception e) {
System.out.println("An error has occurred while writing to a file");
throw e;
}
}
}
Note that this will take into account where the file provided is already in place (thus appending to it). In any other case the file will be created and written to directly.
Call this write method in a fashion similar to this:
public static void main(String... args) throws IOException {
var artical = new Artical("1", "Test", 10.10);
CsvWriter.getInstance().writeCsv("/tmp/test1.csv", artical);
var artical2 = new Artical("2", "Test", 11.14);
CsvWriter.getInstance().writeCsv("/tmp/test1.csv", artical2);
}
With that as a starting point you can go ahead and modify the code to be able to handle list of Artical objects.
If you really need to support CSV files though I would strongly recommend into looking at the various CSV related libraries that are out there instead of implementing your own code.

Can I implement Serializable which exists and compiled class in java(geotools)?

I wrote program for reading and displaying GIS shape files by GeoTools, and I want to save the state of my program.
Main class.java
Project myproject=new Project();
myproject.mapLayers=this.frame.getMapContext().getLayers();
Project.java
import org.geotools.map.MapLayer;
public class Project implements Serializable{
public String name;
public MapLayer[] mapLayers;
public void save(String projectname){
ReadWriteObject.writeObject(projectname+".gpr",this);
}
public Project load(String projectname){
return (Project)ReadWriteObject.readObject(projectname);
}
}
ReadWriteObject
public class ReadWriteObject {
public static boolean writeObject(String filename, Object obj){
try {
FileOutputStream f = new FileOutputStream(new File(filename));
ObjectOutputStream o = new ObjectOutputStream(f);
// Write objects to file
o.writeObject(obj);
o.close();
f.close();
} catch (FileNotFoundException e) {
System.out.println("File not found");
return false;
} catch (IOException e) {
System.out.println("Error initializing stream");
return false;
}
return true;
}
}
Error occurred DefaultMapLayer is not Serializable.
How do I save my programs state in java?
I would simply write out in some format (XML, JSON) the layers, styles that went into your map and then read that back in again to recreate the map. You don't actually need to store the entire state of the program.
Alternatively, you can propose a change to the source code to add Serialize to class. Ideally you should find all of the necessary classes that will need serializing that currently don't implement Serialize and submit a single pull request.

field goes out of scope java

I have some problem with multithreaded application. I want to load the data from a CSV like file and store it in a buffer for later retrieval.
Seems like the animals list goes out of scope when the thread is finished(?), there is something about java threading I don't understand and will be grateful for assistance.
The way it's invoked:
ParseCSV parser = new ParseCSV(null);
EventQueue.invokeLater(parser);
System.err.println("printing!");
EDIT - as requested, this is the part that fails - the content of praser buffer is empty at this point. I thought that if I use new keyword in the parser, the content of animals will be persistent.
while(parser.hasNext()){
System.err.println("#");
System.err.println(parser.getNext().toString());
}
The parser class:
public class ParseCSV implements Runnable{
private String path = null;
private File file = null;
private static Logger log = LogManager.getLogger(ParseCSV.class.getName());
private volatile ArrayList<Animal> animals = new ArrayList<Animal>();
private int pointer =0;
public ParseCSV(String path) {
animals = new ArrayList<Animal>(); //tried to reinitialize, didn't help this is where the problem occurs
if(path == null){
JFileChooser jfc = new JFileChooser();
jfc.showOpenDialog(null);
file = jfc.getSelectedFile();
this.path = file.getAbsolutePath();
}
else {
this.path = path;
}
log.debug("Initialized file parser for " + this.path);
}
#Override
public void run() {
log.debug("begining file parse");
System.err.println("runnner");
try {
Scanner fileScan = new Scanner(this.file);
while(fileScan.hasNextLine()){
parseLine(fileScan.nextLine());
}
fileScan.close();
} catch (FileNotFoundException e) {
log.error("Exception occured: " + e.getMessage() + "\nstack:\n" + e.getStackTrace());
System.err.println("Exception: " + e.getMessage());
e.printStackTrace();
}
}
private void parseLine(String nextLine) {
Scanner lineScanner = new Scanner(nextLine);
lineScanner.useDelimiter("\\s\\|\\s");
if(lineScanner.hasNext()){
Animal an = new Animal(lineScanner.next(), //person
lineScanner.next(), //animal
Integer.parseInt(lineScanner.next()), //emp-number
lineScanner.next(), //date
Integer.parseInt(lineScanner.next()), //ani-number
lineScanner.next());
animals.add(an); //contract ID
System.err.println(an.toString()); //prints correct result!
}
lineScanner.close();
}
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public boolean hasNext(){
System.err.println("size of data = " + animals.size());
if(animals.size() == pointer || animals.isEmpty()) return false;
else return true;
}
public Sale getNext(){
if(animals.size() == pointer) return null;
return animals.get(pointer++);
}
}
EDIT - added comments to point out where the problem appears
You need to wait for the Parser thread to finish (currently both are happening at same time) This may be the reason that your program is not printing anything.
you can try adding some logging statements and check if the sequence is proper on not.
EventQueue#invokeLater adds a task to the event queue, so it might not be done when coming to the next line.
Use EventQueue#invokeAndWait instead, it waits for the task to finish.
There are a few problems with your code. Some of them actually leads to the problem, and some just shows that you don't really understand what you are trying to do.
private volatile ArrayList<Animal> animals = new ArrayList<Animal>();
Why are you using volatile on this? Each thread have their own animals list, so they are just used by one thread. If your main class had a animals model that everyone added to, you would have needed to make it volatile, since multiple threads could access it.
animals = new ArrayList<Animal>(); //tried to reinitialize, didn't help this is where the problem occurs
This isn't going to change anything. It might be useful if you think the method could get called multiple times and you want a fresh list each time, but it's probably just a waste.
Now onto the real problem:
When you call a thread it's because you want it to run in the background and not stop the main program execution. Then you can get back to the result at some time when it's actually finished. As people have said, if you just want a new thread without it really running in the background you could do EventQueue#invokeAndWait, but for your case this isn't the solution.
You could use the observer pattern. To do this you make an interface that has a notify method (call it parseListner or something). The parser has a list of parseListerners. When the parser finish parsing it tells all the listeners (by calling a method on the interface). So you end up with code sort of like this:
public interface ParseListner{
void fileParsed(String fileName, List<Animal> animals);
}
public class Main implements ParseListner{
public void main(){
ParseCSV parser = new ParseCSV(this);
EventQueue.invokeLater(filePath, parser);
}
public void fileParsed(String fileName, List<Animal> animals){
System.Out.Println(doneParsing);
}
}
public class ParseCSV implements Runnable{
List listners = new ArrayList<>();
public ParseCSV(String path, ParseListner caller) {
listner.add(caller)
}
#Override
public void run() {
//all the parsestuff
for(ParseListner p : listners)
p.parsedFile(fileName, animals);
}
I used a list because it's almost always useful (so you can do multiple things when it's done).

Came across this code & I'm wondering why this static helper method is needed?

I did not write this code, All credit goes to the person that is hosting the link. So here is a link to the code and the guy who wrote it is listed on github also... Link -Github SourceCode-
Here is the method preview: (see class below)
//helper method
public static List readFile(String filePath) throws IOException {
return new TextFileReader(filePath).readFile();
}
Wait a second, I think I may get it now, it's just so someone can invoke the readFile() method without having a dependancy to this object, or am I wrong?
and here is a link to the project on git, if anyone wants a lower level view of the project.
I have searched around and I only see helper methods breaking up larger tasks, which was my initial understanding of them.
However, I was on github, and found this: (method brought up from bottom of page for easy viewing, but is also in the class code. Plus here is a link to the git if anyone wants to take a better look... Thank you for any replies or edits that
looked normal until the static helper method at the bottom of the page
public class TextFileReader implements FileReaderStrategy<String> {
private static final FileType FILE_TYPE = FileType.TEXT_FILE;
private String filePath;
public TextFileReader(String filePath) {
this.filePath = filePath;
}
#Override
public List<String> readFile() throws IOException {
List lines = new ArrayList();
BufferedReader in = null;
try {
in = new BufferedReader(
new FileReader(filePath));
String line = in.readLine();
while (line != null) {
lines.add(line);
line = in.readLine();
}
} catch(IOException ioe){
throw ioe;
}finally{
if(in != null){
in.close();
}
}
return lines;
}
//helper method
public static List readFile(String filePath) throws IOException {
return new TextFileReader(filePath).readFile();
}
}
You are correct. Although I would say that it's so the method can be called on the Class rather than on an object, or instance, of the class.
For example, static methods can be called like this:
TextFileReader.readFile(<filepath>);
without having to first create an instance of the class.

How to communicate between two command Handlers

Say I have a Handler that is logging data to some object via a listener.
public Object execute(ExecutionEvent event) throws ExecutionException {
IHandlerService service;
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
try {
RecordingDocument d = new RecordingDocument("TestProject", "Tester", true);
d.record();
MessageDialog.openInformation(
window.getShell(),
"JavaTV",
"You are now recording.");
} catch (CoreException e) {
e.printStackTrace();
}
return null;
}
This object is created when one of the menu items is selected and begins logging to a data structure inside the object.
How do I retrieve this document from a different handler? I need this if someone uses the menu to stop the recording.
It seems like a general Java question on how to make some object accessible by other objects. Obviously, you need to store it in a place, where it can be accessed by others (provide a getter, put to the registry, store to the DB, serialize to the hard drive, etc). There are many design patterns to solve your problem, so no ideal answer can be provided.
You can't, probably use getters, because as you mentioned Handler is created at the time menu is executed. I think that handler is not recreated each time, but only on first access, so you could make an instance variable in the handler, but this doesn't seem right.
Storing to a DB and serialization is probably way too overkill at this stage for you, so I would suggest you to put object to the registry, using Registry pattern (think of it as a global cache). So, here is what you could do:
public class DocumentsRegistry {
private Map<String, RecordingDocument> registry = new HashMap<String, RecordingDocument>();
private static DocumentRegistry instace = new DocumentRegistry();
public static DocumentRegistry getInstance() {
return instance;
}
public void registerDocument(String key, RecordingDocument document) {
registry.put(key, document);
}
public RecordingDocument getDocument(String key) {
return registry.get(key);
}
}
// your handler
public static final String DOCUMENT_KEY = "DOCUMENT";
public Object execute(ExecutionEvent event) throws ExecutionException {
IHandlerService service;
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
try {
RecordingDocument d = new RecordingDocument("TestProject", "Tester", true);
d.record();
MessageDialog.openInformation(
window.getShell(),
"JavaTV",
"You are now recording.");
DocumentsRegistry.getInstance().registerDocument(DOCUMENT_KEY, d);
} catch (CoreException e) {
e.printStackTrace();
}
return null;
}
// another handler
public Object execute(ExecutionEvent event) throws ExecutionException {
RecordingDocument d = DocumentsRegistry.getInstance().getDocument(DOCUMENT_KEY);
// do something with it
return null;
}
If you want to support concurrent recordings, so that many documents can be opened at the same time, you would need a solution for generating keys per document.

Categories