How to write a method that increments a file name in java - java

I am writing a method that takes a a string of html and writes it to a file. The method should increment the file name if the file already exists. For example, if wordmatch.html already exists then a new file should be created wordmatch1.html so and so fourth.
I have created a method that writes the html to a file. I'm working on the last part to incrementally change the name of a new file if the file already existst.
public void saveContent(WordMatch wordMatch){
logger.info(wordMatch);
try {
File file = new File("wordmatch0.html");
String html = wordMatch.toString();
String cleanedHTML = html.replace("WordMatch(content=","").replace(")","");
logger.info(cleanedHTML);
if (file.createNewFile()) {
System.out.println("File created: " + file.getName());
try {
FileWriter myWriter = new FileWriter("word_match.html");
myWriter.write(cleanedHTML);
myWriter.close();
System.out.println("Successfully wrote to the file.");
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
} else {
String fileName = file.getName().toString();
String index = fileName.substring(fileName.indexOf("h") + 1);
index = index.substring(0, index.indexOf("."));
Integer parsedInt = Integer.parseInt(index);
System.out.println(parsedInt);
parsedInt+=1;
fileName = fileName.replace(index,parsedInt.toString());
System.out.println(fileName);
System.out.println("fileName should have been printed by now");
file = new File(fileName);
FileWriter myWriter = new FileWriter(file);
myWriter.write(cleanedHTML);
myWriter.close();
//TODO add method to write file name with new index
System.out.println("File already exists.");
}
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
}
Any help with this would be greatly appreciated. Thanks.

A simple approach will be count the number of files matching your file name and then increment the numberOfFiles to create a new file name :
Stream<Path> files = Files.list(Paths.get("C:\\your\\local\\path"));
long numberOfFiles = files.map(Path.class::cast)
.filter(path -> path.getFileName().toString().startsWith("wordmatch"))
.count();
After all you have to manage certains situations, to have a good algorithm for managing your files.

A problem that seems trivial but has so many pitfalls.
The algorithm you wrote won't work for the following reasons:
Simple if-else is not enough, you need to go through a loop to find the last index, because potentially there could be many files created already.
Else block tries to find an index from the file name that should't have one.
Moreover, there are additional questions that may raise.
What if someone deleted the intermediate indexes and now you have 1 and 4, do you want to go with 2 or 5?
Can someone delete the files from the directory except the programm?
Are nested directories possible?
How often files are created?
Can someone manually create a file with a proper name bypassing the programm?
And more importand question is - do you really want to stick to the strict brute-force counter on the actual files listed in a directory?
If the answer is yes, the more reasonable would be to check the files using File.list(), sort them, take the last index and increment them instead of trying to create a file and increment on a failure.
public class Main {
public static void main(String[] args) {
File directoryPath = new File("path_to_your_dir");
FilenameFilter filenameFilter = (dir, name) -> !dir.isFile();
Integer maxIndex = Arrays.stream(directoryPath.list(filenameFilter))
// Take numeric index from the end of the file name, beware of file extensions!
.map(name -> name.substring("word_match".length(), name.lastIndexOf('.')))
.map(Main::parseOrDefault) // Parse it to a number
.max(Integer::compareTo) // Define how to compare them
.orElse(-1);
// -1 is no files, 0 if a file with no index, otherwise max index
System.out.println(maxIndex);
}
private static Integer parseOrDefault(String integer) {
try {
return Integer.valueOf(integer);
} catch (NumberFormatException e) {
return 0;
}
}
}
If the answer is no, you can have a counter that is persisted somewhere (file system, BD) and incremented regardless every time.
And more simple approach is establish a frequence of file creations and simply append a timestamp/date-time to the end of each file.

Related

fastest way to find list of files in a huge windows directory tree

I have a windows directory tree with about 1,000,000 files inside.
I have a text file that i read in Java, contains some file names (about 100,000), and I want to check for every file name - if it exists in the directory (if yes - give me a full path of the file).
Already tried those options:
1.
File folder = new File("your/path");
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
System.out.println("File " + listOfFiles[i].getName());
} else if (listOfFiles[i].isDirectory()) {
System.out.println("Directory " + listOfFiles[i].getName());
}
}
2.
public void func(String path, String name)
{
Path folder = Paths.get(path);
try (DirectoryStream<Path> stream = Files.newDirectoryStream(folder))
{
for (Path entry : stream)
{
if(Files.isDirectory(entry))
{
func(entry.toString(), name);
}
else
{
if(FilenameUtils.removeExtension(entry.getFileName().toString()).equals(name))
{
System.out.println(entry);
}
}
}
}
catch (IOException ex) {
// An I/O problem has occurred
}
}
So far all those options to do so are very slow.
As I guess, although all the files are in the same logic place, actually every file is saved in another place in the hard drive, so all those IO calls take too much time.
Another idea that i found here is ISearchFolderItemFactory interface, but I found documentation for it only in C++, not in Java.
Maybe I can implement a pre-sort or something, to put all the files really together in the hd, sorted by name, and then to use some hash method to find name by name?
Need some help...

