Saving to new txt file each time library saved by user - java

How would it be possible to enable my application to save to a new .txt file each time the user wishes to save, as opposed to overwriting the existing one?
I have this code which functions and saves information to a text file:
if(Menu.menuChoice == 1 && Library.ManualList.size() > 0){
Library.displayManualList();
boolean saveYesNo = Console.readYesNo("The ManualKeeper® app is able to save your current library to a '.txt' \nfile in your workspace directory.\n\nWould you like to save the current library? (Y/N):\n");
if(saveYesNo){
try {
FileWriter fw = new FileWriter("Library.txt");
PrintWriter pw = new PrintWriter(fw);
for (int i1 = 0; i1 < Library.ManualList.size(); i1++){
pw.println("-------------------- Index Number: " + i1 + " --------------------");
pw.println(Library.ManualList.get(i1).displayManual());
pw.println("---------------------------------------------------------\n");
}
pw.close();
} catch (IOException e) {
System.out.println("Error! Library unable to save.");
}
System.out.println("\n\n--------------------------------------------------------------------------");
System.out.println("\n Library saved!\n");
System.out.println("--------------------------------------------------------------------------\n");
}
else if(saveYesNo){
System.out.println("\n");
}
Ideally I would like the files to be saved in a numbered fashion, so the user could easily select which .txt file to view, at a later date.

To save it to a new file each time, the file name has to be unique.
You can achieve this in mulitple ways. Some ideas:
Date+Time in file name
Add the current date+time to the file name, this will also be informative as when it was created/saved, and when listing files, newer files will be at the end of the list naturally.
String name = "Library-"
+ new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date()) + ".txt";
As an alternative, you could simply append System.currentTimeMillis() which will preserve natural creation order but will not be as nice looking/informative:
String name = "Library-" + System.currentTimeMillis() + ".txt";
Random String in file name
This might not be as nice looking, but for example:
String name = "Library-" + UUID.randomUUID() + ".txt";
Counter in the file name
The idea is to use a counter in the file name, so the first should be "Library.txt", the next should be "Library (2).txt", the third should be "Library (3).txt" etc.
For this to implement, we have to check existing files to determine the next value of the counter. Here is an example how to do it. This is not optimal, but does the job:
public static Path uniqueFile() {
Path file = Paths.get("Library.txt").toAbsolutePath();
if (!Files.exists(file))
return file;
Path folder = file.getParent();
for (int counter = 2; true; counter++) {
file = folder.resolve(String.format("Library (%d).txt", counter));
if (!Files.exists(file))
return file;
}
}
And using it:
String name = uniqueFile().getFileName().toString();

If the application is made with a GUI, a fileDialog would be best (save if he wants to override the file, save as if he wants to save it to a new file, like a lot of applications have).
In your case you should use a counter and add it to the end of the file like Library1.txt.
If rerun the application, of course this counter variable is reset resp. it is not stored. I would suggest to store this variable (and other attributes like that) in another file, e.g. config.txt
This config.txt file you can read (and parse it like I showed you in a previous answer). So everytime you start your application you read the config.txt file, set the counter. Before exiting the application of course you have to save the counter to the config.txt file.
Just pseudocode:
//load at start of application
counter = loaded from config.txt
//save to a new file
FileWriter fw = new FileWriter("Library" + counter++ + ".txt");
//save counter to config.txt file

Related

Java - Saving to txt file duplicates first entry

I have been working on a small library application which allows manuals to be stored. So far I have implemented code to allow my application to save to an existing text file, I would like the same file to be updated each time the user saves, and not overwritten.
Currently if I enter 1 manual and save the library, the text file is updated. But if I add a second manual to the library then save, the first manual is duplicated in the text file
Here is an example of the text file after a second manual is added:
Here is the code I am using to save:
//Choice 7: Save Library:
if(Menu.menuChoice == 7 && Library.ManualList.isEmpty()){
System.out.println(Messages.addManualFirst);
Menu.displayMenu();
}
else if(Menu.menuChoice == 7){
Library.displayManualList();
boolean saveYesNo = Console.readYesNo("\nThe ManualKeeper® app is able to save your current library to a '.txt' \nfile in your workspace directory.\n\nWould you like to save the current library? (Y/N):\n");
if(saveYesNo){
try {
FileWriter fw = new FileWriter("Library.txt", true);
PrintWriter pw = new PrintWriter(fw);
for (int i = 0; i < Library.ManualList.size(); i++){
pw.println("-------------------- Index Number: " + i + " --------------------");
pw.println(Library.ManualList.get(i).displayManual());
pw.println("---------------------------------------------------------\n");
}
pw.close();
} catch (IOException e) {
System.out.println("Error! Library unable to save.");
}
System.out.println("\n\n--------------------------------------------------------------------------");
System.out.println("\n Library saved!\n");
System.out.println("--------------------------------------------------------------------------\n");
}
else if(saveYesNo){
System.out.println("\n");
}
Menu.displayMenu();
}
If anyone knows how I might be able to get the first manual to stop duplicating, please let me know :)
I'm a little confused, you're saying you don't want to overwrite the file, you want to append to it... And that's exactly what's happening.
The PrintWriter will append to the existing file. So I'm assuming what happens is that on your first run, it creates the initial 'index 0' block. On your subsequent run it just appends to the file, duplicating the first entry.
To avoid this you could just create your file object from scratch every time, eg:
File file = new File("Library.txt");
file.delete();
file.createNewFile();
FileWriter fw = new FileWriter(file, true);
But as your question is described, it seems like the problem you're encountering is exactly what you want..?

