I don't know if my mind just fools me or this is really not working.
I need different type of Logging-classes so I created a abstract-class, the only definition that all classes will have the same is the way the writeToLog is handled:
public abstract class LoggerTemplate {
protected String filename ="log/";
protected File logfile;
protected FileWriter fw;
public void writeToLog(String message) {
if(fw != null) {
try {
message = new SimpleDateFormat("dd-MM-hh:mm").format(new Date()) + " " + message;
fw.write(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The concrete sub-classes will implement rest of the logic in their constructor, ie one of them:
public class JitterBufferLogger extends LoggerTemplate {
public JitterBufferLogger() {
super();
filename += new SimpleDateFormat("yyyyddMMhhmm'.log'").format(new Date());
if(!new File("log/").exists())
new File("log").mkdir();
logfile = new File(filename);
try {
logfile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
try {
fw = new FileWriter(logfile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
But when I debug I can see that when calling the writeToLog for a specific logger, it jumps into the LoggerTemplate method, and therefore fw and logfile are null. So it's not working.
Isn't it supposed to work or do I just mess something a bit up and should go into weekend ;-)
It should work, it is normal, that the debugger stepped into the LoggerTemplate class upon entering the writeToLog() method. What is strange that the attributes in the base class have null values.
I have tested your code with the following short test program:
public class Test {
public static void main(String[] args) {
LoggerTemplate lt = new JitterBufferLogger();
lt.writeToLog("Hello");
}
}
After adding fw.flush() to the LoggerTemplate.writeToLog() method just after the fw.write() call, it worked for me, the log file had been created and it contained the log message.
Maybe the new File("log").mkdir() or some other calls throw an exception which you cannot see, because stderr had been redirected somewhere.
So what may be missing?
- filewriter flushing could have helped.
- I can't reproduce the null values with the original code, don't know what happened.
- but as everybody, including me, said: it should work and it does.
Why was nothing in the logfile?
- maybe the flush of fw was missing..
anyhow I wrapped it with a Printwriter:
public abstract class LoggerTemplate {
protected String filename ="log/";
protected File logfile;
protected PrintWriter pw;
public void writeToLog(String message) {
try {
pw = new PrintWriter(new FileWriter(logfile,true));
message = new SimpleDateFormat("dd-MM-hh:mm").format(new Date()) + " " + message + "\n";
pw.write(message);
pw.flush();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and now it's working like it should and was expected to be.
Note that the fw instantiation in the concrete sub-classes is not needed anymore.
Related
I have PVPStats objects stored in PlayerMeta.java:
public static Map <UUID, PVPstats> sPVPStats = new HashMap<>();
I know for sure the map is getting populated with objects that contain the expected vars for each uuid.
I'm trying to write these objects (converted to single lines of strings) into plugins/core/killstats.txt when the server calls onDisable() in Main.java
Along with the Map object, in PlayerMeta.java are also the methods to update and retrieve PVPStats objects from the Map. Those are all working.
The part that is not is working is the write method:
public static void writePVPStats() throws IOException {
BufferedWriter w = new BufferedWriter(new FileWriter("plugins/core/killstats.txt"));
sPVPStats.keySet().forEach(user -> {
try {
System.out.println(sPVPStats);
// stdout = {a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7=a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7:1:0}
w.write(user.toString() + "\n");
w.flush();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
w.close();
}
kill.txt after onDisable() is done:
a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7
Instead it needs to be:
{a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7=a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7:1:0}
For reference, here is the complete PVPStats class.
Lastly, in case it matters / helps, the reader on server launch:
Files.readAllLines(killstats_user_database.toPath()).forEach(line -> {
PVPstats stats = PVPstats.fromString(line);
PlayerMeta.sPVPStats.put(stats.playerid, stats);
});
Source Code:
backend.FileManager.java
backend.PlayerMeta.java
backend.PVPstats.java
events.PVP.java
EDIT
I just tried this with killstats.txt file type nad killstats.txt doesnt have anything in it now.
public static void writePVPStats() throws IOException {
BufferedWriter w = new BufferedWriter(new FileWriter("plugins/core/killstats.txt"));
for (PVPstats object: sPVPStats.values()) {
try {
System.out.println(sPVPStats);
w.write(object.toString() + "\n");
w.flush();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
w.close();
}
Ok so there were multiple issues. I wasn't controlling the flushing of the buffer, I declared the hasmap incorrectly, I wasn't accessing the value part of the hash map, and I wasn't correctly enforcing plain text.
SOLUTION
public static Map <UUID, PVPstats> sPVPStats = new HashMap<UUID, PVPstats>();
public static void writePVPStats() throws IOException {
BufferedWriter w = new BufferedWriter(new FileWriter("plugins/core/killstats.txt"));
for (PVPstats object: sPVPStats.values()) {
try {
System.out.println(sPVPStats);
System.out.println(object.toString());
w.write(object.toString() + "\n");
w.flush();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
w.close();
}
I have a buffered writer which is an instance of FileWriter in java. I have some functions which work like this:
private void a() {
try {
fileMaker("A");
bufferedWriter.write("x");
b();
bufferedWriter.write("z");
} catch (IOException e) {
}
}
private void b() {
try {
fileMaker("B");
bufferedWriter.write("b");
} catch (IOException e) {
}
private FileWriter bufferedWriter;
private void fileMaker(String fileName) {
try {
bufferedWriter = new FileWriter("./artifact/" + fileName + ".txt");
} catch (IOException e) {
System.out.println("there is something wrong in classFileMaker");
}
}
So my problem is, somehow after returning from function b I get a exception and can't write to file "A".
Any idea why?
fileMaker reuses the same bufferedWriter member, so every time you call it you lose the reference to the previous file's writer. A better design would be to return a new instance of a writer from the method and have the caller manage it:
private static FileWriter fileMaker(String fileName) throws IOException {
return new FileWriter("./artifact/" + fileName + ".txt");
}
private void a() {
try (FileWriter bufferedWriter = fileMaker("A")) {
bufferedWriter.write("x");
b();
bufferedWriter.write("z");
} catch (IOException e) {
}
}
private void b() {
try (FileWriter bufferedWriter = fileMaker("B")) {
bufferedWriter.write("b");
} catch (IOException e) {
}
}
I have a class method that logs output to a file and I want more control over format specifying.
public class Logger {
private static boolean FIRST_CALL = true;
public static void log(String content) {
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("debug.txt", !FIRST_CALL)));
if(FIRST_CALL) {
FIRST_CALL = false;
}
out.println(content);
out.close();
} catch (IOException e) {
//exception handling left as an exercise for the reader
}
}
}
I'm not sure how to go about it. changing println to printf creates a whole host of problems.
E.g I call the method as follows:
Logger.log("testval=" + testVal);
Where testVal would be a double for example. It would output 1.9547E-5 but I actually want it in decimal format instead.
Any help appreciated. I'm new to Java.
Take a look at the MessageFormat class.
You can do something like
Logger.log(MessageFormat.format("testval={0}", testVal));
Like printf you can configure the format of your output. See the Javadoc for all the options.
You can use String.format().
In your example:
Logger.log(String.format("testval=%f", testVal));
Well, if to fix your code for a double, I'd write in this way:
private void log(double )
{
// use try-with-resource - it's better
try(PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("debug.txt", !FIRST_CALL))))
{
if(FIRST_CALL) {
FIRST_CALL = false;
}
out.printf("value = %5.7f\n", d);
out.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
and call this code:
log(1.9547E-5)
I am trying to throw my custom exception in java but currently I have had no luck. I have two classes a readWrite class which allows the user to enter the file name and a text to be wrote to the file (via the constructor). It has three methods, write, read and a writeToFile which validates if the file ends in .txt if it does now it should throw my custom exception class stating that "Sorry but this system only accepts .txt files" which I have created in a toString() method in my custom exception. I can not seem to make it work, below is the code, some might be able to help, I hope I have explained properly as I am new to Java, note I have commented out some code as I was trying a few different things to make it work
ReadWrite.java
import java.io.*;
public class ReadWrite
{
private final String file;
private final String text;
public ReadWrite(String file, String text)
{
// initialise instance variables
this.file=file;
this.text=text;
}
private void write() //throws InvalidFileException
{
try {
FileWriter writer = new FileWriter(file);
writer.write(text);
writer.write('\n');
writer.close();
}
catch(IOException e)
{
System.out.print(e);
}
}
public boolean writeToFile()
{
boolean ok;
try{
FileWriter writer = new FileWriter(file);
{
if(file.toLowerCase().endsWith(".txt"))
{
write();
ok = true;
} //if end
else{
ok=false;
//throw new InvalidFileException();
} //else end
}
} //try end
catch(IOException e) {
ok=false;
} // catch end
//catch (InvalidFileException e){
//System.out.println(e.toString());
//}
return ok;
}
public void read(String fileToRead)
{
try {
BufferedReader reader = new BufferedReader(new FileReader(fileToRead));
String line = reader.readLine();
while(line != null) {
System.out.println(line);
line = reader.readLine();
}// while end
reader.close();
}//try end
catch(FileNotFoundException e) {
System.out.println(fileToRead + " the system can not find the file specified");
} //catch end
catch(IOException e) {
e.printStackTrace();
} //catch end
}
}
InvalidFileException.java
import java.io.FileNotFoundException;
import java.io.*;
public class InvalidFileException extends Exception
{
/**
* Constructor for objects of class InvalidFileException
*/
public InvalidFileException(String message)
{
super(message);
}
public String toString()
{
return ("Sorry but this system only accepts .txt files");
}
}
try this:
private void write() throws InvalidFileException {
try {
if(!file.getName().endsWith(".txt") {
throw new InvalidFileException(".txt files only.");
}
FileWriter writer = new FileWriter(file);
writer.write(text);
writer.write('\n');
writer.close();
}
catch(IOException e)
{
// handle exception please.
}
Please note, that you have to override the "getMessage()" Method of Exception in order to print your custom message. Or set it in the super() call.
Overriding the toString() method makes your super() call and therefore your custom (detail) message passed to the exception (in my example ".txt files only.") obsolete, because this string won't be printed anymore.
Below is your requirement:
it does not it should throw my custom exception class stating that
"Sorry but this system only accepts .txt files"
I think you got confused because of toString. You really don't need that toString method. You correctly implemented a InvalidFileException which accepts a String argument.
So, now all you need is throw new InvalidFileException("Sorry but this system only accepts .txt files"); or use whatever String message you want while throwing InvalidFileException.
Please note, if you are throwing an exception from a method and catching it in same method looks illogical unless you are doing because APM (application performance monitoring) tools logging purpose.
As other note, if you are throwing exception like this then you need to add a throw statement in your method signature indicating that this method "may" throw so-and-so exception. So, that called of that method can either re-throw or catch it.
If you are catching the exception somewhere then use getMessage method on the exception object and you will get same message as you placed while throwing the exception, in this case - "Sorry but this system only accepts .txt files"
InvalidFileException extends Exception but you only ever try to catch IOException and FileNotFoundException. I think you meant to have InvalidFileException extend IOException.
I am trying write to a csv file. After the execution of the code bellow the csv file is still empty.
File is in folder .../webapp/resources/.
This is my dao class:
public class UserDaoImpl implements UserDao {
private Resource cvsFile;
public void setCvsFile(Resource cvsFile) {
this.cvsFile = cvsFile;
}
#Override
public void createUser(User user) {
String userPropertiesAsString = user.getId() + "," + user.getName()
+ "," + user.getSurname() +"\n";;
System.out.println(cvsFile.getFilename());
FileWriter outputStream = null;
try {
outputStream = new FileWriter(cvsFile.getFile());
outputStream.append(userPropertiesAsString);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public List<User> getAll() {
return null;
}
}
This is a part of beans.xml.
<bean id="userDao" class="pl.project.dao.UserDaoImpl"
p:cvsFile="/resources/users.cvs"/>
Program compiles and doesn't throw any exceptions but CSV file is empty.
If you're running your app in IDE, the /webapp/resources used for running app will differ from the /webapp/resources in your IDE. Try to log full path to file and check there.
try using outputStream.flush() as the final statement in the first of the try block.
I think you're looking at the wrong file. If you specify an absolute path /resources/users.cvs, then it probably won't be written into the a folder relative to the webapp. Instead, it will be written to /resources/users.cvs
So the first step is to always log an absolute path to make sure the file is where you expect it.
Try with this code, it will at least tell you where the problem lies (Java 7+):
// Why doesn't this method throw an IOException?
#Override
public void createUser(final User user)
{
final String s = String.format("%s,%s,%s",
Objects.requireNonNull(user).getId(),
user.getName(), user.getSurname()
);
// Note: supposes that .getFile() returns a File object
final Path path = csvFile.getFile().toPath().toAbsolutePath();
final Path csv;
// Note: this supposes that the CSV is supposed to exist!
try {
csv = path.toRealPath();
} catch (IOException e) {
throw new RuntimeException("cannot locate CSV " + path, e);
}
try (
// Note: default is to TRUNCATE the destination.
// If you want to append, add StandardOpenOption.APPEND.
// See javadoc for more details.
final BufferedWriter writer = Files.newBufferedWriter(csv,
StandardCharsets.UTF_8);
) {
writer.write(s);
writer.newLine();
writer.flush();
} catch (IOException e) {
throw new RuntimeException("write failure", e);
}
}