Can't create files in a specific folder from the given list

Can anyone explain why this code wont work? Why is it not creating the files in the given destination? Instead it just ouputs the groupId and not created statement.
Any help or guidance would be highly appreciated.
List<String> groupList = userGroupAuthor.getPredefinedGroupList();
String groupId;
for (String groupName : groupList) {
groupId = StringHelper.makeGroupId(groupName);
System.out.println(groupId);
//writeGroupName(groupId, groupName);
File f = new File(testScriptName);
try{
boolean fvar = f.createNewFile();
if(fvar){
System.out.println("File Created");
}else {
System.out.println("Not Created");
}
}
//bw = new BufferedWriter(new FileWriter(f));
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
If I understood the question, it is why the same filename testScriptName is resulting in a "Not Created" message on each run.
The JavaDoc for File.createNewFile states:
Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist. The check for the existence of the file and the creation of the file if it does not exist are a single operation that is atomic with respect to all other filesystem activities that might affect the file. [emphasis added]
Since the same filename is being used inside the loop, it will fail if the file already exists, which it would after the first run.
To resolve the situation, either move the file creation outside of the loop, or use a unique filename for each group. There is insufficient provided logic in the code to determine the intent.

Iterating through a directory in java

Hi right now I have the following method I am using to read one file at a time in a the same directory as the class that has this method:
private byte[][] getDoubleByteArrayOfFile(String fileName, Region region)
throws IOException
{
BufferedImage image = ImageIO.read(getClass().getResource(fileName));
byte[][] alphaInputData =
new byte[region.getInputXAxisLength()][region.getInputYAxisLength()];
for (int x = 0; x < alphaInputData.length; x++)
{
for (int y = 0; y < alphaInputData[x].length; y++)
{
int color = image.getRGB(x, y);
alphaInputData[x][y] = (byte)(color >> 23);
}
}
return alphaInputData;
}
I was wondering how I can make it so that instead of having "fileName" as a argument I can but a directory name as a argument and then iterate through all of the files within that directory and perform the same operation on it. Thanks!
If you are using Java 7, then you need to take a look at NIO.2.
Specifically, take a look at the Listing a Directory's Contents section.
Path dir = Paths.get("/directory/path");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path file: stream) {
getDoubleByteArrayOfFile(file.getFileName(), someRegion);
}
} catch (IOException | DirectoryIteratorException x) {
// IOException can never be thrown by the iteration.
// In this snippet, it can only be thrown by newDirectoryStream.
System.err.println(x);
}
Here is a quick example that may help:
private ArrayList<byte[][]> getDoubleByteArrayOfDirectory(String dirName,
Region region) throws IOException {
ArrayList<byte[][]> results = new ArrayList<byte[][]>();
File directory = new File(dirName);
if (!directory.isDirectory()) return null //or handle however you wish
for (File file : directory.listFiles()) {
results.add(getDoubleByteArrayOfFile(file.getName()), region);
}
return results;
}
Not exactly what you asked for since it's wrapping your old method rather than re-writing it, but I find it a bit cleaner this way, and leaves you with the option of still processing a single file. Be sure to tweak the return type and how to handle the region based on your actual requirements (hard to tell from the question).
It is rather simple, using the File#listFiles() which returns a list of files in the specified File, which must be a directory. To make sure that the File is a directory, simply use File#isDirectory(). The problem occurs where you decide how to return the byte buffer. Since the method returns a 2d buffer, it is necessary to use a 3d byte buffer array, or in this case a List seems to me like the best choice since an unknown number of files will exist in the directory in question.
private List getDoubleByteArrayOfDirectory(String directory, Region region) throws IOException {
File directoryFile = new File(directory);
if(!directoryFile.isDirectory()) {
throw new IllegalArgumentException("path must be a directory");
}
List results = new ArrayList();
for(File temp : directoryFile.listFiles()) {
if(temp.isDirectory()) {
results.addAll(getDoubleByteArrayOfDirectory(temp.getPath(), region));
}else {
results.add(getDoubleByteArrayOfFile(temp.getPath(), region));
}
}
return results;
}
You can, see the list and listFiles documentation for how to do this.
We can use recursion to process a directory with subdirectories also. Here I am deleting file one by one, you can call any other function to process it.
public static void recursiveProcess(File file) {
//to end the recursive loop
if (!file.exists())
return;
//if directory, go inside and call recursively
if (file.isDirectory()) {
for (File f : file.listFiles()) {
//call recursively
recursiveProcess(f);
}
}
//call processing function, for example here I am deleting
file.delete();
System.out.println("Deleted (Processed) file/folder: "+file.getAbsolutePath());
}

