Java split the path..? - java

This is the input as string:
"C:\jdk1.6.0\bin\program1.java"
I need output as:
Path-->C:\jdk1.6.0\bin\
file--->program1.java
extension--->.java
Watch out the "\" char. I easily got output for "/".

The File class gives you everything you need:
File f = new File("C:\\jdk1.6.0\\bin\\program1.java");
System.out.println("Path-->" + f.getParent());
System.out.println("file--->" + f.getName());
int idx = f.getName().lastIndexOf('.');
System.out.println("extension--->" + ((idx > 0) ? f.getName().substring(idx) : "") );
EDIT: Thanks Dave for noting that String.lastIndexOf will return -1 if File.getName does not contain '.'.

Consider using an existing solution instead of rolling your own and introducing more code that needs to be tested. FilenameUtils from Apache Commons IO is one example:
http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/FilenameUtils.html

Since Java's File class does not support probing for the extension, I suggest you create a subclass of File that provides this ability:
package mypackage;
/**
* Enhances java.io.File functionality by adding extension awareness.
*/
public class File extends java.io.File {
/**
* Returns the characters after the last period.
*
* #return An empty string if there is no extension.
*/
public String getExtension() {
String name = getName();
String result = "";
int index = name.lastIndexOf( '.' );
if( index > 0 ) {
result = name.substring( index );
}
return result;
}
}
Now simply substitute your version of File for Java's version and, when combined with Kurt's answer, gives you everything you need.
Notice that using a subclass is ideal because if you wanted to change the behaviour (due to a different operating system using a different extension delimiter token), you need only update a single method and your entire application continues to work. (Or if you need to fix a bug, such as trying to execute str.substring( -1 ).)
In other words, if you extract a file extension in more than one place in your code base, you have made a mistake.
Going further, if you wanted to completely abstract the knowledge of the file type (because some operating systems might not use the . separator), you could write:
/**
* Enhances java.io.File functionality by adding extension awareness.
*/
public class File extends java.io.File {
public File( String filename ) {
super( filename );
}
/**
* Returns true if the file type matches the given type.
*/
public boolean isType( String type ) {
return getExtension().equals( type );
}
/**
* Returns the characters after the last period.
*
* #return An empty string if there is no extension.
*/
private String getExtension() {
String name = getName();
String result = "";
int index = name.lastIndexOf( '.' );
if( index > 0 ) {
result = name.substring( index );
}
return result;
}
}
I would consider this a much more robust solution. This would seamlessly allow substituting a more advanced file type detection mechanism (analysis of file contents to determine the type), without having to change the calling code. Example:
File file = new File( "myfile.txt" );
if( file.isType( "png" ) ) {
System.out.println( "PNG image found!" );
}
If a user saved "myfile.png" as "myfile.txt", the image would still be processed because the advanced version (not shown here) would look for the "PNG" marker that starts every single PNG file in the (cyber) world.

You need to compensate for the double slashes returned in Path (if it has been programmatically generated).
//Considering that strPath holds the Path String
String[] strPathParts = strPath.split("\\\\");
//Now to check Windows Drive
System.out.println("Drive Name : "+strPathParts[0]);

Related

JavaParser - save modified source code file with new name

I'm using JavaParser to modify java source code. My goal is to read a single java source code file (ArithmeticClassToBeMutated) and store it in a compilation unit. Then, i'd like to replace/mutate its arithmetic operators (PLUS,MINUS,MULTIPLY,DIVISION,REMAINDER). All instances of an operator (e.g. plus) shall always be replaced with another one (e.g. minus). In the end, i want to have 4 output files:
One java source code file where every "Plus" became a "Minus",
one file where every "Plus" became a "Multiply",
one file where every "Plus" became a "Division", and
one file where every "Plus" became a "Remainder/Modulo). I can't type the symbols or else i get a formatting error.
In my code (see below), the replacement/modification itself works. Now, my question is: how can I change the name of the output source code files? I did it with the methods add and saveAll:
sourceRoot.add("", OperatorToBeMutated.name() + "_TO_" + arithmeticOperators[i].name() + "_MUTATED_"
+ cu.getStorage().get().getFileName(), cu);
sourceRoot.saveAll(
CodeGenerationUtils.mavenModuleRoot(ReplacementAO.class).resolve(Paths.get("output")));
However, this creates two output files for each operator replacement. One file has the same name as the input file, and one file has my naming convention. The content is the same. What can I do to only save a single file (with my own naming) for each loop? Specifying no name would result in the output file overwriting itself with each iteration, as the name stays the same.
Thank you!
public static String filename = "ArithmeticClassToBeMutated.java";
public static void main(String[] args) {
for (i = 0; i < arithmeticOperators.length; i++) {
if (arithmeticOperators[i] == OperatorToBeMutated) {
continue;
}
sourceRoot = new SourceRoot(
CodeGenerationUtils.mavenModuleRoot(ReplacementAO.class).resolve("src/main/resources"));
CompilationUnit cu = sourceRoot.parse("", filename);
cu.accept(new ModifierVisitor<Void>() {
#Override
public Visitable visit(BinaryExpr n, Void arg) {
if (n.getOperator() == OperatorToBeMutated && n.getLeft().isNameExpr()
&& n.getRight().isNameExpr()) {
n.setOperator(arithmeticOperators[i]);
comment.setContent("Here, the operator " + OperatorToBeMutated.name()
+ " was mutated with the operator " + arithmeticOperators[i].name() + ".");
n.setComment(comment);
}
return super.visit(n, arg);
}
}, null);
sourceRoot.add("", OperatorToBeMutated.name() + "_TO_" + arithmeticOperators[i].name() + "_MUTATED_"
+ cu.getStorage().get().getFileName(), cu);
sourceRoot.saveAll(
CodeGenerationUtils.mavenModuleRoot(ReplacementAO.class).resolve(Paths.get("output")));
}
}
You wouldn't want to rename your file name to be different from the class name, as a public java class needs to have the same name as its file name. As far as I am aware this will throw a compiler error for public classes:
Can I compile a java file with a different name than the class?
I would suggest putting the mutated classes into different folders. Just adding another directory at the end of your path will automatically create a new folder. So for your example:
sourceRoot.saveAll(CodeGenerationUtils.mavenModuleRoot(LogicalOperators.class).resolve(Paths.get("output" + "/mutation1")));

