I currently have a log file(see bellow) that I need to iterate through and pull out a list of files that were scanned. Then by using that list of files copy the scanned files into a different directory.
So in this case, it would go through and pull
c:\tools\baregrep.exe
c:\tools\baretail.exe
etc etc
and then move them to a folder, say c:\folder\SafeFolder with the same file structure
I wish I had a sample of what the output was on a failed scan, but this will get me a good head start and I can probably figure the rest out
Symantec Image of Log File
Thanks in advanced, I really appreciate any help that you can lend me.
This question is tagged as Java, and as much as I love Java, this problem is something that would be easier and quicker to solve in a language such as Perl (so if you only want the end result and do not need to run in a particular environment then you may wish to use a scripting language instead).
Not a working implementation, but code along the lines of the below is all it would take in perl: (Syntax untested and likely broken as is, only serves as a guideline.. been awhile since I wrote any perl).
use File::Copy;
my $outdir = "c:/out/";
while(<>)
{
my ($path) = /Processing File\s+\'([^\']+)\'/;
my ($file) = $path =~ /(.*\\)+([^\\]+)/;
if (($file) && (-e $path))
{
copy($path,$outdir . $file);
}
}
This should do the trick. Now, just adapt for your solution!
public static void find(String logPath, String safeFolder) throws FileNotFoundException, IOException {
ArrayList<File> files = new ArrayList<File>();
BufferedReader br = new BufferedReader(new FileReader(logPath));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
Pattern pattern = Pattern.compile("'[a-zA-Z]:\\\\.+?'");
Matcher matcher = pattern.matcher(line);
if (matcher.matches()) {
}
if (matcher.find()) {
files.add(new File(matcher.group()));
System.out.println("Got a new file! " + files.get(files.size() - 1));
}
}
for (File f : files) {
// Make sure we get a file indeed
if (f.exists()) {
if (!f.renameTo(new File(safeFolder, f.getName()))) {
System.err.println("Unable to move file! " + f);
}
} else {
System.out.println("I got a wrong file! " + f);
}
}
}
Its straight forward.
Read the Log file line by line using NEW_LINE as your deliminator. If this is a small file, feel free to load it & process it via String.split("\n") or StringTokenizer
As you loop each line, you need to do a simple test to detect if that string contains 'Processing File '.
If it does, using Regular Expression (harder) or simple parsing to capture the file names. It should be within the ['], so detect the first occurrence of ['], and detect the second, and get the string in between.
If your string is valid (you may test using java.io.File) or existing, you could copy the file name to another file. I would not advise you against copying it in java for memory restrictions for starters.
Instead, copy the string of files to form a batch file to copy them at once using the OS Script like Windows BAT or Bash Script, eg cp 'filename_from' 'copy_to_dir'
Let me know of you need a working example
regards
Related
Checkmarx - v 9.3.0 HF11
I am passing env value as data directory path in docker file which used in dev/uat server
ENV DATA /app/data/
In local, using following Environment variable
DATA=C:\projects\app\data\
getDataDirectory("MyDirectoryName"); // MyDirectoryName is present in data folder
public String getDataDirectory(String dirName)
{
String path = System.getenv("DATA");
if (path != null) {
path = sanitizePathValue(path);
path = encodePath(path);
dirName = sanitizePathValue(dirName);
if (!path.endsWith(File.separator)) {
path = path + File.separator;
} else if (!path.contains("data")) {
throw new MyRuntimeException("Data Directory path is incorrect");
}
} else {
return null;
}
File file = new File(dirName); // NOSONAR
if (!file.isAbsolute()) {
File tmp = new File(SecurityUtil.decodePath(path)); // NOSONAR
if (!tmp.getAbsolutePath().endsWith(Character.toString(File.separatorChar))) {
dirName = tmp.getAbsolutePath() + File.separatorChar + dirName;
} else {
dirName = tmp.getAbsolutePath() + dirName;
}
}
return dirName;
}
public static String encodePath(String path) {
try {
return URLEncoder.encode(path, "UTF-8");
} catch (UnsupportedEncodingException e) {
logger.error("Exception while encoding path", e);
}
return "";
}
public static String validateAndNormalizePath(String path) {
path = path.replaceAll("/../", "/");
path = path.replaceAll("/%46%46/", "/");
path = SecurityUtil.cleanIt(path);
path = FilenameUtils.normalize(path); // normalize path
return path;
}
public static String sanitizePathValue(String filename){
filename = validateAndNormalizePath(filename);
String regEx = "..|\\|/";
// compile the regex to create pattern
// using compile() method
Pattern pattern = Pattern.compile(regEx);
// get a matcher object from pattern
Matcher matcher = pattern.matcher(filename);
// check whether Regex string is
// found in actualString or not
boolean matches = matcher.matches();
if(matches){
throw new MyAppRuntimeException("filename:'"+filename+"' is bad.");
}
return filename;
}
public static String validateAndNormalizePath(String path) {
path = path.replaceAll("/../", "/");
path = path.replaceAll("/%46%46/", "/");
path = SecurityUtil.cleanIt(path);
path = FilenameUtils.normalize(path); // normalize path
return path;
}
[Attempt] - Update code which I tried with the help of few members to prevent path traversal issue.
Tried to sanitize string and normalize string, but no luck and getting same issue.
How to resolve Stored Absolute Path Traversal issue ?
Your first attempt is not going to work because escaping alone isn't going to prevent a path traversal. Replacing single quotes with double quotes won't do it either given you need to make sure someone setting a property/env variable with ../../etc/resolv.conf doesn't succeed in tricking your code into overwriting/reading a sensitive file. I believe Checkmarx won't look for StringUtils as part of recognizing it as sanitized, so the simple working example below is similar without using StringUtils.
Your second attempt won't work because it is a validator that uses control flow to prevent a bad input when it throws an exception. Checkmarx analyzes data flows. When filename is passed as a parameter to sanitizePathValue and returned as-is at the end, the data flow analysis sees this as not making a change to the original value.
There also appears to be some customizations in your system that recognize System.getProperty and System.getenv as untrusted inputs. By default, these are not recognized in this way, so anyone trying to scan your code probably would not have gotten any results for Absolute Path Traversal. It is possible that the risk profile of your application requires that you call properties and environment variables as untrusted inputs, so you can't really just remove these and revert back to the OOTB settings.
As Roman had mentioned, the logic in the query does look for values that are prepended to this untrusted input to remove those data flows as results. The below code shows how this could be done using Roman's method to trick the scanner. (I highly suggest you do not choose the route to trick the scanner.....very bad idea.) There could be other string literal values that would work using this method, but it would require some actions that control how the runtime is executed (like using chroot) to make sure it actually fixed the issue.
If you scan the code below, you should see only one vulnerable data path. The last example is likely something along the lines of what you could use to remediate the issues. It really depends on what you're trying to do with the file being created.
(I tested this on 9.2; it should work for prior versions. If it doesn't work, post your version and I can look into that version's query.)
// Vulnerable
String fn1 = System.getProperty ("test");
File f1 = new File(fn1);
// Path prepend - still vulnerable, tricks the scanner, DO NOT USE
String fn2 = System.getProperty ("test");
File f2 = new File(Paths.get ("", fn2).toString () );
// Path prepend - still vulnerable, tricks the scanner, DO NOT USE
String fn3 = System.getProperty ("test");
File f3 = new File("" + fn3);
// Path prepend - still vulnerable, tricks the scanner, DO NOT USE
String fn4 = System.getProperty ("test");
File f4 = new File("", fn4);
// Sanitized by stripping path separator as defined in the JDK
// This would be the safest method
String fn5 = System.getProperty ("test");
File f5 = new File(fn5.replaceAll (File.separator, ""));
So, in summary (TL;DR), replace the file separator in the untrusted input value:
String fn5 = System.getProperty ("test");
File f5 = new File(fn5.replaceAll (File.separator, ""));
Edit
Updating for other Checkmarx users that may come across this in search of an answer.
After my answer, OP updated the question to reveal that the issue being found was due to a mechanism written for the code to run in different environments. Pre-docker, this would have been the method to use. The vulnerability would have still been detected but most courses of action would have been to say "our deployment environment has security measures around it to prevent a bad actor from injecting an undesired path into the environment variable where we store our base path."
But now, with Docker, this is a thing of the past. Generally the point of Docker is to create applications that run the way same everywhere they are deployed. Using a base path in an environment likely means OP is executing the code outside of a container for development (based on the update showing a Windows path) and inside the container for deployment. Why not just run the code in the container for development as well as deployment as is intended by Docker?
Most of the answers tend to explain that OP should use a static path. This is because they are realizing that there is no way to avoid this issue because taking an untrusted input (from the environment) and prefixing it to a path is the exact problem of Absolute Path Traversal.
OP could follow the good advice of many posters here and put a static base path in the code then use Docker volumes or Docker bind mounts.
Is it difficult? Nope. If I were OP, I'd fix the base path prefix in code to a static value of /app/data and do a simple volume binding during development. (When you think about it, if there is storage of data in the container during a deployment then the deployment environment must be doing this exact thing for /app/data unless the data is not kept after the lifetime of the container.)
With the base path fixed at /app/data, one option for OP to run their development build is:
docker run -it -v"C:\\projects\\app\\data":/app/data {container name goes here}
All data written by the application would appear in C:\projects\app\data the same way it does when using the environment variables. The main difference is that there are no environment-variable-prefixed paths and thus no Absolute Path Traversal results from the static analysis scanner.
It depends on how Checkmarx comes to this point. Most likely because the value that is handed to File is still tainted. So make sure both /../ and /%46%46/ are replaced by /.
checkedInput = userInput.replaceAll("/../", "/");
Secondly, give File a parent directory to start with and later compare the path of the file you want to process. Some common example code is below. If the file doesn't start with the full parent directory, then it means you have a path traversal.
File file = new File(BASE_DIRECTORY, userInput);
if (file.getCanonicalPath().startsWith(BASE_DIRECTORY)) {
// process file
}
Checkmarx can only check if variables contain a tainted value and in some cases if the logic is correct. Please also think about the running process and file system permissions. A lot of applications have the capability of overwriting their own executables.
If there is one thing to remember it is this
use allow lists not deny lists
(traditionally known as whitelists and blacklists).
For instance, consider replacing /../ with / suggested in another answer. My response is to contain the sequence /../../. You could pursue this iteratively, and I might run out of adversarial examples, but that doesn't mean there are any.
Another problem is knowing all the special characters. \0 used to truncate the file name. What happens to non-ASCII characters - I can't remember. Might other code be changed in future so that the path ends up on a command line with other special characters - worse, OS/command line dependent.
Canonicalisation has its problems too. It can be used to some extent probe the file system (and perhaps beyond the machine).
So, choose what you allow. Say
if (filename.matches("[a-zA-Z0-9_]+")) {
return filename;
} else {
throw new MyException(...);
}
(No need to go through the whole Pattern/Matcher palaver in this situation.)
For this issue i would suggest you hard code the absolute path of the directory that you allow your program to work in; like this:
String separator = FileSystems.getDefault().getSeparator();
// should resolve to /app/workdir in linux
String WORKING_DIR = separator + "app"+separator +"workdir"+separator ;
then when you accept the parameter treat it as a relative path like this:
String filename = System.getProperty("test");
sanitize(filename);
filename = WORKING_DIR+filename;
File dictionaryFile = new File(filename);
To sanitize your user's input make sure he does not include .. and does not include also \ nor /
private static void sanitize(filename){
if(Pattern.compile("\\.\\.|\\|/").matcher(filename).find()){
throw new RuntimeException("filename:'"+filename+"' is bad.");
}
}
Edit
In case you are running the process in linux you can change the root of the process using chroot maybe you do some googling to know how you should implement it.
how about using Java's Path to make the check("../test1.txt" is the input from user):
File base=new File("/your/base");
Path basePath=base.toPath();
Path resolve = basePath.resolve("../test1.txt");
Path relativize = basePath.relativize(resolve);
if(relativize.startsWith("..")){
throw new Exception("invalid path");
}
Based on reading the Checkmarx query for absolute path traversal vulnerability (and I believe in general one of the mitigation approach), is to prepend a hard coded path to avoid the attackers traversing through the file system:
File has a constructor that accepts a second parameter that will allow you to perform some prepending
String filename = System.getEnv("test");
File dictionaryFile = new File("/home/", filename);
UPDATE:
The validateAndNormalizePath would have technically sufficed but I believe Checkmarx is unable to recognize this as a sanitizer (being a custom written function). I would advice to work with your App Security team for them to use the CxAudit and overwrite the base Stored Path Traversal Checkmarx query to recognize validateAndNormalizePath as a valid sanitizer.
This question already has answers here:
How to split a path platform independent?
(6 answers)
How to get the path string from a java.nio.Path?
(2 answers)
Where to use resolve() and relativize() method of java.nio.file.Path class?
(5 answers)
Create a Path from String in Java7
(4 answers)
Recursively list files in Java
(30 answers)
Closed 4 years ago.
I'm currently working on a search output system that searches a directory for a specific phrase in a file, matches it, then outputs it to a log file. I have a problem snippet of code that looks like this:
int j = 0;
for(String currentMatch : lineMatch) {
String[] split = fileList.get(j).toString().split("\\\\");
match.write(split[3] + " : " + currentMatch + "\r\n");
match.flush();
j++;
}
With fileList being an arraylist of the file names with a matching result and filePath being an arraylist of the file path. I used the split[3] to return the name of the the forth folder in this directory that I'm interested in.
The output file then becomes a little funky. This directory in question has roughly 40 unique names, but the log ends up looking like this:
dir1 : matchingline
dir2 : matchingline
dir3 : matchingline
dir3 : matchingline
... (x543)
dir4 : matchingline
And so on. Directory 3 is only supposed to have 88 matching lines and ends up with an additional 455 lines that belong to other directories. Any idea on why this happens? Is it because I'm using an assignment in the middle of a PrintWriter, or am I missing something simple here?
Edit: Variables listed for clarity.
match = Printwriter object used to print to an output.
lineMatch = ArrayList() - contains the directory path of the current matched file
fileMatch = ArrayList() - contains the file name that was matched.
split[3] is used because the matched files are consistently found in the 4th directory in, ex. C:\User\Programs\Programname\
/r/n is used to keep formatting on windows.
This is a personal project, so I'm not too concerned with making it portable.
Edited to add the method used for initializing the arraylist.
public static void addFiles(String dirPath) {
File dir = new File(dirPath);
File[] files = dir.listFiles();
try {
if(files.length == 0) {
emptyFilePath.add(dirPath);
}
else {
for (File currentFile : files) {
if(currentFile.isFile()) {
fileList.add(currentFile);
filePath.add(currentFile.getPath());
}
else if (currentFile.isDirectory()) {
addFiles(currentFile.getAbsolutePath());
}
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
And the code that generates lineMatch:
while(i < fileList.size()) {
File files = new File(filePath.get(i));
Scanner file = new Scanner(files);
try {
while(file.hasNextLine()) {
String currentLine = file.nextLine();
if(currentLine.contains(searchString)) {
lineMatch.add(currentLine);
}
}
}finally {
file.close();
}
i++;
}
There are a number of things that are suspicious about your code.
Are LineMatch and FileList variables? If so, then you should write them like variables, that is, lineMatch and fileList (lowerCamelCase). Doing otherwise confuses readers and syntax highlighters alike.
You use split[3], that looks suspicious.
If you are using split("\\\\") in order to get the directory path parts, beware that your code is non-portable, it will work on Windows only. If you want to split a path into its parts, it's better to use the API.
In order to understand the problem, it would be useful to see how LineMatch and FileList are generated, without that, it's not possible to understand what's going wrong in your code.
If match is a PrintWriter or PrintStream, you should use println() or format("...%n") instead of write(... + "\r\n"). Again, because your code is not portable. On Unix, line endings are \n only, not \r\n.
The actual problem is with your program logic. Your variable lineMatch contains the hits of all files found. Because you don't generate a separate lineMatch for each file, but just a single one for all files. At least that's how it looks like from the code that you've posted so far.
It looks like what you want to program is a simple version of grep (or, on DOS, find). Part of your logic is correct, for example, how you use recursion to descend in to the directory tree. Instead of collecting all matches and then printing, find and print the matches while you're traversing the directory tree.
In general, you will end up with less errors if you avoid global variables. You ran into a problem in the first place because your variables LineMatch and FileList are global variables. Avoid global variables, avoid reusing variables, and also avoid variable re-assignment.
I am trying to save and load files on a project that is coded on libgdx. Which means that i cant use a buffered reader because android wont read it.. and i cant move the project to android because it has to be in the core... after days and days or understanding all.. now i am trying File handing which should work right?? but i cant get it to read line by line.. it puts all the text in on string.. Help plzz.. also is my understanding correct and saving and loading is waaaay more complicated than it should be?? here is the code..
FileHandle handle = Gdx.files.local("words.txt");
String text = handle.readString();
words.add(text);
There are several ways to read this line by line. When your reading a file in using the LibGDX FileHandle API which include strings, byte arrays and into various readers; there are several ways to read the data in. I am assuming you have some form of dictionary in this file, with the words in a list separated by newlines? If this is the case you can take your existing string and split on the new line terminator.
FileHandle handle = Gdx.files.local("words.txt");
String text = handle.readString();
String wordsArray[] = text.split("\\r?\\n");
for(String word : wordsArray) {
words.add(word);
}
There's only really two newlines (UNIX and Windows) that you need to worry about.
FileHandle API
This is to all of you out there new to saving and loading and tired of looking for answers.. let me save u the trouble and days of research...
If you start a project in libgdx and want to save load on android.. Do not follow the buffered reader or inputstreamer or any of these tutorials THEY WILL NOT WORK because for some reason android cannot read inside the assest folder.. it will work on ur desktop version only..
if you are using android studios alone then go ahead with the try catch buffered or file or inputstreamer..
Also the Context.. asset manager.. and that route WILL NOT WORK because the project has to be in your android folder not core to use these libraries..
ELSE FOLLOW THE ABOVE METHOD..
classpath.. internal.. external .. or local ... depending on where you store ur file!!!.. your welcome
String str ="";
StringBuffer buf = new StringBuffer();
FileHandle file = Gdx.files.internal("text.txt");
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(file.read()));
if (is != null) {
while ((str = reader.readLine()) != null) {
buf.append(str + "\n" );
}
}
} finally {
try { is.close(); } catch (Throwable ignore) {}
}
I have a text file (file.txt) which contains multiple lines:
/location/test/file.csv
/location/test1/file2.csv
/location/test2/file.exe
Using ECMA, I would like to replace all instance of "/" with "\". However, the code below only replaces the first line and eliminate lines 2 and 3.
This is the result of the file.txt file after I run the code (as I said, lines 2 and 3 are missing):
\location\test\file.csv
Can anyone please help?
function ReadFile ()
{
var file = new java.io.BufferedReader(new java.io.FileReader("C:\\Test\\file.txt"));
var fileWriter = new java.io.FileWriter("C:\\Test\\file.txt",false);
while ((line = file.readLine()) != null)
{
println(line);
if (line.contains ("/"))
line = line.replace("/","\\");
fileWriter.write(line);
fileWriter.close();
}
}
ReadFile ();
So I managed to run this code using Rhino. It does in fact run. I made some changes to filenames in order to get it running on my mac, but it is essentially the same code:
function ReadFile () {
var file = new java.io.BufferedReader(new java.io.FileReader("file"));
var fileWriter = new java.io.FileWriter("file2",false);
while ((line = file.readLine()) != null) {
if (line.contains ("/"))
line = line.replace("/","\\");
fileWriter.write(line + "\n");
}
fileWriter.close();
file.close();
}
ReadFile ();
So the bugs you had were:
Reading and writing to the same file. This is awkward using streams. Basically, don't do it. I changed it to write to file2.
Closing the writer inside your reader loop. Close the writer at the end, once closed, you can no longer write to it.
Not closing the file you are reading from.
For those interested in how I got this running, on OS X, using rhino:
brew install rhino
rhino example.js
I had to remove the println because that wasn't recognised but that wasn't a critical part. JS on the JVM. Fun! Except nothing is async.....
There are other JS engines too, but rhino worked.
JavaScript String object has a replace method that takes a regular expression that can replace characters in a String. However, the Java in your JavaScript won't work because you are mixing up two languages.
http://www.w3schools.com/jsref/jsref_replace.asp
The problem is that you're writing over the file as you're reading it, so as soon as your first write(line) completes, the file no longer has the next two lines. Either use a second, temporary file to write to until you've finished processing the file, or keep a list/array of all the new lines in memory, and then write out the file at the end.
I'm really curious to know, though, how you managed to get your current program to even run. In my experience, Java and ECMA/Javascript are two completely separate languages, but it looks like you're using javascript code against Java libraries. What's up with that?
Java's File.renameTo() is problematic, especially on Windows, it seems.
As the API documentation says,
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 return value should always
be checked to make sure that the
rename operation was successful.
In my case, as part of an upgrade procedure, I need to move (rename) a directory that may contain gigabytes of data (lots of subdirectories and files of varying sizes). The move is always done within the same partition/drive, so there's no real need to physically move all the files on disk.
There shouldn't be any file locks to the contents of the dir to be moved, but still, quite often, renameTo() fails to do its job and returns false. (I'm just guessing that perhaps some file locks expire somewhat arbitrarily on Windows.)
Currently I have a fallback method that uses copying & deleting, but this sucks because it may take a lot of time, depending on the size of the folder. I'm also considering simply documenting the fact that the user can move the folder manually to avoid waiting for hours, potentially. But the Right Way would obviously be something automatic and quick.
So my question is, do you know an alternative, reliable approach to do a quick move/rename with Java on Windows, either with plain JDK or some external library. Or if you know an easy way to detect and release any file locks for a given folder and all of its contents (possibly thousands of individual files), that would be fine too.
Edit: In this particular case, it seems we got away using just renameTo() by taking a few more things into account; see this answer.
See also the Files.move() method in JDK 7.
An example:
String fileName = "MyFile.txt";
try {
Files.move(new File(fileName).toPath(), new File(fileName).toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
Logger.getLogger(SomeClass.class.getName()).log(Level.SEVERE, null, ex);
}
For what it's worth, some further notions:
On Windows, renameTo() seems to fail if the target directory exists, even if it's empty. This surprised me, as I had tried on Linux, where renameTo() succeeded if target existed, as long as it was empty.
(Obviously I shouldn't have assumed this kind of thing works the same across platforms; this is exactly what the Javadoc warns about.)
If you suspect there may be some lingering file locks, waiting a little before the move/rename might help. (In one point in our installer/upgrader we added a "sleep" action and an indeterminate progress bar for some 10 seconds, because there might be a service hanging on to some files). Perhaps even do a simple retry mechanism that tries renameTo(), and then waits for a period (which maybe increases gradually), until the operation succeeds or some timeout is reached.
In my case, most problems seem to have been solved by taking both of the above into account, so we won't need to do a native kernel call, or some such thing, after all.
The original post requested "an alternative, reliable approach to do a quick move/rename with Java on Windows, either with plain JDK or some external library."
Another option not mentioned yet here is v1.3.2 or later of the apache.commons.io library, which includes FileUtils.moveFile().
It throws an IOException instead of returning boolean false upon error.
See also big lep's response in this other thread.
On windows i use Runtime.getRuntime().exec("cmd \\c ") and then use commandline rename function to actually rename files. It is much more flexible, e.g if you want to rename extension of all txt files in a dir to bak just write this to output stream:
rename *.txt *.bak
I know it is not a good solution but apparently it has always worked for me, much better then Java inline support.
In my case it seemed to be a dead object within my own application, which kept a handle to that file. So that solution worked for me:
for (int i = 0; i < 20; i++) {
if (sourceFile.renameTo(backupFile))
break;
System.gc();
Thread.yield();
}
Advantage: it is pretty quick, as there is no Thread.sleep() with a specific hardcoded time.
Disadvantage: that limit of 20 is some hardcoded number. In all my tests, i=1 is enough. But to be sure I left it at 20.
I know this seems a little hacky, but for what I've been needing it for, it seems buffered readers and writers have no issue making the files.
void renameFiles(String oldName, String newName)
{
String sCurrentLine = "";
try
{
BufferedReader br = new BufferedReader(new FileReader(oldName));
BufferedWriter bw = new BufferedWriter(new FileWriter(newName));
while ((sCurrentLine = br.readLine()) != null)
{
bw.write(sCurrentLine);
bw.newLine();
}
br.close();
bw.close();
File org = new File(oldName);
org.delete();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
Works well for small text files as part of a parser, just make sure oldName and newName are full paths to the file locations.
Cheers
Kactus
The following piece of code is NOT an 'alternative' but has reliably worked for me on both Windows and Linux environments:
public static void renameFile(String oldName, String newName) throws IOException {
File srcFile = new File(oldName);
boolean bSucceeded = false;
try {
File destFile = new File(newName);
if (destFile.exists()) {
if (!destFile.delete()) {
throw new IOException(oldName + " was not successfully renamed to " + newName);
}
}
if (!srcFile.renameTo(destFile)) {
throw new IOException(oldName + " was not successfully renamed to " + newName);
} else {
bSucceeded = true;
}
} finally {
if (bSucceeded) {
srcFile.delete();
}
}
}
Why not....
import com.sun.jna.Native;
import com.sun.jna.Library;
public class RenamerByJna {
/* Requires jna.jar to be in your path */
public interface Kernel32 extends Library {
public boolean MoveFileA(String existingFileName, String newFileName);
}
public static void main(String[] args) {
String path = "C:/yourchosenpath/";
String existingFileName = path + "test.txt";
String newFileName = path + "renamed.txt";
Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
kernel32.MoveFileA(existingFileName, newFileName);
}
}
works on nwindows 7, does nothing if existingFile does not exist, but obviously could be better instrumented to fix this.
I had a similar issue. File was copied rather moving on Windows but worked well on Linux. I fixed the issue by closing the opened fileInputStream before calling renameTo(). Tested on Windows XP.
fis = new FileInputStream(originalFile);
..
..
..
fis.close();// <<<---- Fixed by adding this
originalFile.renameTo(newDesitnationForOriginalFile);
In my case, the error was in the path of the parent directory. Maybe a bug, I had to use the substring to get a correct path.
try {
String n = f.getAbsolutePath();
**n = n.substring(0, n.lastIndexOf("\\"));**
File dest = new File(**n**, newName);
f.renameTo(dest);
} catch (Exception ex) {
...
Well I have found a pretty straight forward solution to this problem -
boolean retVal = targetFile.renameTo(new File("abcd.xyz"));
while(!retVal) {
retVal= targetFile.renameTo(new File("abcd.xyz"));
}
As suggested by Argeman, you can place a counter and limit the number of times the while loop will run so that it doesn't get into an infinite loop in case of some file are being used by another windows process.
int counter = 0;
boolean retVal = targetFile.renameTo(new File("abcd.xyz"));
while(!retVal && counter <= 10) {
retVal = targetFile.renameTo(new File("abcd.xyz"));
counter = counter + 1;
}
I know it sucks, but an alternative is to create a bat script which outputs something simple like "SUCCESS" or "ERROR", invoke it, wait for it to be executed and then check its results.
Runtime.getRuntime().exec("cmd /c start test.bat");
This thread may be interesting. Check also the Process class on how to read the console output of a different process.
You may try robocopy. This is not exactly "renaming", but it's very reliable.
Robocopy is designed for reliable mirroring of directories or directory trees. It has features to ensure all NTFS attributes and properties are copied, and includes additional restart code for network connections subject to disruption.
To move/rename a file you can use this function:
BOOL WINAPI MoveFile(
__in LPCTSTR lpExistingFileName,
__in LPCTSTR lpNewFileName
);
It is defined in kernel32.dll.
File srcFile = new File(origFilename);
File destFile = new File(newFilename);
srcFile.renameTo(destFile);
The above is the simple code. I have tested on windows 7 and works perfectly fine.