Pass multiple files to another class

How to pass multiple files to another class?
I am developing an application which first compresses the image and after that it'll convert it into pdf.
The program which i have written works well seperately ie; it compresses the image and then in another project i use the path where the image are stores to convert it to pdf.
Now i want to have both these codes in the same project and i am encountering the problem where i am creating a loop where i pass the path name one by one. The source path works well but i need to specify the destination path which changes the name dynamically this where i am facing the problem. I have attached the code below please tell me what to do.
System.out.println("before convert");
Conversion cc = new Conversion();
File directory = new File(Success);
File[] files = directory.listFiles();
if(files!=null)
{
for(File f:files){
String path = f.getName();
System.out.println("The Name of file is="+path);
cc.createPdf("path" , "output", true);
System.out.println("the file is ="+output+".pdf");
System.out.println("after convert");
}
}
In the above code i need to change the output file name dynamically here cc.createPdf("path" , "output", true);
A simple implementation would be to keep a counter outside loop and increment it before appending it to output file name
int counter = 0;
for(File f:files){
String path = f.getName();
System.out.println("The Name of file is="+path);
counter++; //increment the counter
cc.createPdf("path" , "output"+counter, true); // append it to output
System.out.println("the file is ="+output+".pdf");
System.out.println("after convert");
}
For more robustness, counter can be replaced by UUID generator, System time in milliseconds etc
Im guessing your having trouble getting a File object with a newly created .pdf extension, you will have to adapt this to your code but it should be pretty straight forward.
File inputFile = new File("c:\\myimage.png");
String fileName = inputFile.getName();
File pdfFile = new File(inputFile.getParent(), fileName.substring(0, fileName.indexOf(".")) +".pdf");
System.out.println(inputFile + " " + pdfFile);
I think you should keep things simple by just appending ".pdf" to the names. The fact that you are processing a directory ensures that the source file names are unique. Hence, the new ".pdf" names would also be unique.
Assuming your output files land in the same directory, it also becomes much easier to sort files by names and know immediately which ".pdf" files correlate to which source files.
So, your output file name simply becomes
String path = f.getName();
String output = path.substring(0, path.lastIndexOf('.')) + ".pdf";

how to append a string to a file that has been selected with JFileChooser in java

I am writing a program that has multiple users, and I want each user to be able to save a file with a filename they choose, but, also append their username or a related key to the file name to help with searching later on. How can I adjust this code to do so?
For example, the user "bob" wants to save a file as "aFile.html". The file I want to actually save would be "aFile_bob.html"
String user = "bob";
// select a file to save output
JFileChooser JfileChooser = new JFileChooser(new File(defaultDirectory));
JfileChooser.setSelectedFile(new File("TestFile.html"));
int i = JfileChooser.showSaveDialog(null);
if (i != JFileChooser.APPROVE_OPTION) return;
File saveFile = JfileChooser.getSelectedFile();
// somehow append "user" to saveFile name here?
FileOutputStream fop = new FileOutputStream(saveFile);
Use the renameTo method, like this:
int lastDot = saveFile.getName().lastIndexOf('.');
String name = saveFile.getName();
String ext = ""; // Might not have a file extension
if(lastDot > 0) { // At least one dot
// Take substring of the last occurrence
ext = saveFile.getName().substring(lastDot);
name = name.substring(0, lastDot);
}
saveFile.renameTo(new File(defaultDirectory + "/" + name + "_" + user + ext));
Using this method, you don't need the FileOutputStream.

Writing to a file without overwriting or appending