Check if file exists without creating it

If I do this:
File f = new File("c:\\text.txt");
if (f.exists()) {
System.out.println("File exists");
} else {
System.out.println("File not found!");
}
Then the file gets created and always returns "File exists". Is it possible to check if a file exists without creating it?
EDIT:
I forgot to mention that it's in a for loop. So here's the real thing:
for (int i = 0; i < 10; i++) {
File file = new File("c:\\text" + i + ".txt");
System.out.println("New file created: " + file.getPath());
}
When you instantiate a File, you're not creating anything on disk but just building an object on which you can call some methods, like exists().
That's fine and cheap, don't try to avoid this instantiation.
The File instance has only two fields:
private String path;
private transient int prefixLength;
And here is the constructor :
public File(String pathname) {
if (pathname == null) {
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
As you can see, the File instance is just an encapsulation of the path. Creating it in order to call exists() is the correct way to proceed. Don't try to optimize it away.
Starting from Java 7 you can use java.nio.file.Files.exists:
Path p = Paths.get("C:\\Users\\first.last");
boolean exists = Files.exists(p);
boolean notExists = Files.notExists(p);
if (exists) {
System.out.println("File exists!");
} else if (notExists) {
System.out.println("File doesn't exist!");
} else {
System.out.println("File's status is unknown!");
}
In the Oracle tutorial you can find some details about this:
The methods in the Path class are syntactic, meaning that they operate on the Path instance. But eventually you must access the file system to verify that a particular Path exists, or does not exist. You can do so with the exists(Path, LinkOption...) and the notExists(Path, LinkOption...) methods. Note that !Files.exists(path) is not equivalent to Files.notExists(path). When you are testing a file's existence, three results are possible:
The file is verified to exist.
The file is verified to not exist.
The file's status is unknown. This result can occur when the program does not have access to the file.
If both exists and notExists return false, the existence of the file cannot be verified.
Creating a File instance does not create a file on the file system, so the posted code will do what you require.
The Files.exists method has noticeably poor performance in JDK 8, and can slow an application significantly when used to check files that don't actually exist.
This can be applied too for Files.noExists, Files.isDirectory and Files.isRegularFile
According this you can use the following :
Paths.get("file_path").toFile().exists()

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