Removing a substring from a string

I have a very simple question and just can't get my code to work in Java. I want to return a string that indicates a filepath, but extracts a certain portion of that path if it it exists.
So, my input might be "c:/lotus/notes/data/directory/mydatabase.nsf" and I want to return only "directory/mydatabase.nsf". Sometimes, the path provided will already leave out the "c:/lotus/notes/data/" because it is being accessed on the server rather than locally.
public String getDataPath ( String path ) {
int pathStart;
boolean pathContains;
String lowerPath;
lowerPath = path.toLowerCase();
pathStart = lowerPath.indexOf("c:/lotus/notes/data");
if ( pathStart >= 0) {
// 20 characters in "c:/lotus/notes/data/"
return path.substring(19);
}
pathContains = lowerPath.contains("lotus/notes/data");
if ( pathContains ) {
// 20 characters in "c:/lotus/notes/data/"
return path.substring(19);
}
return path;
}
This is simple, but somehow, I can't get it right. Neither of my if's ever evaluates as true.
Keep it simple:
path.replace("c:/lotus/notes/data", "");
You can simply do a path.replaceAll("c:/lotus/notes/data", ""). This will remove the leading path name if it is contained in the string, else the string will not change.
Take a look at the Path interface:
Paths Documentation
Path Documentation
It is used to do exactly what you want: Extract informations about the single parts of a path.

How to convert a filepath to valid file path in Java 1.7

Using Java 1.6 Filepath can be entered by user and then I apply various regular expressions to remove characters that are invalid for the platform (such as '?' is invalid on Windows), and check path length to ensure we end up with a valid filepath for the OS before trying to create the filepath.
But there are two problems:
Its a pain working out what is valid or not for each platform.
I'm making assumptions based on default filesystem for the platform, but of course an OSX system could be writing to a non-mac filesystem such a FAT32, in which case these checks will not be valid.
So I was hoping there would be a better way to do it with NIO2 in Java 7, but haven't found a solution yet, is there one ?
Depending on your expected result (corrected String? Invalid character position? Exception?), this should give you an idea of what can be done:
import java.io.File;
import java.nio.file.InvalidPathException;
public class Test {
public static final void main(final String[] args) {
final String current = new File(".").toPath().toAbsolutePath().normalize().toFile().toString();
Test.correctPath(current);
Test.correctPath(current + "aValidExpression");
Test.correctPath(current + "aValidExpression?;:-&é");
Test.correctPath(current + "aValidExpr//ession?;:-&é");
Test.correctPath(current + "aValidExpre\\ssion?;:-&é");
}
public static final String correctPath(final String path) {
try {
final String returnValue = new File(path).toPath().toAbsolutePath().normalize().toFile().toString();
System.out.println(returnValue);
return returnValue;
} catch (final InvalidPathException e) {
System.err.println(e.getMessage());
final int errorIndex = e.getIndex();
final String newPath = path.substring(0, errorIndex - 1) + path.substring(errorIndex + 1);
return Test.correctPath(newPath);
}
}
}
I hope it helps.
The key to your question is the phrase "remove characters that are invalid for the platform". The various String to Path conversion functions, such as get() and resolve(), will tell you whether the string was valid as a path, but the won't tell why it's invalid. One way of being invalid is to contain invalid characters. Another would be to have, say, too many slash characters together. Regardless, the library does not give any more information than this; it provides no facility to assist in validating user input in any way that would help a user fix an input error. This ought to be a standard practice, admittedly, but it's hardly a practice at all.
Upshot: You'll have to write such a validation library yourself if you want to have one. Upside: You certainly aren't the only person with such a problem.
I guess you should look at Path.getPath
public static Path get(String first,
String... more)
getPath("/foo","bar","gus")-->/foo/bar/gus
Converts a path string, or a sequence of strings that when joined form a path string, to a Path. If more does not specify any elements then the value of the first parameter is the path string to convert. If more specifies one or more elements then each non-empty string, including first, is considered to be a sequence of name elements (see Path) and is joined to form a path string. The details as to how the Strings are joined is provider specific but typically they will be joined using the name-separator as the separator. For example, if the name separator is "/" and getPath("/foo","bar","gus") is invoked, then the path string "/foo/bar/gus" is converted to a Path. A Path representing an empty path is returned if first is the empty string and more does not contain any non-empty strings.

