Create Sequential File extension method needed

I've got a requirement to generate filenames based on a general pattern that looks like: "something.nnn" where "nnn" is some number represented in a zero padded fixed field - so the 6th sequential filename would be "something.006".

So in a directory with files: file.001, file.002, file.005

The generated file name for the next file should be file.006

not file.003!

Any ideas on the "best" way to do this?

David

[450 byte] By [davidakoontza] at [2007-9-29 17:13:24]
# 1
Keep a counter somewhere else. Before you create one of these files, increment the counter and save it. Then build the file name from that value.
DrClapa at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 2
1. Determine what the highest number is in the directory.2. Add one to that value3. Create a new file based on the incremented number.
dubwaia at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 3

> 1. Determine what the highest number is in the

> directory.

> 2. Add one to that value

> 3. Create a new file based on the incremented number.

Yes that's kinda obvious - but step 1 is not quite so trivial.

I was looking for help with that.

Thanks

davidakoontza at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 4
> Yes that's kinda obvious - but step 1 is not quite so> trivial.> > I was looking for help with that.> > ThanksAre you using 1.4? Is the problem getting the list of filenames of extracting the number from each filename?
dubwaia at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 5

No real "problem" - just thinking maybe someone has done this and has the algorithm... or the code they want to share.

I've not done this before - but it appears to me I've got to sort the file names and find the 'max'. and since sorting numbers with a alpha sort doesn't give the proper max - it looks like I'd have to convert the strings to numbers - then look for a max, seems like this could be done many ways.

Any suggestions.

davidakoontza at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 6
Are you using 1.4?
dubwaia at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 7
No 1.3.1 - Why?
davidakoontza at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 8

Because I want to know whether you have regex available to you. You do not.

Use String tokenizer and tokenize on "." The number should be the second token. Use Integer.parseInt() to get the int value. Keep a varaible that is the largest value so far. If the next value is greater than that value, it becomes the new max. When you've look through all the files that end in numbers, the value is the max.

dubwaia at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 9

> Because I want to know whether you have regex

> available to you. You do not.

>

> Use String tokenizer and tokenize on "." The number

> should be the second token. Use Integer.parseInt() to

> get the int value. Keep a varaible that is the

> largest value so far. If the next value is greater

> than that value, it becomes the new max. When you've

> look through all the files that end in numbers, the

> value is the max.

Thanks.

Good idea - looks like it will work most of the time.

But what about this filename "path/file.name.ext"

I think instead of tokenizer I'd better use String.lastIndexOf()

to get the extension.

So how would having regEx change things?

davidakoontza at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 10

If you had jdk1.4 then it String has a method called split(). It is

a convienience method and is based on regexps. Since you don't use

this version you have to use the String tokenizer or write your won code

to do it.

The following is probably the way to do it though

JDK1.3 code