I am writing a program in Java where the output is written to a .txt file. Each time I run the program the file is overwritten. I do not want to use the append switch and add data to the file.
I would like to have it so a new file, with the same name, is created each time I run the program. For example, if overflow.txt is the file name, and I run the program three times, the files overflow(1).txt, overflow(2).txt, and overflow(3).txt should be made.
How can this be achieved?
Check if the file exists, if so rename it. Using File.exists and FileUtils.moveFile
You would need to do this recursively until no conflict is found.
Check if the file exists first. If so, modify the name.
String origName = "overflow";
String ext = ".txt";
int num = 1;
file = new File(origName + ext);
while (file.exists()) {
num++;
file = new File(myOrigFileName +"(" + num + ")" + ext);
}
Modify depending on actual requirements. Question is not very clear.
"A new file with the same name" doesn't make sense in most file systems.
In your example, you've got three files with different names:
overflow(1).txt
overflow(2).txt
overflow(3).txt
The bit in brackets is still part of the name. If you want to emulate that behaviour, you'll have to:
Detect the presence of the "plain" filename (if you want to write to that if it doesn't exist)
Start counting at 1, and work out the "new" filename each time by removing the extension, adding the count in brackets, then putting the extension back
Keep counting until you find a filename which doesn't exist
String dirPath = "./";
String fileName = dirPath + "overflow.txt";
if(new File(dirPath + fileName).exist())
{
int counter = 0;
while(new File(dirPath + "overflow(" + ++counter + ").txt").exist());
fileName = "overflow(" + counter + ").txt";
}
When you instanciate the File object, verify if it exists, if it does, just rename it by adding the braces and number, and check again.

Generating the output file through java IO

I have developed a java code that reads files from the folder chosen by the user. It displays how many lines of code are in each file, it reads only .java filesonly and final outcome is shown on console , I was thinking that output to be get displayed on console but along with a text file conataing the same information to be get stored on desktop also, please advise how to that and the name of the file that is generated its name is to be based on timestamp lets assume that name of the output file would be 'output06282012' and that text file should contain the same information that is shown on the console , here is my piece of code...
public static void main(String[] args) throws FileNotFoundException {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new java.io.File("C:" + File.separator));
chooser.setDialogTitle("FILES ALONG WITH LINE NUMBERS");
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
{ Map<String, Integer> result = new HashMap<String, Integer>();
File directory = new File(chooser.getSelectedFile().getAbsolutePath());
int totalLineCount = 0;
File[] files = directory.listFiles(new FilenameFilter(){
#Override
public boolean accept(File directory, String name) {
if(name.endsWith(".java"))
return true;
else
return false;
}
}
);
for (File file : files)
{
if (file.isFile())
{ Scanner scanner = new Scanner(new FileReader(file));
int lineCount = 0;
try
{ for (lineCount = 0; scanner.nextLine() != null; lineCount++) ;
} catch (NoSuchElementException e)
{ result.put(file.getName(), lineCount);
totalLineCount += lineCount;
}
} }
System.out.println("*****************************************");
System.out.println("FILE NAME FOLLOWED BY LOC");
System.out.println("*****************************************");
for (Map.Entry<String, Integer> entry : result.entrySet())
{ System.out.println(entry.getKey() + " ==> " + entry.getValue());
}
System.out.println("*****************************************");
System.out.println("SUM OF FILES SCANNED ==>"+"\t"+result.size());
System.out.println("SUM OF ALL THE LINES ==>"+"\t"+ totalLineCount);
}
}
Now the idea in my mind id for this logic
1) construct the file name you want to use
2) open the file for write
3) each time you call a System.out.println(), make a similar call to write the same message to the file
4) when you are all done, make sure you close the file handle.
I have an rough idea something like this
try{
java.util.Date date= new java.util.Date();
System.out.println(new Timestamp(date.getTime()));
BufferedWriter out = new BufferedWriter(new FileWriter("C://Desktop//output"+new Timestamp(date.getTime())+".txt"));
out.write("some information");
out.close;
}catch(IOException e){
e.printStackTrace();
}
please advise how to that and the name of the file that is generated its name is to be based on timestamp lets assume that name of the output file would be 'output06282012' and that text file should contain the same information that is shown on the console
As far as I can tell, this is the only thing you are actually asking:
Please advise how to that and the name of the file that is generated its name is to be based on timestamp. Lets assume that name of the output file would be 'output06282012' ...
The simple answer is:
String fileName = "output" + new Date().getTime();
You then go on to say:
.... and that text file should contain the same information that is shown on the console
You've got two choices:
You can change where System.out goes to by calling System.setOut(...). (Check the javadoc for details.)
You can create a PrintWriter or PrintStream wrapper for your file stream and write to that instead of writing to System.out.
In my opinion, it is a bad idea to use System.setOut(...) unless you've got no choice. It is a "global action" that affects the entire application. It is better to pass the writer that you want to use as a parameter ...
could you please sow in code as I have done that will clear the understanding
Sorry, I don't write people's programs for them (unless it is an interesting problem!). You need to write and debug the code yourself, using the information provided in the relevant javadocs. You can find the Java documentation online on the Oracle website: http://docs.oracle.com/javase/7/docs/

Categories