Get XML and encoded data in a file with hex zeros using Java

I have to read a file (existing format not under my control) that contains an XML document and encoded data. This file unfortunately includes MQ-related data around it including hex zeros (end of files).
So, using Java, how can I read this file, stripping or ignoring the "garbage" I don't need to get at the XML and encoded data. I believe an acceptable solution is to just leave out the hex zeros (are there other values that will stop my reading?) since I don't need the MQ information (RFH header) anyway and the counts are meaningless for my purposes.
I have searched a lot and only find really heinous complicated "solutions". There must be a better way...
What worked was to pull out the XML documents - Groovy code:
public static final String REQUEST_XML = "<Request>";
public static final String REQUEST_END_XML = "</Request>";
/**
* #param xmlMessage
* #return 1-N EncodedRequests for those I contain
*/
private void extractRequests( String xmlMessage ) {
int start = xmlMessage.indexOf(REQUEST_XML);
int end = xmlMessage.indexOf(REQUEST_END_XML);
end += REQUEST_END_XML.length();
while( start >= 0 ) { //each <Request>
requests.add(new EncodedRequest(xmlMessage.substring(start,end)));
start = xmlMessage.indexOf(REQUEST_XML, end);
end = xmlMessage.indexOf(REQUEST_END_XML, start);
end += REQUEST_END_XML.length();
}
}
and then decode the base64 portion:
public String getDecodedContents() {
if( decodedContents == null ) {
byte[] decoded = Base64.decodeBase64(getEncodedContents().getBytes());
String newString = new String(decoded);
decodedContents = newString;
decodedContents = decodedContents.replace('\r','\t');
}
return decodedContents;
}
I've hit this issue before (well ... something similar). Have a look a my FilterInputStream for a file filter that you should be able to modify to your needs.
Essentially it implements a push-back buffer that chucks away anything you don't want.

Java - How to find out whether a File name is valid? [duplicate]