public int findNextFileExtension(File directory) {

if((directory==null)||(!directory.isDirectory())

throw new IllegalArgumentException("Invalid directory");

int maxValue = Integer.MIN_VALUE;

// you can add a FilenameFilter or a FileFilter to the following line

// if you want to refine the search more (such that only files that

// have a certain name are considered)

File[] files = directory.listFiles();

for(int i=0;i<files.length;i++) {

// ignore directories

if(file[i].isFile()) {

String name = files[i].getName();

String ext = name.substring(name.lastIndexOf('.'));

try {

int i = Integer.parseInt(ext);

if(i>maxValue)maxValue=i;

}catch(NumberFormatException nfe) {

// quietly do nothing

}

}

//in case there are no files of this format in the directory

if(maxValue<0) maxValue = 0;

return maxValue;

}

}

matfud

matfuda at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 11

Isn't complicated... Take this as psuedocode.. since I'm sure it has typos and bugs.

String FILENAME = "file"

File dir = new File("c:\");

File[] files = dir.listFiles();

int max = 0;

for ( int x = 0; x < files.length; x++) {

String fname = files.getName();

int idx = fname.lastIndexOf('.');

if ( ( idx != -1 ) && ( fname.substring( 0, idx - 1).equals(FILENAME) ) )

{

String ext = fname.substring(idx+1);

int num = Integer.parseInt( ext );

if ( num > max )

max = num;

}

}

String numStr = "" + max;

if ( numStr.length() == 1 )

numStr = "00"+max;

else if ( numStr.length() == 2 )

numStr = "0"+max;

File createThisFile = new File( dir, FILENAME + "." + numStr );

eduar09a at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 12

> If you had jdk1.4 then it String has a method called

> split(). It is

> a convienience method and is based on regexps.

I would go even another step and just write a regex that finds the last number in the name. something like this (untested):

"\\d+$"

And you could make it more restrictive based on othe info.

dubwaia at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 13
> But what about this filename "path/file.name.ext"You can catch Parse exceptions and keep going until you get a valid number of finish the String. Also, if you know something about the beginning of the file name you can use that to ignore files.
dubwaia at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 14

[nobr]Well thanks for the discussion, here's what I've developed (with many of the ideas from this thread).

/*

* Copyright (c) 2003 David A. Koontz

* Licensed under the Open Software License version 2.0

* http://www.opensource.org/licenses/osl-2.0.php

*/

import java.io.*;

/**

* Utility class for generating sequential file extensions.

*

*

* Assume a directory with:<br>

* <code>

*|- file.name.001

*|- file.name.002

*|- file.name.005

* </code>

* What is the next file name in the sequential set?<br>

* <b>file.name.006</b> <i>or maybe</i> <b>file.name.003</b><br>

* Depends on what you want to do.

*

* The method <code>nextSequentialFile</code> will generate a

* File object to meet either need.

*

* @author David A. Koontz

*/

public class SequentialExtension {

/**

* Finds the next file extension of a sequential extension.

* <P>

* Given file.001, file.002, file.005 in a directory this

* method will return file.003 when <code>infix == true</code>

* or file.006 when <code>infix == false</code>.

*

* If baseName is null or empty string then every file within the

* directory is considered within the sequential set.

*

* @param directorythe directory in which to search

* @param baseNamethe filename's base part

* @param infix when true gaps in sequence will be infiled

* @returnthe File with the next sequential number

*/

public File nextSequentialFile(File directory, String baseName, boolean infix) {

File seqFile = null;

if( (directory==null) || (!directory.isDirectory()) )

throw new IllegalArgumentException("Invalid directory");

if ( infix ) {

// start with *.000 or *.001

// int next = 1; // if you want to start with *.001

// just for sanity we limit the sequence loop to *.999

for ( int next = 0; next < 1000; next++ ) {

// generate the next extension in sequential set

String numStr = makeNumericExtension(next);

seqFile = new File(directory, baseName + '.' + numStr);

if ( ! seqFile.exists() ) {

break; // found a non-existant file name - break out of loop & return it

}

}

if ( seqFile == null ) {

throw new UnsupportedOperationException("All sequential files 000 - 999 exist for "+baseName+"!");

}

} else {

// not inclusive - meaning generate extension at end of current set

// so file.001, file.002, file.005 results in file.006

int max = findMaxSequentialExtension(directory, baseName);

int next = max + 1;

// generate the next extension in sequential set

String numStr = makeNumericExtension(next);

seqFile = new File( directory, baseName + '.' + numStr );

}

return seqFile;

}

/**

* Generate a three digit extension (zero padded).

*

* Like: "003" or "023" (also "4321").

*/

private String makeNumericExtension(int number) {

String numStr = "" + number;

if ( numStr.length() == 1 )

numStr = "00" + number;

else if ( numStr.length() == 2 )

numStr = "0" + number;

return numStr;

}

/**

* Finds the next file extension of a sequential extension.

* <P>

* Given file.001, file.002, file.005 in a directory this

* method will return file.003.

*

* If baseName is null or empty string then every file within the

* directory is considered within the sequential set.

*

* @param directorythe directory in which to search

* @param baseNamethe filename's base part

* @returnthe File with the next sequential number

*/

public File nextSequentialFile(File directory, String baseName) {

if( (directory==null) || (!directory.isDirectory()) )

throw new IllegalArgumentException("Invalid directory");

// start with *.000 or *.001

// int next = 1; // if you want to start with *.001

// just for sanity we limit the sequence loop to *.999

File seqFile = null;

for ( int next = 0; next < 1000; next++ ) {

// generate the next extension in sequential set

String numStr = "" + next;

if ( numStr.length() == 1 )

numStr = "00"+next;

else if ( numStr.length() == 2 )

numStr = "0"+next;

seqFile = new File(directory, baseName + '.' + numStr);

if ( ! seqFile.exists() ) {

break; // found a non-existant file name - break out of loop & return it

}

}

if ( seqFile == null ) {

throw new UnsupportedOperationException("All sequential files 000 - 999 exist for "+baseName+"!");

}

return seqFile;

}

/**

* Finds the max file extension of a sequential file.

* <P>

* Given file.001, file.002, file.005 in a directory this

* method will return 5.

*

* Uses a FileFilter to search the directory if baseName is

* provided. If baseName is null or empty string then every

* file within the directory is considered within the sequential set.

*

* @param directorythe directory in which to search

* @param baseNamethe filename's base part

* @returnthe max sequential number

*/

private int findMaxSequentialExtension(File directory, String baseName) {

if( (directory==null) || (!directory.isDirectory()) )

throw new IllegalArgumentException("Invalid directory");

// start with *.000

// int maxValue = 0; // if you want to start with *.001

int maxValue = -1;

File[] files;

if ( baseName!=null && baseName.length()>0 ) {

files = directory.listFiles(new BaseNameFilter(baseName));

} else {

files = directory.listFiles();

}

for(int i=0; i < files.length; i++) {

// ignore directories & do not recurse into sub-dir

if(files[i].isFile()) {

String name = files[i].getName();

int dotIndex = name.lastIndexOf('.');

// if no dot lastIndexOf returns -1

// what about unix hidden (dot) files

if (dotIndex > 0) {

// only if there is a basename

String ext = name.substring(dotIndex+1);

System.out.println( "found ext = " + ext );

try {

int num = Integer.parseInt(ext);

if ( num > maxValue ) maxValue=num;

}catch(NumberFormatException nfe) {

; // ignore

}

}

}

}

return maxValue;

}

/**

* Strips path and extension from a filename.

*

*/

public static String getBaseName( String name )

{

// strip path.

String base = new File( name ).getName();

// strip possible extension.

int index = base.lastIndexOf( '.' );

if( index != -1 )

base = base.substring( 0, index );

return base;

}

/**

* Strips path and extension from a filename.

*

* example: path/file.name.txt -> file.name

*

* Note: define extension as the substring after the last dot.

*

*/

public static String getBaseName( File name )

{

// strip path.

String base = name.getName();

// strip possible extension.

int index = base.lastIndexOf( '.' );

if( index != -1 )

base = base.substring( 0, index );

return base;

}

/**

* Strips path and base name from a filename.

*

* example: path/file.txt -> txt

*

* Note: define extension as the substring after the last dot.

*

* example: path/long.file.name.ext -> ext

*/

public static String getFileExtension( File file, boolean keepDot )

{

// strip path

String base = file.getName();

// strip possible extension

String extension = "";

int index = base.lastIndexOf( '.' );

if( index != -1 )

{

if( keepDot )

extension = base.substring( index );

else

extension = base.substring( index + 1 );

}

return extension;

}

/**

* A Filter for filenames of a given base name.

*

* For use in <code>File.listFiles<code><br>

* <code>

* File[] files = directory.listFiles(BaseNameFilter("MyFile"));

* </code><br>

* Would return MyFile.001, MyFile.002, MyFile.txt, etc.

*/

class BaseNameFilter implements FileFilter {

// inner class

private String name;

BaseNameFilter(String baseName) {

name = baseName;

}

public boolean accept(File f) {

//

String bn = getBaseName(f.getName());

// is file system case sensitive? how would I know?

// shouldn't Java System know?

// if ( name.equalsIgnoreCase(bn) ) {

if ( name.equals(bn) ) {

return true;

}

return false;

}

}

/**

* A Filter for filenames of a given extension.

*

* For use in <code>File.listFiles<code><br>

* <code>

* File[] files = directory.listFiles(ExtensionFilter("txt"));

* </code><br>

* Would return junk.txt, apple.txt, MyFile.txt, etc.

*/

class ExtensionFilter implements FileFilter {

// inner class

private String name;

ExtensionFilter(String extension) {

name = extension;

}

public boolean accept(File f) {

//

String ext = getFileExtension(f, false);

// is file system case sensitive? how would I know?

// shouldn't Java System know?

// if ( name.equalsIgnoreCase(ext) ) {

if ( name.equals(ext) ) {

return true;

}

return false;

}

}

/**

* Unit testing the Filters & findMaxSequentialExtension()

*/

public static void main( String[] args ) {

File nextFile = null;

String baseName = "file.name";

SequentialExtension se = new SequentialExtension(".");

// generate the next extension (not infix) in sequential set

nextFile = se.nextSequentialFile(se.cwd, baseName, false);

try {

if ( nextFile.createNewFile() ) {

System.out.println("Created " + nextFile.getName() );

} else {

System.out.println("Failed to create " + nextFile.getName() );

}

} catch (IOException ex) {

System.out.println("Failed" + ex);

}

// generate the infixed extension within a sequential set

nextFile = se.nextSequentialFile(se.cwd, baseName, true);

try {

if ( nextFile.createNewFile() ) {

System.out.println("Created " + nextFile.getName() );

} else {

System.out.println("Failed to create " + nextFile.getName() );

}

} catch (IOException ex) {

System.out.println("Failed" + ex);

}

se.list(baseName);

/* This is program output after a few runs & deleting a few files

Note the missing files (003 & 004).

found ext = 000

found ext = 001

found ext = 002

found ext = 005

found ext = 006

Created file.name.007

Created file.name.003

List of 'file.name' files:

file.name.000

file.name.001

file.name.002

file.name.005

file.name.006

file.name.007

file.name.003

*/

}

File cwd;

public SequentialExtension(String dir) {

cwd = new File(dir);

}

public void list(String basename) {

File[] files = cwd.listFiles(new BaseNameFilter(basename) );

System.out.println("List of '" + basename + "' files:");

for (int i = 0; i < files.length; i++) {

System.out.println(""+ files[i].getName() );

}

}

}

/*

* Copyright (c) 2003 David A. Koontz

* Licensed under the Open Software License version 2.0

* http://www.opensource.org/licenses/osl-2.0.php

*/

[/nobr]

davidakoontza at 2007-7-15 15:57:02 > top of Java-index,Other Topics,Algorithms...
# 15

// if no dot lastIndexOf returns -1

// what about unix hidden (dot) files

if (dotIndex > 0) {

youve handled them. If the file is a hidden file then its first char will

be 0. Assuming the worst case where this file has no extension then

the lastIndexOf('.') will return 0. You are ignoring 0.

If the file has an extension then lastIndexOf will return the '.' that

splits the filename from the extension and all will be well.

matfud

matfuda at 2007-7-19 12:32:41 > top of Java-index,Other Topics,Algorithms...
# 16

>

> > // if no dot lastIndexOf returns -1

> // what about unix hidden (dot) files

> if (dotIndex > 0) {

>

>

> youve handled them. If the file is a hidden file then

> its first char will

> be 0. Assuming the worst case where this file has no

> extension then

> the lastIndexOf('.') will return 0. You are ignoring

> 0.

>

> If the file has an extension then lastIndexOf will

> return the '.' that

> splits the filename from the extension and all will be

> well.

>

> matfud

I haven't tested on unix yet... does File.listFiles() return hidden files or not? I guess it would. But that appears to open another can of worms.

davidakoontza at 2007-7-19 12:32:41 > top of Java-index,Other Topics,Algorithms...