Writing to a file without overwriting or appending - java

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.

Related

Put Brackets around filename

This is a correction of my previous question Put brackets around filename for Excel formula
My project is based on Apache POI.I'm trying to use a formula on a cell.
My formula is as follows.
sheet7.createRow(0).createCell(0).setCellFormula("+'C:\\Users\\Desktop\\[Test.xlsx]Average_Graph'!A2");
Im using a JFileChooser, which allows users to select the file. Therefore the filepath will be changed every time the program is used.
From the JFileChooser, I'm getting a filepath as follows.
String filepath= "C:\\Users\\Desktop\\Sheet.xlsx"`
In order to work the formula correctly, the filepath should be in following format.
"C:\\Users\\Desktop\\[Sheet.xlsx]"
How Can I Change the string which I'm getting from the JFileCHooser to run the formula correctly?
In previous question, I mistakenly typed C:\Users\Desktop[Sheet.xlsx] instead of C:\Users\Desktop\[Sheet.xlsx]
The answers gave me the output which i've mentioned. But I need the Output as C:\Users\Desktop\[Sheet.xlsx]
Please help.
If you want to solve this by directly altering the file path, you may use String#replaceAll:
String filepath = "C:\\Users\\Desktop\\Sheet.xlsx";
filepath = filepath.replaceAll("(?<=\\\\)([^\\\\]+)$", "[$1]");
System.out.println(filepath);
C:\Users\Desktop\[Sheet.xlsx]
Demo
File names won't have \backslashes in them, so we can assume that our filename begins after the last backslash and ends at the end of the string.
We can use this:
String filepath = "C:\\Users\\Desktop\\Sheet.xlsx";
String dir = filepath.substring(0, filepath.lastIndexOf("\\"+1));
String filename = filepath.substring(filepath.lastIndexOf("\\"+1));
filepath = dir + "[" + filename + "]";
Or a shorter version:
String filepath = "C:\\Users\\Desktop\\Sheet.xlsx";
filepath = filepath.substring(0, filepath.lastIndexOf("\\"+1)) +
"[" + filepath.substring(filepath.lastIndexOf("\\"+1)) + "]";

Not able to execute Unix commands containing variables using JSch library

I have written a Java program which when executed would open an upload wizard through which a user can select a file. After doing this, the selected file would be transferred/uploaded to a Unix box to a directory which the user specifies and processed further. Here are the steps/actions:
Browse the file through the upload wizard
After this the program would prompt for a new directory to be created, the name of which the user can give as an input
The program creates a new directory (source) and places the selected file in the created directory of the server
Show the contents of the transferred file in the source (using cat command)
Prompt the user for a new directory to be created (target), copy the file from the source to target and subsequently show the contents of the file in the target, all with Linux commands.
I'm able to upload the file to the source (step 3). However, the 4th and the 5th steps don't work. Here's the code:
String cmd1 = "cat" + " " + path + s1 + "/" + file;
System.out.println(cmd1);
((ChannelExec)channel).setCommand(cmd1);
Scanner in2 = new Scanner(System.in);
System.out.println("Enter d target directory");
String s = in2.nextLine();
String path2 = "/e/f/";
String d = path2 + s;
String cmd2 = "mkdir" + " " + path2 + s;
((ChannelExec)channel).setCommand(cmd2);
String src = p + "/" + file;
String cmd3 = "cp" + " " + path + s1 + "/" + file + " " + path2 + s;
((ChannelExec)channel).setCommand(cmd3);
String destpath = d + "/" + file;
String cmd4 = "cat" + " " + path2 + s + "/" + file;
I'm not able to make the program work with variables (for user inputs) in the command. However, hardcoded strings like, for eg. cat /a/b/file seems to be able to work.
Could any one please help me in this regard?
From your snippet i guess channel is a ChannelExec, which is a channel intended for just issuing commands and does not work like a shell (that use-case is handled by the shell channel, which allocates a pseudo-tty).
In your case I'd simplify the code and not using variables at all. Otherwise, if you absolutely need them, you could:
if the variable is defined your Java program call ChannelExec.setEnv(name, value)
if the variable is defined on the target host, ensure it's in the right place, for example a file sourced when a non-interactive SSH session is spawned. A good place could be .bashrc but you should check your system documentation (and maybe this other answer)
I think the problem is in some mess with variables values (variable d is created but almost not used) and final / character. And I don't know the p value.
I would start adding a println for cmd2 and cmd3 before executing them because I think there will be a missing / in some place, or perhaps two / where should be only one depending on what the user types, and doing some normalization of directories so they always have a final /, or they never have, but I would like to be sure that whatever the user inputs or the parameters have, all directory names are consistent.
Directory names, user input and final / are always a pain...

Saving to new txt file each time library saved by user

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

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";

File.renameTo() doesn't have any effect

I'd like to be able to rename a list of folders in order to remove unwanted characters (a dot and double space have to become a single space, for example).
Upon clicking a button in the Gui, you'll see a messagebox with the correctly formatted name appear which indicates that both the formatting is correct and the function is called.
When I look at the test folders I've created, the names aren't changed (not even after refreshing). Using a hardcoded string doesn't work either.
What am I overlooking?
public void cleanFormat() {
for (int i = 0; i < directories.size(); i++) {
File currentDirectory = directories.get(i);
for (File currentFile : currentDirectory.listFiles()) {
String formattedName = "";
formattedName = currentFile.getName().replace(".", " ");
formattedName = formattedName.replace(" ", " ");
currentFile.renameTo(new File(formattedName));
JOptionPane.showMessageDialog(null, formattedName);
}
}
}
For future browsers: This was fixed with Assylias' comment. Below you will find the eventual code which fixed it.
public void cleanFormat() {
for (int i = 0; i < directories.size(); i++) {
File currentDirectory = directories.get(i);
for (File currentFile : currentDirectory.listFiles()) {
String formattedName = "";
formattedName = currentFile.getName().replace(".", " ");
formattedName = formattedName.replace(" ", " ");
Path source = currentFile.toPath();
try {
Files.move(source, source.resolveSibling(formattedName));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Well, first of all the File.renameTo is trying to rename a file on the same filesystem.
The following is from java doc
Many aspects of the behavior of this method are inherently platform-dependent:
The rename operation might not be able to move a file from one filesystem to
another, it might not be atomic, and it might not succeed if a file with the
destination abstract pathname already exists.
The call to getName() returns just the name of the file and not any directory information. So you may be trying to rename the file to a different directory.
Try adding the containing directory to the file object you pass into rename
currentFile.renameTo(new File(currentDirectory, formattedName));
Also like others have said you should be checking the return value of renameTo which is probably false, or use the new methods in Files class which I've found to throw pretty informative IOExceptions.
First of all check return value, File.renameTo returns true if the renaming succeeded; false otherwise. E.g. you cannot rename / move a file from c: to d: on Windows.
And most importantly, use Java 7's java.nio.file.Files.move instead.

Categories