This question already has answers here:
Is there a way in Java to determine if a path is valid without attempting to create a file?
(7 answers)
Closed 7 years ago.
In my Java application I am renaming files to a file name provided in a String parameter. There is a method
boolean OKtoRename(String oldName, String newName)
which basically checks whether the newName isn't already taken by some other file, as I wouldn't want to bury existing ones.
It now occurred to me that perhaps the newName String will not denote a valid file name. So I thought to add this check to the method:
if (new File(newName).isFile()) {
return false;
}
Which obviously isn't the right way to do it, since in most cases the newFile does not yet exist and therefore although it is OKtoRename, the function returns false.
I was wondering, is there a method (I know there isn't for the java.io.File objects) like canExist()? Or would I have to resort to regex to make sure the newFile String does not contain invalid characters (e.g. ?, *, ", :)? I wonder if there is perhaps a function hidden somewhere in the JDK that would tell me if a string could possibly denote a valid file name.
I assembled a list of illegal filename characters (considering UNIX, Mac OS X and Windows systems) based on some online research a couple of months ago. If the new filename contains any of these, there's a risk that it might not be valid on all platforms.
private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' };
EDIT:
I would like to stress, that this is not a complete solution: as a commenter pointed out, even though it passes this test your file name could still be a Windows specific keyword like COM, PRN, etc. However, if your file name contains any of these characters, it will certainly cause trouble in a cross-platform environment.
Use createNewFile(), which will atomically create the file only if it doesn't yet exist.
If the file is created, the name is valid and it is not clobbering an existing file. You can then open the files and efficiently copy data from one to the other with FileChannel.transferXXX operations.
An important thing to keep in mind that, in general, the check and the creation should be atomic. If you first check whether an operation is safe, then perform the operation as a separate step, conditions may have changed in the meantime, making the operation unsafe.
Additional food for thought is available at this related post: "Move/Copy operations in Java."
Update:
Since this answer, the NIO.2 APIs have been introduced, which add more interaction with the file system.
Suppose you have an interactive program, and want to validate after each keystroke whether the file is potentially valid. For example, you might want to enable a "Save" button only when the entry is valid rather than popping up an error dialog after pressing "Save". Creating and ensuring the deletion of a lot of unnecessary files that my suggestion above would require seems like a mess.
With NIO.2, you can't create a Path instance containing characters that are illegal for the file system. An InvalidPathException is raised as soon as you try to create the Path.
However, there isn't an API to validate illegal names comprised of valid characters, like "PRN" on Windows. As a workaround, experimentation showed that using an illegal file name would raise a distinct exception when trying to access attributes (using Files.getLastModifiedTime(), for example).
If you specify a legal name for a file that does exist, you get no exception.
If you specify a legal name for a file that does not exist, it raises NoSuchFileException.
If you specify an illegal name, FileSystemException is raised.
However, this seems very kludgey and might not be reliable on other operating systems.
Here system specific way is suggested.
public static boolean isFilenameValid(String file) {
File f = new File(file);
try {
f.getCanonicalPath();
return true;
} catch (IOException e) {
return false;
}
}
If developing for Eclipse, check out org.eclipse.core.internal.resources.OS
public abstract class OS {
private static final String INSTALLED_PLATFORM;
public static final char[] INVALID_RESOURCE_CHARACTERS;
private static final String[] INVALID_RESOURCE_BASENAMES;
private static final String[] INVALID_RESOURCE_FULLNAMES;
static {
//find out the OS being used
//setup the invalid names
INSTALLED_PLATFORM = Platform.getOS();
if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) {
//valid names and characters taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp
INVALID_RESOURCE_CHARACTERS = new char[] {'\\', '/', ':', '*', '?', '"', '<', '>', '|'};
INVALID_RESOURCE_BASENAMES = new String[] {"aux", "com1", "com2", "com3", "com4", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
"com5", "com6", "com7", "com8", "com9", "con", "lpt1", "lpt2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
"lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "nul", "prn"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$
Arrays.sort(INVALID_RESOURCE_BASENAMES);
//CLOCK$ may be used if an extension is provided
INVALID_RESOURCE_FULLNAMES = new String[] {"clock$"}; //$NON-NLS-1$
} else {
//only front slash and null char are invalid on UNIXes
//taken from http://www.faqs.org/faqs/unix-faq/faq/part2/section-2.html
INVALID_RESOURCE_CHARACTERS = new char[] {'/', '\0',};
INVALID_RESOURCE_BASENAMES = null;
INVALID_RESOURCE_FULLNAMES = null;
}
}
/**
* Returns true if the given name is a valid resource name on this operating system,
* and false otherwise.
*/
public static boolean isNameValid(String name) {
//. and .. have special meaning on all platforms
if (name.equals(".") || name.equals("..")) //$NON-NLS-1$ //$NON-NLS-2$
return false;
if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) {
//empty names are not valid
final int length = name.length();
if (length == 0)
return false;
final char lastChar = name.charAt(length-1);
// filenames ending in dot are not valid
if (lastChar == '.')
return false;
// file names ending with whitespace are truncated (bug 118997)
if (Character.isWhitespace(lastChar))
return false;
int dot = name.indexOf('.');
//on windows, filename suffixes are not relevant to name validity
String basename = dot == -1 ? name : name.substring(0, dot);
if (Arrays.binarySearch(INVALID_RESOURCE_BASENAMES, basename.toLowerCase()) >= 0)
return false;
return Arrays.binarySearch(INVALID_RESOURCE_FULLNAMES, name.toLowerCase()) < 0;
}
return true;
}
}
Just something i found, in java 7 and later, there is a class called Paths that has a method called get that takes one or more Strings and throws
InvalidPathException - if the path string cannot be converted to a Path
This is how I implemented this:
public boolean isValidFileName(final String aFileName) {
final File aFile = new File(aFileName);
boolean isValid = true;
try {
if (aFile.createNewFile()) {
aFile.delete();
}
} catch (IOException e) {
isValid = false;
}
return isValid;
}
To me it appears to be an OS dependent problem. You may simply want to check for some invalid character in the file name. Windows does this when you try to rename the file, it pops a message saying that a file cannot contain any of the following characters: \ / : * ? < > |
I am not sure if your question is "is there a library doing the job for me?" in that case I don't know any.
Using
String validName = URLEncoder.encode( fileName , "UTF-8");
File newFile = new File( validName );
Does the work.
I have just found today. I'm not sure if it works 100% of the time, but so far, I have been able to create valid file names.

Categories