/*::.
==================================================================================================================================
=================================================¦ Copyright © 2002 Allen Baker ¦=================================================
+------------------------------+
File: XFile.java
Originator: Allen Baker (2002.12.19 23:05)
LayoutRev: 5
================================================================================================================================== */
/*.
==========================================================================================
Package
------------------------------------------------------------------------------------------ */
package cosmicabyss.com.lib;
/*.
==========================================================================================
Imports
------------------------------------------------------------------------------------------ */
import java.io.*;
import java.net.*;
import java.util.*;
import java.nio.channels.FileChannel;
import java.security.*;
import java.lang.reflect.*;
/*::
======================================================================================================================== *//**
This class provides methods to supplement the capabilities provided by a class that is part of the JDK, J2EE, or some
other 3rd party library. The extensions are provided by way of this subclass of the 3rd party class.<P>
In particular, this class extends the capabilities of the File class. Like the File class, this class provides methods
that manipulate and get parts of a file's name or path and retrieve other information about a file that the File class
does not. Unlike the File class, this class also provides methods for modifying the content of the file; among others,
this includes methods that encrypt, decrypt, copy, and append the file. The class provides a number of other
miscellaneous file management methods as well.
<P>
<DL>
<DT>
<B>
Example usage:
</B>
<DD>
<BLOCKQUOTE>
<PRE id="unindent">
no example provided
</PRE>
</BLOCKQUOTE>
</DD>
</DT>
<DT>
<B>
View Source:
</B>
<DD>
<A href="XFile.java.html">
xFile.java
</A>
</DD>
</DT>
<DT>
<B>
Author:
</B>
<DD>
<A href="mailto:sourcecode.v01@cosmicabyss.com">
Allen Baker
</A>
</DD>
</DT>
</DL>
*//*
======================================================================================================================== */
public class XFile extends File
{
/*: :METHOD:000:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method creates an instance of the XFile class.
<P><B>Implementation: </B><A HREF="XFile.java.html#000">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> XFile(File parent, Type child)
{
super(parent, UString.toString(child));
}
/*: :METHOD:001:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method creates an instance of the XFile class.
<P><B>Implementation: </B><A HREF="XFile.java.html#001">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> XFile(Type pathname)
{
super(UString.toString(pathname));
}
/*: :METHOD:002:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method creates an instance of the XFile class.
<P><B>Implementation: </B><A HREF="XFile.java.html#002">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public <Type1,Type2> XFile(Type1 parent, Type2 child)
{
super(UString.toString(parent),UString.toString(child));
}
/*: :METHOD:003:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method creates an instance of the XFile class.
<P><B>Implementation: </B><A HREF="XFile.java.html#003">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public XFile(URI uri)
{
super(uri);
}
/*: :METHOD:004:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method creates an instance of the XFile class.
<P><B>Implementation: </B><A HREF="XFile.java.html#004">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public XFile(File file) throws Exception
{
super(file.getCanonicalPath());
}
/*: :METHOD:005:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method encrypts the file.
<P><B>Implementation: </B><A HREF="XFile.java.html#005">View source</A>
@param
pPassword is the password that will be used to encrypt and/or decrypt the file.
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public void encrypt(Password pPassword, int pIterations) throws Exception
{
/*.
==========================================================================================
This method makes no sense on directory files, this must be a normal file
------------------------------------------------------------------------------------------ */
if (this.isDirectory()) return;
/*.
==========================================================================================
Set up the FileCipher object to encrypt this file.
------------------------------------------------------------------------------------------ */
if (iCipher == null)
{
iCipher = new FileCipher
(
this.getCanonicalPath(),
pPassword,
pIterations
);
}
/*.
==========================================================================================
Encrypt the file
------------------------------------------------------------------------------------------ */
iCipher.encrypt();
}
/*: :METHOD:006:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method encrypts the file the FileCipher's default number of times.
<P><B>Implementation: </B><A HREF="XFile.java.html#006">View source</A>
@param
pPassword is the password that will be used to encrypt and/or decrypt the file.
*//*
---------------------------------------------------------------------------------------------------- */
public void encrypt(Password pPassword) throws Exception
{
/*.
==========================================================================================
This method makes no sense on directory files, this must be a normal file
------------------------------------------------------------------------------------------ */
if (this.isDirectory()) return;
/*.
==========================================================================================
Set up the FileCipher object to encrypt this file.
------------------------------------------------------------------------------------------ */
if (iCipher == null)
{
iCipher = new FileCipher
(
this.getCanonicalPath(),
pPassword
);
}
/*.
==========================================================================================
Encrypt the file
------------------------------------------------------------------------------------------ */
iCipher.encrypt();
}
/*: :METHOD:007:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method encrypts the file using the FileCipher's default password.
<P><B>Implementation: </B><A HREF="XFile.java.html#007">View source</A>
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public void encrypt(int pIterations) throws Exception
{
/*.
==========================================================================================
Since no password was specified, use the default password
------------------------------------------------------------------------------------------ */
Password password = new Password();
/*.
==========================================================================================
Encrypt the file
------------------------------------------------------------------------------------------ */
this.encrypt(password,pIterations);
}
/*: :METHOD:008:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method encrypts the file the FileCipher's default number of times using the FileCipher's
default password.
<P><B>Implementation: </B><A HREF="XFile.java.html#008">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void encrypt() throws Exception
{
/*.
==========================================================================================
Since no password was specified, use the default password
------------------------------------------------------------------------------------------ */
Password password = new Password();
/*.
==========================================================================================
Encrypt the file
------------------------------------------------------------------------------------------ */
this.encrypt(password);
}
/*: :METHOD:009:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method encrypts the file.
<P><B>Implementation: </B><A HREF="XFile.java.html#009">View source</A>
@param
pPwd is the password XString that will be used to encrypt and/or decrypt the file.
@param
pPwdCount is the number of times the password XString is hashed before it is used to encrypt
and/or decrypt the file.
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> void encrypt(Type pPwd, int pPwdCount, int pIterations) throws Exception
{
/*.
==========================================================================================
Create the password
------------------------------------------------------------------------------------------ */
Password password = (new Password(UString.toString(pPwd))).iterate(pPwdCount);
/*.
==========================================================================================
Encrypt the file
------------------------------------------------------------------------------------------ */
this.encrypt(password,pIterations);
}
/*: :METHOD:010:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method encrypts the file after hashing the password XString the Password object's default
number of times.
<P><B>Implementation: </B><A HREF="XFile.java.html#010">View source</A>
@param
pPwd is the password XString that will be used to encrypt and/or decrypt the file.
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> void encrypt(Type pPwd, int pIterations) throws Exception
{
/*.
==========================================================================================
Create the password
------------------------------------------------------------------------------------------ */
Password password = new Password(UString.toString(pPwd));
/*.
==========================================================================================
Encrypt the file
------------------------------------------------------------------------------------------ */
this.encrypt(password,pIterations);
}
/*: :METHOD:011:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method encrypts the file the FileCipher's default number of times after hashing the password
xString the Password object's default number of times.
<P><B>Implementation: </B><A HREF="XFile.java.html#011">View source</A>
@param
pPwd is the password XString that will be used to encrypt and/or decrypt the file.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> void encrypt(Type pPwd) throws Exception
{
/*.
==========================================================================================
Create the password
------------------------------------------------------------------------------------------ */
Password password = new Password(UString.toString(pPwd));
/*.
==========================================================================================
Encrypt the file
------------------------------------------------------------------------------------------ */
this.encrypt(password);
}
/*: :METHOD:012:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method encrypts the file using the Password object's default password XString.
<P><B>Implementation: </B><A HREF="XFile.java.html#012">View source</A>
@param
pPwdCount is the number of times the password XString is hashed before it is used to encrypt
and/or decrypt the file.
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public void encrypt(int pPwdCount, int pIterations) throws Exception
{
/*.
==========================================================================================
Create the password
------------------------------------------------------------------------------------------ */
Password password = (new Password()).iterate(pPwdCount);
/*.
==========================================================================================
Encrypt the file
------------------------------------------------------------------------------------------ */
this.encrypt(password,pIterations);
}
/*: :METHOD:013:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method decrypts the file.
<P><B>Implementation: </B><A HREF="XFile.java.html#013">View source</A>
@param
pPassword is the password that will be used to encrypt and/or decrypt the file.
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the decrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public void decrypt(Password pPassword, int pIterations) throws Exception
{
/*.
==========================================================================================
This method makes no sense on directory files, this must be a normal file
------------------------------------------------------------------------------------------ */
if (this.isDirectory()) return;
/*.
==========================================================================================
Set up the FileCipher object to decrypt this file.
------------------------------------------------------------------------------------------ */
if (iCipher == null)
{
iCipher = new FileCipher
(
this.getCanonicalPath(),
pPassword,
pIterations
);
}
/*.
==========================================================================================
Decrypt the file
------------------------------------------------------------------------------------------ */
iCipher.decrypt();
}
/*: :METHOD:014:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method decrypts the file the FileCipher's default number of times.
<P><B>Implementation: </B><A HREF="XFile.java.html#014">View source</A>
@param
pPassword is the password that will be used to encrypt and/or decrypt the file.
*//*
---------------------------------------------------------------------------------------------------- */
public void decrypt(Password pPassword) throws Exception
{
/*.
==========================================================================================
This method makes no sense on directory files, this must be a normal file
------------------------------------------------------------------------------------------ */
if (this.isDirectory()) return;
/*.
==========================================================================================
Set up the FileCipher object to decrypt this file.
------------------------------------------------------------------------------------------ */
if (iCipher == null)
{
iCipher = new FileCipher
(
this.getCanonicalPath(),
pPassword
);
}
/*.
==========================================================================================
Decrypt the file
------------------------------------------------------------------------------------------ */
iCipher.decrypt();
}
/*: :METHOD:015:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method decrypts the file using the FileCipher's default password.
<P><B>Implementation: </B><A HREF="XFile.java.html#015">View source</A>
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public void decrypt(int pIterations) throws Exception
{
/*.
==========================================================================================
Since no password was specified, use the default password
------------------------------------------------------------------------------------------ */
Password password = new Password();
/*.
==========================================================================================
Decrypt the file
------------------------------------------------------------------------------------------ */
this.decrypt(password,pIterations);
}
/*: :METHOD:016:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method decrypts the file the FileCipher's default number of times using the FileCipher's
default password.
<P><B>Implementation: </B><A HREF="XFile.java.html#016">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void decrypt() throws Exception
{
/*.
==========================================================================================
Since no password was specified, use the default password
------------------------------------------------------------------------------------------ */
Password password = new Password();
/*.
==========================================================================================
Decrypt the file
------------------------------------------------------------------------------------------ */
this.decrypt(password);
}
/*: :METHOD:017:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method decrypts the file.
<P><B>Implementation: </B><A HREF="XFile.java.html#017">View source</A>
@param
pPwd is the password XString that will be used to encrypt and/or decrypt the file.
@param
pPwdCount is the number of times the password XString is hashed before it is used to decrypt
and/or decrypt the file.
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> void decrypt(Type pPwd, int pPwdCount, int pIterations) throws Exception
{
/*.
==========================================================================================
Create the password
------------------------------------------------------------------------------------------ */
Password password = (new Password(UString.toString(pPwd))).iterate(pPwdCount);
/*.
==========================================================================================
Decrypt the file
------------------------------------------------------------------------------------------ */
this.decrypt(password,pIterations);
}
/*: :METHOD:018:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method decrypts the file after hashing the password XString the Password object's default
number of times.
<P><B>Implementation: </B><A HREF="XFile.java.html#018">View source</A>
@param
pPwd is the password XString that will be used to encrypt and/or decrypt the file.
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> void decrypt(Type pPwd, int pIterations) throws Exception
{
/*.
==========================================================================================
Create the password
------------------------------------------------------------------------------------------ */
Password password = new Password(UString.toString(pPwd));
/*.
==========================================================================================
Decrypt the file
------------------------------------------------------------------------------------------ */
this.decrypt(password,pIterations);
}
/*: :METHOD:019:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method decrypts the file the FileCipher's default number of times after hashing the password
xString the Password object's default number of times.
<P><B>Implementation: </B><A HREF="XFile.java.html#019">View source</A>
@param
pPwd is the password XString that will be used to encrypt and/or decrypt the file.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> void decrypt(Type pPwd) throws Exception
{
/*.
==========================================================================================
Create the password
------------------------------------------------------------------------------------------ */
Password password = new Password(UString.toString(pPwd));
/*.
==========================================================================================
Decrypt the file
------------------------------------------------------------------------------------------ */
this.decrypt(password);
}
/*: :METHOD:020:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method decrypts the file using the Password object's default password XString.
<P><B>Implementation: </B><A HREF="XFile.java.html#020">View source</A>
@param
pPwdCount is the number of times the password XString is hashed before it is used to decrypt
and/or decrypt the file.
@param
pIterations is the number of times the file will be run through the encryption and/or decryption
algorithm when the encrypt and/or decrypt method is called. If this value is 1 or less, the file
will be run through 1 time.
*//*
---------------------------------------------------------------------------------------------------- */
public void decrypt(int pPwdCount, int pIterations) throws Exception
{
/*.
==========================================================================================
Create the password
------------------------------------------------------------------------------------------ */
Password password = (new Password()).iterate(pPwdCount);
/*.
==========================================================================================
Decrypt the file
------------------------------------------------------------------------------------------ */
this.decrypt(password,pIterations);
}
/*: :METHOD:021:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method returns the canonical path name of the directory that this file is in - always without a
trailing '\'.
If the file is in the root directory, then on Windows this method returns a string containing the
drive specifier such as "C:". On Unix, it would probably return the empty string.
This method is needed because Java's getParent*() methods work from the name of the file given to
the constructor and do not necessarily return a complete parent path. This code shows the problem
with Java's standard methods:
<BLOCKQUOTE>
<PRE id="unindent">
* // Get the parent of a relative filename path
* File file = new File("Ex1.java");
* XString parentPath = file.getParent(); // null
* File parentDir = file.getParentFile(); // null
*
* // Get the parents of an absolute filename path
* file = new File("D:/almanac/Ex1.java");
* parentPath = file.getParent(); // D:\almanac
* parentDir = file.getParentFile(); // D:\almanac
</PRE>
</BLOCKQUOTE>
<P><B>Implementation: </B><A HREF="XFile.java.html#021">View source</A>
@return
The canonical path name of the directory that this file is in - always without a trailing '\'.
*//*
---------------------------------------------------------------------------------------------------- */
public XString getCanonicalParent() throws Exception
{
XString result = new XString((new File(this.getCanonicalPath())).getParent());
result = result.trimRight("\\");
return result;
}
/*: :METHOD:022:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method returns the extension part of the file name (the part of the file name that follows the
last '.' character in the file name.
<P><B>Implementation: </B><A HREF="XFile.java.html#022">View source</A>
@return
The extension part of the file name (the part of the file name that follows the last '.'
character in the file name, or the empty string if this file's extension is empty
*//*
---------------------------------------------------------------------------------------------------- */
public XString getExtension()
{
XString fileName = new XString(this.getName());
if (fileName.equals(""))
{
return XString.EMPTY;
}
int lastIndex = fileName.lastIndexOf('.');
if (lastIndex == (-1))
{
return XString.EMPTY;
}
return fileName.substring(lastIndex+1);
}
/*: :METHOD:023:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method returns the name of the file or directory denoted by this abstract pathname, minus its
extension. This is just the last name in the pathname's name sequence with the extension and it's
delimiting '.' removed. If the pathname's name sequence is empty, then the empty string is returned.
<P><B>Implementation: </B><A HREF="XFile.java.html#023">View source</A>
@return
The name of the file or directory denoted by this abstract pathname, minus its extension. This is
just the last name in the pathname's name sequence with the extension and it's delimiting '.'
removed. If the pathname's name sequence is empty, then the empty string is returned.
*//*
---------------------------------------------------------------------------------------------------- */
public XString getExtensionlessName()
{
XString fileName = new XString(this.getName());
if (fileName.equals(""))
{
return XString.EMPTY;
}
if (fileName.endsWith("."))
{
fileName = fileName.trimRight(".");
return fileName;
}
XString extension = this.getExtension();
if (extension.equals(""))
{
return fileName;
}
fileName = fileName.trimRight("." + extension);
return fileName;
}
/*: :METHOD:024:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method returns the canonical name of the file or directory denoted by this abstract pathname,
minus its extension. This is the canonical path with the extension and it's delimiting '.' removed.
If the pathname's name sequence is empty, then the empty string is returned.
<P><B>Implementation: </B><A HREF="XFile.java.html#024">View source</A>
@return
This method returns the canonical name of the file or directory denoted by this abstract
pathname, minus its extension. This is the canonical path with the extension and it's delimiting
'.' removed. If the pathname's name sequence is empty, then the empty string is returned.
*//*
---------------------------------------------------------------------------------------------------- */
public XString getExtensionlessCanonicalPath() throws Exception
{
XString pathName = new XString(this.getCanonicalPath());
if (pathName.equals(""))
{
return XString.EMPTY;
}
if (pathName.endsWith("."))
{
pathName = pathName.trimRight(".");
return pathName;
}
XString extension = this.getExtension();
if (extension.equals(""))
{
return pathName;
}
pathName = pathName.trimRight("." + extension);
return pathName;
}
/*: :METHOD:025:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method returns the canonical name of the file or directory denoted by this abstract pathname,
minus its drive specifier. This is the canonical path with the drive and it's delimiting ':'
removed. If the pathname's name sequence is empty, then the empty string is returned.
<P><B>Implementation: </B><A HREF="XFile.java.html#025">View source</A>
@return
This method returns the canonical name of the file or directory denoted by this abstract
pathname, minus its drive specifier. This is the canonical path with the drive and it's
delimiting ':' removed. If the pathname's name sequence is empty, then the empty string is
returned.
*//*
---------------------------------------------------------------------------------------------------- */
public XString getDrivelessCanonicalPath() throws Exception
{
XString pathName = new XString(this.getCanonicalPath());
if (pathName.equals(""))
{
return XString.EMPTY;
}
ArrayList<XString> tokens = pathName.tokenizedString(":");
if (tokens.size() < 1)
{
return XString.EMPTY;
}
return tokens.get(tokens.size()-1);
}
/*: :METHOD:026:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method returns the canonical name of the parent of the file or directory denoted by this
abstract pathname, minus its drive specifier. This is the canonical path with the drive and it's
delimiting ':' removed. If the pathname's name sequence is empty, then the empty string is returned.
<P><B>Implementation: </B><A HREF="XFile.java.html#026">View source</A>
@return
This method returns the canonical name of the parent of the file or directory denoted by this
abstract pathname, minus its drive specifier. This is the canonical path with the drive and it's
delimiting ':' removed. If the pathname's name sequence is empty, then the empty string is
returned.
*//*
---------------------------------------------------------------------------------------------------- */
public XString getDrivelessParent() throws Exception
{
/*.
==========================================================================================
Get the parent (or directory) for this file.
For some reason, this.getParent() and this.getParentFile() do not work in here -- they
both return null. So this kludge is to get around the problem until I can troubleshoot
and fix it.
File parent = this.getParentFile();
------------------------------------------------------------------------------------------ */
XString path = new XString(this.getCanonicalPath());
path = path.trimRight(File.separator + this.getName());
File parent = new File(path.toString());
/*.
==========================================================================================
Return it without its drive specifier.
------------------------------------------------------------------------------------------ */
if (parent == null)
{
return XString.EMPTY;
}
return (new XFile(parent)).getDrivelessCanonicalPath();
}
/*: :METHOD:027:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method renames the file denoted by this abstract pathname.
<P><B>Implementation: </B><A HREF="XFile.java.html#027">View source</A>
@return
True if and only if the renaming succeeded; false otherwise
@param
pNewName is the new name for the file
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> boolean renameTo(Type pNewName)
{
XFile newFile = new XFile(pNewName);
return renameTo(newFile);
}
/*: :METHOD:028:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method renames the file denoted by this abstract pathname.
<P><B>Implementation: </B><A HREF="XFile.java.html#028">View source</A>
@return
True if and only if the renaming succeeded; false otherwise
@param
pNewFileExt is an XFile object containing the new name for the file.
*//*
---------------------------------------------------------------------------------------------------- */
public boolean renameTo(XFile pNewFileExt)
{
return renameTo((File)pNewFileExt);
}
/*: :METHOD:029:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method is a cover for File.renameTo(). The motivation for this cover method is that with this
new version of Java (1.5.0), rename (and other file methods) sometimes don't work on the first try.
This is because file objects that have been closed are hung onto, pending garbage collection.
<P><B>Implementation: </B><A HREF="XFile.java.html#029">View source</A>
@return
True if and only if the renaming succeeded; false otherwise
@param
pNewFile is a File object containing the new name for the file.
*//*
---------------------------------------------------------------------------------------------------- */
public boolean renameTo(File pNewFile)
{
/*.
==========================================================================================
HACK - I should just be able to call renameTo() here and return its result. In fact, I
used to do just that and this method always worked fine. Now with this new version of Java
(1.5.0), rename (and other file methods) sometimes don't work on the first try. This is
because file objects that have been closed are hung onto, pending garbage collection. By
suggesting garbage collection, the next time, the renameTo() usually (but not always)
works.
------------------------------------------------------------------------------------------ */
for (int i=0; i<20; i++)
{
try
{
if (super.renameTo(pNewFile))
{
return true;
}
System.gc();
Util.sleep(200);
}
catch (Exception e)
{
XString topBanner = new XString("=========================| " + i + " |=========================");
XString botBanner = XString.EMPTY;
botBanner.fill(topBanner.length(), '=');
System.out.println(topBanner);
System.out.println(e.getMessage());
e.printStackTrace();
System.out.println(botBanner);
}
}
return false;
}
/*: :METHOD:030:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method replaces a file's extension.
<BLOCKQUOTE>
<PRE id="unindent">
Example: if the file's name is:
\tuna\test.ex1
and this method is called like this:
XFile myFile = new XFile("\tuna\test.ex1");
myFile.changeExtension("newExt");
then the file would be renamed to:
\tuna\test.newExt
</PRE>
</BLOCKQUOTE>
<P><B>Implementation: </B><A HREF="XFile.java.html#030">View source</A>
@return
True if and only if the renaming succeeded; false otherwise
@param
pNewExt is the new extension for the file
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> boolean changeExtension(Type pNewExt) throws Exception
{
XString fileName = new XString(this.getCanonicalPath());
XString extension = this.getExtension();
if ( ! extension.equals(""))
{
fileName = fileName.trimRight("." + extension);
}
fileName = new XString(fileName.toString() + "." + UString.toString(pNewExt));
return renameTo(fileName.toString());
}
/*: :METHOD:031:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method sets the last-modified time and last-accessed times of the file to the current system
time.
<P><B>Implementation: </B><A HREF="XFile.java.html#031">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void touch()
{
long newTime = (new java.util.Date()).getTime();
this.setLastModified(newTime);
this.setLastAccessed(newTime);
}
/*: :METHOD:032:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method increments the file's last-modified time and last-accessed time by a very small amount
that is just enough for the "xcopy /d" command to recognize that the file has a newer date-time
stamp. This allows backup operations that are based upon xcopy to work without changing the
date-time stamp of the file significantly enough to be noticable in a "dir" command display.
<P><B>Implementation: </B><A HREF="XFile.java.html#032">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void lightlyTouch()
{
long newTime = this.lastModified() + 1;
this.setLastModified(newTime);
this.setLastAccessed(newTime);
}
/*: :METHOD:033:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
Compares two lastModified dates.
<BLOCKQUOTE>
<PRE id="unindent">
=> If this method returns 0, it means this XFile is THE SAME AGE as the argument XFile
=> If this method returns -1, it means this XFile is OLDER than the argument XFile
=> If this method returns 1, it means this XFile is NEWER than the argument XFile
</PRE>
</BLOCKQUOTE>
<P><B>Implementation: </B><A HREF="XFile.java.html#033">View source</A>
@return
This method returns:
<BLOCKQUOTE>
<PRE id="unindent">
=> 0, if this XFile is THE SAME AGE as the argument XFile
=> -1, if this XFile is OLDER than the argument XFile
=> 1, if this XFile is NEWER than the argument XFile
</PRE>
</BLOCKQUOTE>
@param
pOther the XFile whose lastModified date is to be compared to this XFile's lastModified date.
*//*
---------------------------------------------------------------------------------------------------- */
public int compareLastModified(XFile pOther)
{
long thisDate = this.lastModified();
long otherDate = pOther.lastModified();
if (thisDate < otherDate) return (-1);
if (thisDate > otherDate) return ( 1);
return (0);
}
/*: :METHOD:034:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method changes the year, month, and day components of this file's date-time stamp. It leaves
the remaining date-time stamp components unchanged.
<P><B>Implementation: </B><A HREF="XFile.java.html#034">View source</A>
@param
Yyyy is the year to set the last modified time of the file to.
@param
MM is the month to set the last modified time of the file to.
@param
Dd is the day of the month to set the last modified time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setLastModified(int yyyy, int MM, int dd)
{
/*.
==========================================================================================
Get a calendar object the represents the existing date-time stamp on this file
------------------------------------------------------------------------------------------ */
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(this.lastModified());
/*.
==========================================================================================
Pick out the elements of the existing date-time stamp that are going to stay the same
after the arguments to this method are appiled;
------------------------------------------------------------------------------------------ */
int HH = calendar.get(Calendar.HOUR_OF_DAY);
int mm = calendar.get(Calendar.MINUTE);
int ss = calendar.get(Calendar.SECOND);
int ms = calendar.get(Calendar.MILLISECOND);
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
this.setLastModified(yyyy,MM,dd,HH,mm,ss,ms);
}
/*: :METHOD:035:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method changes the year, month, day, hour, minute, and second components of this file's
date-time stamp. It leaves the remaining date-time stamp components unchanged.
<P><B>Implementation: </B><A HREF="XFile.java.html#035">View source</A>
@param
Yyyy is the year to set the last modified time of the file to.
@param
MM is the month to set the last modified time of the file to.
@param
Dd is the day of the month to set the last modified time of the file to.
@param
HH is the hour in 24hr format to set the last modified time of the file to.
@param
Mm is the minute to set the last modified time of the file to.
@param
Ss is the second to set the last modified time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setLastModified
(
int yyyy,
int MM,
int dd,
int HH,
int mm,
int ss
)
{
/*.
==========================================================================================
Get a calendar object the represents the existing date-time stamp on this file
------------------------------------------------------------------------------------------ */
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(this.lastModified());
/*.
==========================================================================================
Pick out the elements of the existing date-time stamp that are going to stay the same
after the arguments to this method are appiled;
------------------------------------------------------------------------------------------ */
int ms = calendar.get(Calendar.MILLISECOND);
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
this.setLastModified(yyyy,MM,dd,HH,mm,ss,ms);
}
/*: :METHOD:036:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method sets the last modified time of the file to the time represented by the year, month, day,
hour, minute, second, and millisecond specified.
<P><B>Implementation: </B><A HREF="XFile.java.html#036">View source</A>
@param
Yyyy is the year to set the last modified time of the file to.
@param
MM is the month to set the last modified time of the file to.
@param
Dd is the day of the month to set the last modified time of the file to.
@param
HH is the hour in 24hr format to set the last modified time of the file to.
@param
Mm is the minute to set the last modified time of the file to.
@param
Ss is the second to set the last modified time of the file to.
@param
Ms is the millisecond to set the last modified time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setLastModified
(
int yyyy,
int MM,
int dd,
int HH,
int mm,
int ss,
int ms
)
{
/*.
==========================================================================================
Normal people number months 1..12. The numb-nuts at Sun number them 0..11. Make an
adjustment from normal numbering to numb-nuts numbering.
------------------------------------------------------------------------------------------ */
MM = MM - 1;
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
java.util.Date date = Util.getDate(yyyy,MM,dd,HH,mm,ss);
this.setLastModified(date.getTime() + ms);
}
/*: :METHOD:037:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
Returns the time that the file denoted by this abstract pathname was created.
<P><B>Implementation: </B><A HREF="XFile.java.html#037">View source</A>
@return
A long value representing the time the file was created, measured in milliseconds since the epoch
(00:00:00 GMT, January 1, 1970), or 0L if the file does not exist or if an I/O error occurs.
*//*
---------------------------------------------------------------------------------------------------- */
public long created()
{
try
{
/*.
==========================================================================================
Call a native method to get a string representation of the created time in this format:
yyyy:MM:dd:HH:mm:ss:ms
------------------------------------------------------------------------------------------ */
NativeMethods nm = new NativeMethods();
XString created = new XString(nm.getCreated(this.getCanonicalPath()));
/*.
==========================================================================================
Break the string representation down into its individual parts
------------------------------------------------------------------------------------------ */
ArrayList<XString> tokens = created.tokenizedString(":");
/*.
==========================================================================================
Convert the individual parts from string values into integer values.
------------------------------------------------------------------------------------------ */
int yyyy = UMath.decodeDecimalInt(tokens.get(0));
int MM = UMath.decodeDecimalInt(tokens.get(1));
int dd = UMath.decodeDecimalInt(tokens.get(2));
int HH = UMath.decodeDecimalInt(tokens.get(3));
int mm = UMath.decodeDecimalInt(tokens.get(4));
int ss = UMath.decodeDecimalInt(tokens.get(5));
int ms = UMath.decodeDecimalInt(tokens.get(6));
/*.
==========================================================================================
Normal people number months 1..12. The numb-nuts at Sun number them 0..11. Make an
adjustment from normal numbering to numb-nuts numbering.
------------------------------------------------------------------------------------------ */
MM = MM - 1;
/*.
==========================================================================================
Use a Date object to convert the individual parts into the long that is returned
------------------------------------------------------------------------------------------ */
java.util.Date date = Util.getDate(yyyy,MM,dd,HH,mm,ss);
return date.getTime() + (long)ms;
}
catch (Exception e)
{
return 0;
}
}
/*: :METHOD:038:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method sets the created time of the file or directory named by this abstract pathname. All
platforms support created times to the nearest second, but some provide more precision. The argument
will be truncated to fit the supported precision. If the operation succeeds and no intervening
operations on the file take place, then the next invocation of the created() method will return the
(possibly truncated) time argument that was passed to this method.
<P><B>Implementation: </B><A HREF="XFile.java.html#038">View source</A>
@return
True if and only if the operation succeeded; false otherwise.
@param
pTime - The new created time, measured in milliseconds since the epoch (00:00:00 GMT, January 1,
1970).
*//*
---------------------------------------------------------------------------------------------------- */
public boolean setCreated(long pTime)
{
/*.
==========================================================================================
Get a calendar object that represents the new created time
------------------------------------------------------------------------------------------ */
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(pTime);
/*.
==========================================================================================
Pick out the elements of the calendar object that will be used to set the created time.
------------------------------------------------------------------------------------------ */
int yyyy = calendar.get(Calendar.YEAR);
int MM = calendar.get(Calendar.MONTH);
int dd = calendar.get(Calendar.DAY_OF_MONTH);
int HH = calendar.get(Calendar.HOUR_OF_DAY);
int mm = calendar.get(Calendar.MINUTE);
int ss = calendar.get(Calendar.SECOND);
int ms = calendar.get(Calendar.MILLISECOND);
/*.
==========================================================================================
Normal people number months 1..12. The numb-nuts at Sun number them 0..11. Make an
adjustment from numb-nuts numbering to normal numbering.
------------------------------------------------------------------------------------------ */
MM = MM + 1;
/*.
==========================================================================================
Set the created time
------------------------------------------------------------------------------------------ */
this.setCreated(yyyy,MM,dd,HH,mm,ss,ms);
/*.
==========================================================================================
Assume all went well. This method only returns a boolean in order to keep it true to its
sister-method, the Java-SDK-supplied setLastModified(long).
------------------------------------------------------------------------------------------ */
return true;
}
/*: :METHOD:039:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method changes the year, month, and day components of this file's date-time stamp. It leaves
the remaining date-time stamp components unchanged.
<P><B>Implementation: </B><A HREF="XFile.java.html#039">View source</A>
@param
Yyyy is the year to set the created time of the file to.
@param
MM is the month to set the created time of the file to.
@param
Dd is the day of the month to set the created time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setCreated(int yyyy, int MM, int dd)
{
/*.
==========================================================================================
Get a calendar object the represents the existing date-time stamp on this file
------------------------------------------------------------------------------------------ */
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(this.created());
/*.
==========================================================================================
Pick out the elements of the existing date-time stamp that are going to stay the same
after the arguments to this method are appiled;
------------------------------------------------------------------------------------------ */
int HH = calendar.get(Calendar.HOUR_OF_DAY);
int mm = calendar.get(Calendar.MINUTE);
int ss = calendar.get(Calendar.SECOND);
int ms = calendar.get(Calendar.MILLISECOND);
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
this.setCreated(yyyy,MM,dd,HH,mm,ss,ms);
}
/*: :METHOD:040:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method changes the year, month, day, hour, minute, and second components of this file's
date-time stamp. It leaves the remaining date-time stamp components unchanged.
<P><B>Implementation: </B><A HREF="XFile.java.html#040">View source</A>
@param
Yyyy is the year to set the created time of the file to.
@param
MM is the month to set the created time of the file to.
@param
Dd is the day of the month to set the created time of the file to.
@param
HH is the hour in 24hr format to set the created time of the file to.
@param
Mm is the minute to set the created time of the file to.
@param
Ss is the second to set the created time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setCreated
(
int yyyy,
int MM,
int dd,
int HH,
int mm,
int ss
)
{
/*.
==========================================================================================
Get a calendar object the represents the existing date-time stamp on this file
------------------------------------------------------------------------------------------ */
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(this.created());
/*.
==========================================================================================
Pick out the elements of the existing date-time stamp that are going to stay the same
after the arguments to this method are appiled;
------------------------------------------------------------------------------------------ */
int ms = calendar.get(Calendar.MILLISECOND);
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
this.setCreated(yyyy,MM,dd,HH,mm,ss,ms);
}
/*: :METHOD:041:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method sets the created time of the file to the time represented by the year, month, day, hour,
minute, second, and millisecond specified.
<P><B>Implementation: </B><A HREF="XFile.java.html#041">View source</A>
@param
Yyyy is the year to set the created time of the file to.
@param
MM is the month to set the created time of the file to.
@param
Dd is the day of the month to set the created time of the file to.
@param
HH is the hour in 24hr format to set the created time of the file to.
@param
Mm is the minute to set the created time of the file to.
@param
Ss is the second to set the created time of the file to.
@param
Ms is the millisecond to set the created time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setCreated
(
int yyyy,
int MM,
int dd,
int HH,
int mm,
int ss,
int ms
)
{
try
{
/*.
==========================================================================================
Change the file time
------------------------------------------------------------------------------------------ */
NativeMethods nm = new NativeMethods();
nm.setCreated (this.getCanonicalPath(),yyyy,MM,dd,HH,mm,ss,ms);
}
catch (Exception e)
{
}
}
/*: :METHOD:042:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
Returns the time that the file denoted by this abstract pathname was last accessed.
<P><B>Implementation: </B><A HREF="XFile.java.html#042">View source</A>
@return
A long value representing the time the file was last accessed, measured in milliseconds since the
epoch (00:00:00 GMT, January 1, 1970), or 0L if the file does not exist or if an I/O error
occurs.
*//*
---------------------------------------------------------------------------------------------------- */
public long lastAccessed()
{
try
{
/*.
==========================================================================================
Call a native method to get a string representation of the last accessed time in this
format: yyyy:MM:dd:HH:mm:ss:ms
------------------------------------------------------------------------------------------ */
NativeMethods nm = new NativeMethods();
XString lastAccessed = new XString(nm.getLastAccessed(this.getCanonicalPath()));
/*.
==========================================================================================
Break the string representation down into its individual parts
------------------------------------------------------------------------------------------ */
ArrayList<XString> tokens = lastAccessed.tokenizedString(":");
/*.
==========================================================================================
Convert the individual parts from string values into integer values.
------------------------------------------------------------------------------------------ */
int yyyy = UMath.decodeDecimalInt(tokens.get(0));
int MM = UMath.decodeDecimalInt(tokens.get(1));
int dd = UMath.decodeDecimalInt(tokens.get(2));
int HH = UMath.decodeDecimalInt(tokens.get(3));
int mm = UMath.decodeDecimalInt(tokens.get(4));
int ss = UMath.decodeDecimalInt(tokens.get(5));
int ms = UMath.decodeDecimalInt(tokens.get(6));
/*.
==========================================================================================
Normal people number months 1..12. The numb-nuts at Sun number them 0..11. Make an
adjustment from normal numbering to numb-nuts numbering.
------------------------------------------------------------------------------------------ */
MM--;
/*.
==========================================================================================
Use a Date object to convert the individual parts into the long that is returned
------------------------------------------------------------------------------------------ */
java.util.Date date = Util.getDate(yyyy,MM,dd,HH,mm,ss);
return date.getTime() + (long)ms;
}
catch (Exception e)
{
return 0;
}
}
/*: :METHOD:043:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method sets the last-accessed time of the file or directory named by this abstract pathname.
All platforms support file-access times to the nearest second, but some provide more precision. The
argument will be truncated to fit the supported precision. If the operation succeeds and no
intervening operations on the file take place, then the next invocation of the lastAccessed() method
will return the (possibly truncated) time argument that was passed to this method.
<P><B>Implementation: </B><A HREF="XFile.java.html#043">View source</A>
@return
True if and only if the operation succeeded; false otherwise.
@param
pTime - The new last-accessed time, measured in milliseconds since the epoch (00:00:00 GMT,
January 1, 1970).
*//*
---------------------------------------------------------------------------------------------------- */
public boolean setLastAccessed(long pTime)
{
/*.
==========================================================================================
Get a calendar object that represents the new last-accessed time
------------------------------------------------------------------------------------------ */
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(pTime);
/*.
==========================================================================================
Pick out the elements of the calendar object that will be used to set the last-accessed
time.
------------------------------------------------------------------------------------------ */
int yyyy = calendar.get(Calendar.YEAR);
int MM = calendar.get(Calendar.MONTH);
int dd = calendar.get(Calendar.DAY_OF_MONTH);
int HH = calendar.get(Calendar.HOUR_OF_DAY);
int mm = calendar.get(Calendar.MINUTE);
int ss = calendar.get(Calendar.SECOND);
int ms = calendar.get(Calendar.MILLISECOND);
/*.
==========================================================================================
Normal people number months 1..12. The numb-nuts at Sun number them 0..11. Make an
adjustment from numb-nuts numbering to normal numbering.
------------------------------------------------------------------------------------------ */
MM = MM + 1;
/*.
==========================================================================================
Set the last-accessed time
------------------------------------------------------------------------------------------ */
this.setLastAccessed(yyyy,MM,dd,HH,mm,ss,ms);
/*.
==========================================================================================
Assume all went well. This method only returns a boolean in order to keep it true to its
sister-method, the Java-SDK-supplied setLastModified(long).
------------------------------------------------------------------------------------------ */
return true;
}
/*: :METHOD:044:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method changes the year, month, and day components of this file's date-time stamp. It leaves
the remaining date-time stamp components unchanged.
<P><B>Implementation: </B><A HREF="XFile.java.html#044">View source</A>
@param
Yyyy is the year to set the last Accessed time of the file to.
@param
MM is the month to set the last Accessed time of the file to.
@param
Dd is the day of the month to set the last Accessed time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setLastAccessed(int yyyy, int MM, int dd)
{
/*.
==========================================================================================
Get a calendar object the represents the existing date-time stamp on this file
------------------------------------------------------------------------------------------ */
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(this.lastAccessed());
/*.
==========================================================================================
Pick out the elements of the existing date-time stamp that are going to stay the same
after the arguments to this method are appiled;
------------------------------------------------------------------------------------------ */
int HH = calendar.get(Calendar.HOUR_OF_DAY);
int mm = calendar.get(Calendar.MINUTE);
int ss = calendar.get(Calendar.SECOND);
int ms = calendar.get(Calendar.MILLISECOND);
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
this.setLastAccessed(yyyy,MM,dd,HH,mm,ss,ms);
}
/*: :METHOD:045:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method changes the year, month, day, hour, minute, and second components of this file's
date-time stamp. It leaves the remaining date-time stamp components unchanged.
<P><B>Implementation: </B><A HREF="XFile.java.html#045">View source</A>
@param
Yyyy is the year to set the last Accessed time of the file to.
@param
MM is the month to set the last Accessed time of the file to.
@param
Dd is the day of the month to set the last Accessed time of the file to.
@param
HH is the hour in 24hr format to set the last Accessed time of the file to.
@param
Mm is the minute to set the last Accessed time of the file to.
@param
Ss is the second to set the last Accessed time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setLastAccessed
(
int yyyy,
int MM,
int dd,
int HH,
int mm,
int ss
)
{
/*.
==========================================================================================
Get a calendar object the represents the existing date-time stamp on this file
------------------------------------------------------------------------------------------ */
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(this.lastAccessed());
/*.
==========================================================================================
Pick out the elements of the existing date-time stamp that are going to stay the same
after the arguments to this method are appiled;
------------------------------------------------------------------------------------------ */
int ms = calendar.get(Calendar.MILLISECOND);
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
this.setLastAccessed(yyyy,MM,dd,HH,mm,ss,ms);
}
/*: :METHOD:046:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method sets the last Accessed time of the file to the time represented by the year, month, day,
hour, minute, second, and millisecond specified.
<P><B>Implementation: </B><A HREF="XFile.java.html#046">View source</A>
@param
Yyyy is the year to set the last Accessed time of the file to.
@param
MM is the month to set the last Accessed time of the file to.
@param
Dd is the day of the month to set the last Accessed time of the file to.
@param
HH is the hour in 24hr format to set the last Accessed time of the file to.
@param
Mm is the minute to set the last Accessed time of the file to.
@param
Ss is the second to set the last Accessed time of the file to.
@param
Ms is the millisecond to set the last Accessed time of the file to.
*//*
---------------------------------------------------------------------------------------------------- */
public void setLastAccessed
(
int yyyy,
int MM,
int dd,
int HH,
int mm,
int ss,
int ms
)
{
try
{
/*.
==========================================================================================
Change the file time
------------------------------------------------------------------------------------------ */
NativeMethods nm = new NativeMethods();
nm.setLastAccessed (this.getCanonicalPath(),yyyy,MM,dd,HH,mm,ss,ms);
}
catch (Exception e)
{
}
}
/*: :METHOD:047:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method copies the dates of this file to another file.
<P><B>Implementation: </B><A HREF="XFile.java.html#047">View source</A>
@param
pToFile is the file to which the dates of this file is copied.
*//*
---------------------------------------------------------------------------------------------------- */
public void copyDatesTo(XFile pToFile) throws Exception
{
pToFile.setCreated(this.created());
pToFile.setLastModified(this.lastModified());
pToFile.setLastAccessed(this.lastAccessed());
}
/*: :METHOD:048:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
<P><B>Implementation: </B><A HREF="XFile.java.html#048">View source</A>
*//* This method copies the dates of this file to another file.
@param
pToFile is the file to which the dates of this file is copied.
---------------------------------------------------------------------------------------------------- */
public void copyDatesTo(File pToFile) throws Exception
{
XFile toFile = new XFile(pToFile);
this.copyDatesTo(toFile);
}
/*: :METHOD:049:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method copies the dates of another file to this file.
<P><B>Implementation: </B><A HREF="XFile.java.html#049">View source</A>
@param
pFromFile is the file whose dates are copied to this file.
*//*
---------------------------------------------------------------------------------------------------- */
public void copyDatesFrom(XFile pFromFile) throws Exception
{
pFromFile.copyDatesTo(this);
}
/*: :METHOD:050:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method copies the dates of another file to this file.
<P><B>Implementation: </B><A HREF="XFile.java.html#050">View source</A>
@param
pFromFile is the file whose dates are copied to this file.
*//*
---------------------------------------------------------------------------------------------------- */
public void copyDatesFrom(File pFromFile) throws Exception
{
XFile fromFile = new XFile(pFromFile);
this.copyDatesFrom(fromFile);
}
/*: :METHOD:051:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method copies the contents of this file to another file. This method also copies the file dates
from this file to its copy file.
** IMPLEMENTATION SUGGESTIION **
Also worth noting - if youve got JDK 1.4, then FileChannel has transferTo() and transferFrom() which
are generally much, much faster than copying bytes using streams. (They take better advantage of
native code and hardware optimizations, and bypass the JVM for a lot of the work.)
<P><B>Implementation: </B><A HREF="XFile.java.html#051">View source</A>
@param
pToFile is the file to which the content of this file is copied.
*//*
---------------------------------------------------------------------------------------------------- */
public void copyTo(XFile pToFile) throws Exception
{
/*.
==========================================================================================
This method makes no sense on directory files, this must be a normal file
------------------------------------------------------------------------------------------ */
if (this.isDirectory())
{
throw new Exception("Attempt to copy a Directory from <" + this.getCanonicalPath() + "> to a file <" + pToFile.getCanonicalPath() + ">");
}
/*.
==========================================================================================
Create channel on the source
------------------------------------------------------------------------------------------ */
FileChannel srcChannel = new FileInputStream(this).getChannel();
/*.
==========================================================================================
Create channel on the destination
------------------------------------------------------------------------------------------ */
FileChannel dstChannel = new FileOutputStream(pToFile).getChannel();
/*.
==========================================================================================
Copy file contents from source to destination
------------------------------------------------------------------------------------------ */
dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
/*.
==========================================================================================
Close the channels
------------------------------------------------------------------------------------------ */
srcChannel.close();
dstChannel.force(true);
dstChannel.close();
/*.
==========================================================================================
Copy the file dates
------------------------------------------------------------------------------------------ */
this.copyDatesTo(pToFile);
}
/*: :METHOD:052:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method copies the contents of this file to another file. This method also copies the file dates
from this file to its copy file.
<P><B>Implementation: </B><A HREF="XFile.java.html#052">View source</A>
@param
pToFile is the file to which the content of this file is copied.
*//*
---------------------------------------------------------------------------------------------------- */
public void copyTo(File pToFile) throws Exception
{
XFile toFile = new XFile(pToFile);
this.copyTo(toFile);
}
/*: :METHOD:053:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method copies the contents of another file to this file. This method also copies the file dates
from the other file to this file.
<P><B>Implementation: </B><A HREF="XFile.java.html#053">View source</A>
@param
pFromFile is the file whose contents are copied to this file.
*//*
---------------------------------------------------------------------------------------------------- */
public void copyFrom(XFile pFromFile) throws Exception
{
pFromFile.copyTo(this);
}
/*: :METHOD:054:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method copies the contents of another file to this file. This method also copies the file dates
from the other file to this file.
<P><B>Implementation: </B><A HREF="XFile.java.html#054">View source</A>
@param
pFromFile is the file whose contents are copied to this file.
*//*
---------------------------------------------------------------------------------------------------- */
public void copyFrom(File pFromFile) throws Exception
{
XFile fromFile = new XFile(pFromFile);
this.copyFrom(fromFile);
}
/*: :METHOD:055:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method appends the contents of this file to another file.
** IMPLEMENTATION SUGGESTIION **
Also worth noting - if youve got JDK 1.4, then FileChannel has transferTo() and transferFrom() which
are generally much, much faster than copying bytes using streams. (They take better advantage of
native code and hardware optimizations, and bypass the JVM for a lot of the work.)
<P><B>Implementation: </B><A HREF="XFile.java.html#055">View source</A>
@param
pToFile is the file to which the content of this file is appended.
*//*
---------------------------------------------------------------------------------------------------- */
public void appendTo(XFile pToFile) throws Exception
{
/*.
==========================================================================================
This method makes no sense on directory files, this must be a normal file
------------------------------------------------------------------------------------------ */
if (this.isDirectory()) return;
/*.
==========================================================================================
Create channel on the source
------------------------------------------------------------------------------------------ */
FileChannel srcChannel = new FileInputStream(this).getChannel();
/*.
==========================================================================================
Create channel on the destination
------------------------------------------------------------------------------------------ */
FileChannel dstChannel = new FileOutputStream(pToFile,true).getChannel();
/*.
==========================================================================================
Copy file contents from source to destination
------------------------------------------------------------------------------------------ */
dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
/*.
==========================================================================================
Close the channels
------------------------------------------------------------------------------------------ */
srcChannel.close();
dstChannel.force(true);
dstChannel.close();
}
/*: :METHOD:056:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
<P><B>Implementation: </B><A HREF="XFile.java.html#056">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void appendTo(File pToFile) throws Exception
{
XFile toFile = new XFile(pToFile);
this.appendTo(toFile);
}
/*: :METHOD:057:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method appends the contents of another file to this file.
<P><B>Implementation: </B><A HREF="XFile.java.html#057">View source</A>
@param
pFromFile is the file whose contents are appended to this file.
*//*
---------------------------------------------------------------------------------------------------- */
public void appendFrom(XFile pFromFile) throws Exception
{
pFromFile.appendTo(this);
}
/*: :METHOD:058:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
<P><B>Implementation: </B><A HREF="XFile.java.html#058">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void appendFrom(File pFromFile) throws Exception
{
XFile fromFile = new XFile(pFromFile);
this.appendFrom(fromFile);
}
/*: :METHOD:059:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method appends the contents of one or more other files to this file.
<P><B>Implementation: </B><A HREF="XFile.java.html#059">View source</A>
@param
pArrayList is an array list of Files (or subclasses like FileExts).
*//*
---------------------------------------------------------------------------------------------------- */
public void appendFrom(ArrayList pArrayList) throws Exception
{
Iterator iter = pArrayList.iterator();
while (iter.hasNext())
{
File fromFile = (File)iter.next();
this.appendFrom(fromFile);
}
}
/*: :METHOD:060:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method computes and returns a string represntation of this XFile's digest
<P><B>Implementation: </B><A HREF="XFile.java.html#060">View source</A>
@return
The digest of the file
@param
pAlgorithm is the name of the algorithm requested. See Appendix A in the Java Cryptography
Architecture API Specification & Reference for information about standard algorithm names.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> XString digest(Type pAlgorithm) throws Exception
{
return (new Digest(UString.toString(pAlgorithm),this)).xstring();
}
/*: :METHOD:061:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method computes and returns a string represntation of this XFile's MD5 digest
<P><B>Implementation: </B><A HREF="XFile.java.html#061">View source</A>
@return
The MD5 digest of the file
*//*
---------------------------------------------------------------------------------------------------- */
public XString digest() throws Exception
{
return this.digest("MD5");
}
/*: :METHOD:062:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method compares the contents of this XFile with the contents of another XFile.
<P><B>Implementation: </B><A HREF="XFile.java.html#062">View source</A>
@return
True if the contents of the FileExts are identical; false otherwise.
@param
pOtherFile is the XFile whose contents are compared to this XFile's contents.
*//*
---------------------------------------------------------------------------------------------------- */
public boolean contentEquals(XFile pOtherFile) throws Exception
{
/*.
==========================================================================================
Point of interest: here's the old, less efficient, but more elegant way to compare two
files:
Return
( (this.length() == pOtherFile.length()) &&
this.digest("SHA").equalsIgnoreCase(pOtherFile.digest("SHA")) );
------------------------------------------------------------------------------------------ */
return this.contentEquals((File)pOtherFile);
}
/*: :METHOD:063:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method compares the contents of this XFile with the contents of another File.
<P><B>Implementation: </B><A HREF="XFile.java.html#063">View source</A>
@return
True if the contents of the files are identical; false otherwise.
@param
pOtherFile is the File whose contents are compared to this XFile's contents.
*//*
---------------------------------------------------------------------------------------------------- */
public boolean contentEquals(File pOtherFile) throws Exception
{
/*.
==========================================================================================
If the two files are different sizes, then their contents are not equal.
------------------------------------------------------------------------------------------ */
if (this.length() != pOtherFile.length())
{
return false;
}
/*.
==========================================================================================
Otherwise, do a byte-by-byte comparison of the two files' content.
------------------------------------------------------------------------------------------ */
boolean result = true;
byte[] thisByteArray = new byte[2 * UMath.ONE_MEG];
byte[] otherByteArray = new byte[2 * UMath.ONE_MEG];
BufferedInputStream thisFile = new BufferedInputStream
(
new FileInputStream(this)
);
BufferedInputStream otherFile = new BufferedInputStream
(
new FileInputStream(pOtherFile)
);
/*.
==========================================================================================
Compare each byte in this file to the corresponding byte in the other file and if any
difference is found, set the result to false and stop the comparing process.
------------------------------------------------------------------------------------------ */
while (true)
{
/*.
==========================================================================================
Read the next chunk of bytes from both files
------------------------------------------------------------------------------------------ */
int thisBytesRead = thisFile.read(thisByteArray,0,2 * UMath.ONE_MEG);
int otherBytesRead = otherFile.read(otherByteArray,0,2 * UMath.ONE_MEG);
/*.
==========================================================================================
If the same number of bytes were not available in both files then one file is smaller than
the other so they are not equal so set the result to false and break out of the loop.
------------------------------------------------------------------------------------------ */
if (thisBytesRead != otherBytesRead)
{
result = false;
break;
}
/*.
==========================================================================================
If we've reached the end of file break out of the loop
------------------------------------------------------------------------------------------ */
if (thisBytesRead == (-1)) break;
/*.
==========================================================================================
Compare each byte and if one is found to be different then set the result to false and
break out of the loop.
------------------------------------------------------------------------------------------ */
for (int i=0; i < thisBytesRead; i++)
{
if (thisByteArray[i] != otherByteArray[i])
{
result = false;
break;
}
}
}
/*.
==========================================================================================
Close the files and return the result
------------------------------------------------------------------------------------------ */
thisFile.close();
otherFile.close();
return result;
}
/*: :METHOD:064:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method overrides the File.delete() method and deletes the file or directory denoted by this
abstract pathname. If this pathname denotes a directory, then the directory is emptied first and
then deleted.
<P><B>Implementation: </B><A HREF="XFile.java.html#064">View source</A>
@return
True if and only if the file or directory is successfully deleted; false otherwise
*//*
---------------------------------------------------------------------------------------------------- */
public boolean delete()
{
try
{
/*.
==========================================================================================
If this is a directory, it must be empty before it can be deleted. This block empties it.
------------------------------------------------------------------------------------------ */
if (this.isDirectory())
{
/*.
==========================================================================================
Create a list of the files and sub directories that reside within this directory
------------------------------------------------------------------------------------------ */
XString fileList[] = XString.toXStringArray(this.list());
/*.
==========================================================================================
All the files and sub directories in this directory must be deleted before this directory
can be deleted.
------------------------------------------------------------------------------------------ */
XString thisDirName = new XString(this.getCanonicalPath());
for (int i=0; i < fileList.length; i++)
{
XFile currXFile = new XFile(thisDirName, fileList[i]);
if (currXFile.isDirectory())
{
/*.
==========================================================================================
Sub-directory: remove it
------------------------------------------------------------------------------------------ */
if ( ! currXFile.delete()) return false;
}
else
{
/*.
==========================================================================================
Regular file: delete it. (this upcasts the XFile to a File so that the overriden
File.delete() can be used to actually delete the file)
------------------------------------------------------------------------------------------ */
if ( ! currXFile.deleteFile()) return false;
}
}
}
/*.
==========================================================================================
Now delete this file or directory (this upcasts the XFile to a File so that the overriden
File.delete() can be used to actually delete the file)
------------------------------------------------------------------------------------------ */
return this.deleteFile();
}
catch (Exception e)
{
return false;
}
}
/*: :METHOD:065:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method wipes the file or directory denoted by this abstract pathname. If this pathname denotes
a directory, then the directory is emptied first and then wiped.
Wipe is an advanced security tool, which allows you to completely remove sensitive data from your
hard disk.
Caveat: Caveat:
On a journaling filesystem like NTFS there is actually no way to securely erase a single file
without wiping all the free space on the drive. The problem is that the new blocks (which you've
presumably overwritten with random data) are not guaranteed to be in the same place on disk as
the old ones.
In order to keep your data secure, the only real solution you have is to completely encrypt the
drive
<P><B>Implementation: </B><A HREF="XFile.java.html#065">View source</A>
@return
True if and only if the file or directory is successfully wiped; false otherwise
*//*
---------------------------------------------------------------------------------------------------- */
public boolean wipe()
{
try
{
/*.
==========================================================================================
If this is a directory, it must be empty before it can be deleted. This block empties it.
------------------------------------------------------------------------------------------ */
if (this.isDirectory())
{
/*.
==========================================================================================
Create a list of the files and sub directories that reside within this directory
------------------------------------------------------------------------------------------ */
XString fileList[] = XString.toXStringArray(this.list());
/*.
==========================================================================================
All the files and sub directories in this directory must be deleted before this directory
can be deleted.
------------------------------------------------------------------------------------------ */
XString thisDirName = new XString(this.getCanonicalPath());
for (int i=0; i < fileList.length; i++)
{
XFile currXFile = new XFile(thisDirName, fileList[i]);
if (currXFile.isDirectory())
{
/*.
==========================================================================================
Sub-directory: remove it
------------------------------------------------------------------------------------------ */
if ( ! currXFile.wipe()) return false;
}
else
{
/*.
==========================================================================================
Regular file: delete it. (this upcasts the XFile to a File so that the overriden
File.delete() can be used to actually delete the file)
------------------------------------------------------------------------------------------ */
if ( ! currXFile.wipeFile()) return false;
}
}
}
/*.
==========================================================================================
Now delete this file or directory (this upcasts the XFile to a File so that the overriden
File.delete() can be used to actually delete the file)
------------------------------------------------------------------------------------------ */
return this.wipeFile();
}
catch (Exception e)
{
return false;
}
}
/*: :METHOD:066:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method fixes up the "created", "lastModified", and "lastAccessed" dates on "this" file or
directory.
If "this" is a normal file:
This method sets the created date for "this" file to 0 and sets the lastAccesse date to whatever
the lastModified date is.
If "this" is a directory:
If there aren't any files or subdirectories in "this" directory then this method sets the
lastModified and lastAccessed dates to match the created date.
If there are files or subdirectories in "this" directory then this method changes the
lastModified and lastAccessed dates on "this" directory to match the lastModified date of the
most recently modified file or subdirectory in "this" directory.
<P><B>Implementation: </B><A HREF="XFile.java.html#066">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void fixDates() throws Exception
{
/*.
==========================================================================================
If "this" is a regular file ...
------------------------------------------------------------------------------------------ */
if (this.isFile())
{
this.setCreated(0);
this.setLastAccessed(this.lastModified());
}
/*.
==========================================================================================
Else "this" is a directory ...
------------------------------------------------------------------------------------------ */
else
{
/*.
==========================================================================================
Create a list of the files and sub directories that reside within "this" directory
------------------------------------------------------------------------------------------ */
XString fileList[] = XString.toXStringArray(this.list());
/*.
==========================================================================================
If there aren't any files or subdirectories in "this" directory then just set the
lastModified and lastAccessed dates to match the created date.
------------------------------------------------------------------------------------------ */
if (fileList.length == 0)
{
long date = this.created();
this.setLastModified(date);
this.setLastAccessed(date);
}
/*.
==========================================================================================
Otherwise, change the lastModified and lastAccessed dates on "this" directory to match the
lastModified date of the most recently modified file or subdirectory in "this" directory.
------------------------------------------------------------------------------------------ */
else
{
long newestDate = 0;
XString thisDirName = new XString(this.getCanonicalPath());
/*.
==========================================================================================
Search each file and subdirectory for the most recent lastModified date
------------------------------------------------------------------------------------------ */
for (int i=0; i < fileList.length; i++)
{
File currentFile = new File(thisDirName.string(), fileList[i].string());
newestDate = UMath.max(newestDate,currentFile.lastModified());
}
/*.
==========================================================================================
Change this directory's dates
------------------------------------------------------------------------------------------ */
this.setLastModified(newestDate);
this.setLastAccessed(newestDate);
}
}
}
/*: :METHOD:067:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method recursively fixes up the "created", "lastModified", and "lastAccessed" dates on "this"
file or directory.
If "this" is a normal file:
This method sets the created date for "this" file to 0 and sets the lastAccesse date to whatever
the lastModified date is.
If "this" is a directory:
If there aren't any files or subdirectories in "this" directory then this method sets the
lastModified and lastAccessed dates to match the created date.
If there are files or subdirectories in "this" directory then this method changes the
lastModified and lastAccessed dates on "this" directory to match the lastModified date of the
most recently modified file or subdirectory in "this" directory after recursively fixing the
dates on any subdirectories in "this" directory.
<P><B>Implementation: </B><A HREF="XFile.java.html#067">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void recursivelyFixDates() throws Exception
{
/*.
==========================================================================================
If "this" is a regular file ...
------------------------------------------------------------------------------------------ */
if (this.isFile())
{
this.setCreated(0);
this.setLastAccessed(this.lastModified());
}
/*.
==========================================================================================
Else "this" is a directory ...
------------------------------------------------------------------------------------------ */
else
{
/*.
==========================================================================================
Create a list of the files and sub directories that reside within "this" directory
------------------------------------------------------------------------------------------ */
XString fileList[] = XString.toXStringArray(this.list());
/*.
==========================================================================================
If there aren't any files or subdirectories in "this" directory then just set the
lastModified and lastAccessed dates to match the created date.
------------------------------------------------------------------------------------------ */
if (fileList.length == 0)
{
long date = this.created();
this.setLastModified(date);
this.setLastAccessed(date);
}
/*.
==========================================================================================
Otherwise, change the lastModified and lastAccessed dates on "this" directory to match the
lastModified date of the most recently modified file or subdirectory in "this" directory.
------------------------------------------------------------------------------------------ */
else
{
long newestDate = 0;
XString thisDirName = new XString(this.getCanonicalPath());
/*.
==========================================================================================
For each file and subdirectory ..
------------------------------------------------------------------------------------------ */
for (int i=0; i < fileList.length; i++)
{
XFile currentFileExt = new XFile(thisDirName, fileList[i]);
/*.
==========================================================================================
Fix this file or sudirectory's date
------------------------------------------------------------------------------------------ */
currentFileExt.recursivelyFixDates();
/*.
==========================================================================================
Remember the lastModified date of the most recently modified file or subdirectory in
"this" directory
------------------------------------------------------------------------------------------ */
newestDate = UMath.max(newestDate,currentFileExt.lastModified());
}
/*.
==========================================================================================
Change this directory's dates
------------------------------------------------------------------------------------------ */
this.setLastModified(newestDate);
this.setLastAccessed(newestDate);
}
}
}
/*: :METHOD:068:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method fixes up and then displays the "created", "lastModified", and "lastAccessed" dates on
"this" file or directory.
If "this" is a normal file:
This method sets the created date for "this" file to 0 and sets the lastAccesse date to whatever
the lastModified date is.
If "this" is a directory:
If there aren't any files or subdirectories in "this" directory then this method sets the
lastModified and lastAccessed dates to match the created date.
If there are files or subdirectories in "this" directory then this method changes the
lastModified and lastAccessed dates on "this" directory to match the lastModified date of the
most recently modified file or subdirectory in "this" directory.
<P><B>Implementation: </B><A HREF="XFile.java.html#068">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void fixAndDisplayDates() throws Exception
{
this.fixDates();
this.displayDates();
}
/*: :METHOD:069:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method recursively fixes up and then displays the "created", "lastModified", and "lastAccessed"
dates on "this" file or directory.
If "this" is a normal file:
This method sets the created date for "this" file to 0 and sets the lastAccesse date to whatever
the lastModified date is.
If "this" is a directory:
If there aren't any files or subdirectories in "this" directory then this method sets the
lastModified and lastAccessed dates to match the created date.
If there are files or subdirectories in "this" directory then this method changes the
lastModified and lastAccessed dates on "this" directory to match the lastModified date of the
most recently modified file or subdirectory in "this" directory after recursively fixing the
dates on any subdirectories in "this" directory.
<P><B>Implementation: </B><A HREF="XFile.java.html#069">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void recursivelyFixAndDisplayDates() throws Exception
{
/*.
==========================================================================================
If "this" is a regular file ...
------------------------------------------------------------------------------------------ */
if (this.isFile())
{
this.setCreated(0);
this.setLastAccessed(this.lastModified());
}
/*.
==========================================================================================
Else "this" is a directory ...
------------------------------------------------------------------------------------------ */
else
{
/*.
==========================================================================================
Create a list of the files and sub directories that reside within "this" directory
------------------------------------------------------------------------------------------ */
XString fileList[] = XString.toXStringArray(this.list());
/*.
==========================================================================================
If there aren't any files or subdirectories in "this" directory then just set the
lastModified and lastAccessed dates to match the created date.
------------------------------------------------------------------------------------------ */
if (fileList.length == 0)
{
long date = this.created();
this.setLastModified(date);
this.setLastAccessed(date);
}
/*.
==========================================================================================
Otherwise, change the lastModified and lastAccessed dates on "this" directory to match the
lastModified date of the most recently modified file or subdirectory in "this" directory.
------------------------------------------------------------------------------------------ */
else
{
long newestDate = 0;
XString thisDirName = new XString(this.getCanonicalPath());
/*.
==========================================================================================
For each file and subdirectory ..
------------------------------------------------------------------------------------------ */
for (int i=0; i < fileList.length; i++)
{
XFile currentFileExt = new XFile(thisDirName, fileList[i]);
/*.
==========================================================================================
Fix this file or sudirectory's date
------------------------------------------------------------------------------------------ */
currentFileExt.recursivelyFixAndDisplayDates();
/*.
==========================================================================================
Remember the lastModified date of the most recently modified file or subdirectory in
"this" directory
------------------------------------------------------------------------------------------ */
newestDate = UMath.max(newestDate,currentFileExt.lastModified());
}
/*.
==========================================================================================
Change this directory's dates
------------------------------------------------------------------------------------------ */
this.setLastModified(newestDate);
this.setLastAccessed(newestDate);
}
}
/*.
==========================================================================================
Display the dates for "this"
------------------------------------------------------------------------------------------ */
this.displayDates();
}
/*: :METHOD:070:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method displays the created, lastModified, and lastAccessed dates for "this" directory and
recursively for all subdirectories under "this" directory.
<P><B>Implementation: </B><A HREF="XFile.java.html#070">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void recursivelyDisplayDirDates() throws Exception
{
/*.
==========================================================================================
If this is a directory ...
------------------------------------------------------------------------------------------ */
if (this.isDirectory())
{
/*.
==========================================================================================
Create a list of the files and sub directories that reside within this directory
------------------------------------------------------------------------------------------ */
XString fileList[] = XString.toXStringArray(this.list());
/*.
==========================================================================================
All the sub directories in this directory must have their dates changed
------------------------------------------------------------------------------------------ */
XString thisDirName = new XString(this.getCanonicalPath());
for (int i=0; i < fileList.length; i++)
{
XFile currentFileExt = new XFile(thisDirName, fileList[i]);
if (currentFileExt.isDirectory())
{
/*.
==========================================================================================
Sub-directory: change its dates
------------------------------------------------------------------------------------------ */
currentFileExt.recursivelyDisplayDirDates();
}
}
/*.
==========================================================================================
Change this directory's dates
------------------------------------------------------------------------------------------ */
this.displayDates();
}
}
/*: :METHOD:071:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method displays the created, lastModified, and lastAccessed dates for a file or directory.
<P><B>Implementation: </B><A HREF="XFile.java.html#071">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void displayDates() throws Exception
{
/*.
==========================================================================================
Display the dates for "this".
------------------------------------------------------------------------------------------ */
cOut.println
(
Util.timeStamp("yyyy-MM-dd HH:mm:ss.SSS",new Date(this.created())) +
" " +
Util.timeStamp("yyyy-MM-dd HH:mm:ss.SSS",new Date(this.lastModified())) +
" " +
Util.timeStamp("yyyy-MM-dd HH:mm:ss.SSS",new Date(this.lastAccessed())) +
" " +
this.getCanonicalPath()
);
}
/*: :METHOD:072:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method displays the column headers appropriate to subsequent calls to the displayDates()
method.
<P><B>Implementation: </B><A HREF="XFile.java.html#072">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void displayDatesColumnHeaders() throws Exception
{
/*.
==========================================================================================
Display column headers
------------------------------------------------------------------------------------------ */
cOut.println("");
cOut.println
(
" Create Date Last Modified Date Last Accessed Date File Name"
);
cOut.println
(
"----------------------- ----------------------- ----------------------- -------------------"
);
}
/*: :METHOD:073:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method makes a bakup of this file. If this file is a normal file, it also backs up any existing
backups of this file, up to the number of backup files specified by the static value of MAX_BKUPS.
For example:
<BLOCKQUOTE>
<PRE id="unindent">
* if
* this is a normal file named \temp\x.x
* and MAX_BKUPS is 3
* and the backup directory is \backup
*
* then the first time backup() is called on \temp\x.x
* \temp\x.x is copied to \backup\temp\x.x.1
*
* and the second time backup() is called on \temp\x.x
* first, \backup\temp\x.x.1 is copied to \backup\temp\x.x.2
* then, \temp\x.x is copied to \backup\temp\x.x.1
*
* and the third and all subsequent times backup() is called on \temp\x.x
* first, \backup\temp\x.x.2 is copied to \backup\temp\x.x.3
* next, \backup\temp\x.x.1 is copied to \backup\temp\x.x.2
* then, \temp\x.x is copied to \backup\temp\x.x.1
</PRE>
</BLOCKQUOTE>
If this file is a directory, this method backs up all the normal files in this directory and
recursively descends into all the subdirectories and backs them up too.
This method preserves file dates. In other words, it sets the file dates on the backup file to match
the dates on the file that the backup file backs up.
<P><B>Implementation: </B><A HREF="XFile.java.html#073">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void backup() throws Exception
{
/*.
==========================================================================================
If this is a directory ...
------------------------------------------------------------------------------------------ */
if (this.isDirectory())
{
/*.
==========================================================================================
Create a list of the files and sub directories that reside within this directory
------------------------------------------------------------------------------------------ */
XString[] fileList = XString.toXStringArray(this.list());
/*.
==========================================================================================
Back up all the normal files and recursively descend into the sub directories backing up
everything in them.
------------------------------------------------------------------------------------------ */
XString thisDirName = new XString(this.getCanonicalPath());
for (int i=0; i < fileList.length; i++)
{
XFile currentFileExt = new XFile(thisDirName.string(), fileList[i].string());
currentFileExt.backup();
}
}
/*.
==========================================================================================
Else this is a normal file so make its backup(s)
------------------------------------------------------------------------------------------ */
else
{
this.backupNormalFile(null,null,0);
}
}
/*: :METHOD:074:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method tests to see if two files are normal (not directory) and distinct (distinguished as not
being the same; separate) files.
<P><B>Implementation: </B><A HREF="XFile.java.html#074">View source</A>
@return
This method returns true if the two files are normal and distinct. Otherwise, this method returns
false.
@param
pFirstFile is any file
@param
pSecondFile is any file
*//*
---------------------------------------------------------------------------------------------------- */
public static boolean filesAreNormalAndDistinct(File pFirstFile, File pSecondFile) throws Exception
{
return filesAreNormal(pFirstFile, pSecondFile) && filesAreDistinct(pFirstFile, pSecondFile);
}
/*: :METHOD:075:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method tests to see if two files are normal (not directory) and distinct (distinguished as not
being the same; separate) files.
<P><B>Implementation: </B><A HREF="XFile.java.html#075">View source</A>
@return
This method returns true if the two files are normal and distinct. Otherwise, this method returns
false.
@param
pFirstPathname is anything that can be converted to a String representing the name of any file
@param
pSecondPathname is anything that can be converted to a String representing the name of any file
*//*
---------------------------------------------------------------------------------------------------- */
public static <Type1, Type2> boolean filesAreNormalAndDistinct(Type1 pFirstPathname, Type2 pSecondPathname) throws Exception
{
if (pFirstPathname == null)
{
throw new Exception("pFirstPathname is null");
}
if (pSecondPathname == null)
{
throw new Exception("pSecondPathname is null");
}
/*.
==========================================================================================
Get files for each pathname
------------------------------------------------------------------------------------------ */
File firstFile = new File(UString.toString(pFirstPathname));
File secondFile = new File(UString.toString(pSecondPathname));
/*.
==========================================================================================
Test then release the files to the garbage collector and return result of test
------------------------------------------------------------------------------------------ */
boolean result = filesAreNormalAndDistinct(firstFile, secondFile);
firstFile = null;
secondFile = null;
return result;
}
/*: :METHOD:076:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method tests to see if two files are normal (not directory) files.
<P><B>Implementation: </B><A HREF="XFile.java.html#076">View source</A>
@return
This method returns true if the two files are normal. If either is a directory, this method
returns false.
@param
pFirstFile is any file
@param
pSecondFile is any file
*//*
---------------------------------------------------------------------------------------------------- */
public static boolean filesAreNormal(File pFirstFile, File pSecondFile) throws Exception
{
return pFirstFile.isFile() && pSecondFile.isFile();
}
/*: :METHOD:077:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method tests to see if two files are normal (not directory) files.
<P><B>Implementation: </B><A HREF="XFile.java.html#077">View source</A>
@return
This method returns true if the two files are normal. If either is a directory, this method
returns false.
@param
pFirstPathname is anything that can be converted to a String representing the name of any file
@param
pSecondPathname is anything that can be converted to a String representing the name of any file
*//*
---------------------------------------------------------------------------------------------------- */
public static <Type1, Type2> boolean filesAreNormal(Type1 pFirstPathname, Type2 pSecondPathname) throws Exception
{
if (pFirstPathname == null)
{
throw new Exception("pFirstPathname is null");
}
if (pSecondPathname == null)
{
throw new Exception("pSecondPathname is null");
}
/*.
==========================================================================================
Get files for each pathname
------------------------------------------------------------------------------------------ */
File firstFile = new File(UString.toString(pFirstPathname));
File secondFile = new File(UString.toString(pSecondPathname));
/*.
==========================================================================================
Test then release the files to the garbage collector and return result of test
------------------------------------------------------------------------------------------ */
boolean result = filesAreNormal(firstFile, secondFile);
firstFile = null;
secondFile = null;
return result;
}
/*: :METHOD:078:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method tests to see if two files are distinct (distinguished as not being the same; separate)
files.
<P><B>Implementation: </B><A HREF="XFile.java.html#078">View source</A>
@return
This method returns true if the two files are distinct. If they are the same file, this method
returns false.
@param
pFirstFile is any file
@param
pSecondFile is any file
*//*
---------------------------------------------------------------------------------------------------- */
public static boolean filesAreDistinct(File pFirstFile, File pSecondFile) throws Exception
{
return (pFirstFile.getCanonicalPath() != pSecondFile.getCanonicalPath());
}
/*: :METHOD:079:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method tests to see if two files are distinct (distinguished as not being the same; separate)
files.
<P><B>Implementation: </B><A HREF="XFile.java.html#079">View source</A>
@return
This method returns true if the two files are distinct. If they are the same file, this method
returns false.
@param
pFirstPathname is anything that can be converted to a String representing the name of any file
@param
pSecondPathname is anything that can be converted to a String representing the name of any file
*//*
---------------------------------------------------------------------------------------------------- */
public static <Type1, Type2> boolean filesAreDistinct(Type1 pFirstPathname, Type2 pSecondPathname) throws Exception
{
if (pFirstPathname == null)
{
throw new Exception("pFirstPathname is null");
}
if (pSecondPathname == null)
{
throw new Exception("pSecondPathname is null");
}
/*.
==========================================================================================
Get files for each pathname
------------------------------------------------------------------------------------------ */
File firstFile = new File(UString.toString(pFirstPathname));
File secondFile = new File(UString.toString(pSecondPathname));
/*.
==========================================================================================
Test then release the files to the garbage collector and return result of test
------------------------------------------------------------------------------------------ */
boolean result = filesAreDistinct(firstFile, secondFile);
firstFile = null;
secondFile = null;
return result;
}
/*: :METHOD:080:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method tests to see if this file is distinct (distinguished as not being the same; separate)
from the other file identified by pOtherPathname.
<P><B>Implementation: </B><A HREF="XFile.java.html#080">View source</A>
@return
This method returns true if the two files are distinct. If they are the same file, this method
returns false.
@param
pOtherPathname is anything that can be converted to a String representing the name of any file
*//*
---------------------------------------------------------------------------------------------------- */
public <Type1> boolean filesAreDistinct(Type1 pOtherPathname) throws Exception
{
return filesAreDistinct(this.getCanonicalPath(), pOtherPathname);
}
/*: :METHOD:081:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method replaces this file with another. The content of this file is made to be an exact copy of
the replacement file and the replacement file no longer exists after this method completes.
<P><B>Implementation: </B><A HREF="XFile.java.html#081">View source</A>
@param
pReplacementPathname is anything that can be converted to a String representing the name of any
file.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type1> void replaceFile(Type1 pReplacementPathname) throws Exception
{
replaceFile(this.getCanonicalPath(), pReplacementPathname);
}
/*: :METHOD:082:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method replaces one file with another. The content of the original file is made to be an exact
copy of the replacement file and the replacement file no longer exists after this method completes.
This method guarantees that a copy of the original file is kept until a successful and verified
replacement of it has occured.
<P><B>Implementation: </B><A HREF="XFile.java.html#082">View source</A>
@param
pOriginalPathname is anything that can be converted to a String representing the name of any file
@param
pReplacementPathname is anything that can be converted to a String representing the name of any
file
*//*
---------------------------------------------------------------------------------------------------- */
public static <Type1, Type2> void replaceFile
(
Type1 pOriginalPathname,
Type2 pReplacementPathname
)
throws Exception
{
/*.
==========================================================================================
Check the parameters.
------------------------------------------------------------------------------------------ */
if (pOriginalPathname == null)
{
throw new Exception("pOriginalPathname is null");
}
if (pReplacementPathname == null)
{
throw new Exception("pReplacementPathname is null");
}
if (pOriginalPathname.equals(pReplacementPathname))
{
throw new Exception("pOriginalPathname and pReplacementPathname are the same file");
}
/*.
==========================================================================================
Open the two files. These XFile constructors throw an Exception if anything goes wrong.
------------------------------------------------------------------------------------------ */
XFile originalFile = new XFile(UString.toString(pOriginalPathname));
XFile replacementFile = new XFile(UString.toString(pReplacementPathname));
/*.
==========================================================================================
Make sure we're not messing with directories and these are two different files.
------------------------------------------------------------------------------------------ */
if ( ! filesAreNormalAndDistinct(originalFile, replacementFile))
{
cOut.titledSeverityPrintf
(
Const.HALT,
CLASS_NAME,
"I/O Error: pOriginalPathname <" +
UString.toString(pOriginalPathname) +
" and/or pReplacementPathname <" +
UString.toString(pReplacementPathname) +
"> either refer to a directory or refer to the same file." +
" " +
"The original file <" +
UString.toString(pOriginalPathname) +
"> was not changed."
);
throw new Exception("Files are not normal and distinct.");
}
/*.
==========================================================================================
Only replace the file if it is different from the original
------------------------------------------------------------------------------------------ */
if (originalFile.contentEquals(replacementFile))
{
/*.
==========================================================================================
Delete the replacement file.
------------------------------------------------------------------------------------------ */
if ( ! replacementFile.delete())
{
throw new Exception("Cannot delete replacement file <" + replacementFile.getCanonicalPath() + ">");
}
replacementFile = null;
return;
}
/*.
==========================================================================================
Make a temporary "Save My Ass" file. This throws an Exception if anything goes wrong.
------------------------------------------------------------------------------------------ */
String recoveryPathname = null;
XFile recoveryFile = null;
try
{
recoveryPathname = Util.getTempFileName().toString();
recoveryFile = new XFile(recoveryPathname);
}
catch (Exception e)
{
cOut.titledSeverityPrintf
(
Const.HALT,
CLASS_NAME,
"I/O Error: Cannot create temporary recovery file <" +
recoveryPathname +
">." +
" " +
"The original file <" +
UString.toString(pOriginalPathname) +
"> was not changed."
);
throw e;
}
/*.
==========================================================================================
Make a temporary "Save My Ass" copy of the original file. This throws an Exception if
anything goes wrong.
------------------------------------------------------------------------------------------ */
try
{
recoveryFile.copyFrom(originalFile);
}
catch (Exception e)
{
cOut.titledSeverityPrintf
(
Const.HALT,
CLASS_NAME,
"I/O Error: Cannot copy original file <" +
originalFile.getCanonicalPath() +
"> into recovery file <" +
recoveryFile.getCanonicalPath() +
">." +
" " +
"The original file <" +
UString.toString(pOriginalPathname) +
"> was not changed."
);
throw e;
}
/*.
==========================================================================================
Test to make sure the copy was exact. This throws an Exception if anything goes wrong.
------------------------------------------------------------------------------------------ */
if ( ! recoveryFile.contentEquals(originalFile))
{
cOut.titledSeverityPrintf
(
Const.HALT,
CLASS_NAME,
"I/O Error: recovery file <" +
recoveryFile.getCanonicalPath() +
"> is not an exact copy of the original file <" +
originalFile.getCanonicalPath() +
">." +
" " +
"The original file <" +
UString.toString(pOriginalPathname) +
"> was not changed."
);
throw new Exception("Copy of original file to recovery file failed");
}
/*.
==========================================================================================
For source code files, we do something special. We load the full content of both the
original and the replacement file into separate XStrings. Then we delete all the
whitespace out of both XStrings. Then we compare the two XStrings and if they are
different, we print a warning message and save the original somewhere so the user can
retrieve it after this file replacement method is done. Often, there are meaningful
changes made to a source file before this replace method is called, and in those cases the
user can ignore the warning. If however, the changes were just cosmetic formatting (extra
or reduced whitespace, including newlines, spaces instead of tabs, etc.) then after
removing all the whitespace, the two files should be identical. If the user wasn't
expecting any changes of substance, the warning message will tell him where he can recover
the original file from.
------------------------------------------------------------------------------------------ */
boolean keeprecoveryFile = false;
XString extension = originalFile.getExtension();
boolean isSourceFile =
(
extension.equalsIgnoreCase("java")
|| extension.equalsIgnoreCase("c")
|| extension.equalsIgnoreCase("cpp")
|| extension.equalsIgnoreCase("cs")
|| extension.equalsIgnoreCase("cpp")
|| extension.equalsIgnoreCase("h")
|| extension.equalsIgnoreCase("hpp")
|| extension.equalsIgnoreCase("bas")
|| extension.equalsIgnoreCase("vba")
|| extension.equalsIgnoreCase("js")
);
if (isSourceFile)
{
XString theWholeOriginalFile = new XString(originalFile ).replaceAll("\\s+","").replace("/", "");
XString theWholeReplacementFile = new XString(replacementFile).replaceAll("\\s+","").replace("/", "");
if (!theWholeOriginalFile.contentEquals(theWholeReplacementFile))
{
keeprecoveryFile = true;
cOut.titledSeverityPrintf
(
Const.WARNING,
CLASS_NAME,
"Substantive Source Code Change: The file changes will go beyond simple whitespace " +
"formatting changes to include format-insensitive content changes as well. If " +
"that is unexpected, a recovery copy of the original file was saved, and you " +
"can restore the original from it if needed.\n" +
"\n" +
"=> Original file ------- <" + originalFile.getCanonicalPath() + ">\n" +
"=> Saved recovery file - <" + recoveryFile.getCanonicalPath() + ">\n" +
"\n" +
"Moving on now to modify the original file . . .\n" +
" "
);
}
theWholeOriginalFile = null;
theWholeReplacementFile = null;
}
/*.
==========================================================================================
Copy the replacement file into the original file. This throws an Exception if anything
goes wrong.
------------------------------------------------------------------------------------------ */
try
{
originalFile.copyFrom(replacementFile);
}
catch (Exception e)
{
cOut.titledSeverityPrintf
(
Const.HALT,
CLASS_NAME,
"I/O Error: Cannot overwrite original file <" +
originalFile.getCanonicalPath() +
"> from replacement file <" +
replacementFile.getCanonicalPath() +
">. Just in case, a recovery copy of the " +
"original file is in <" +
recoveryFile.getCanonicalPath() +
">."
);
throw e;
}
/*.
==========================================================================================
Test to make sure the copy was exact. This throws an Exception if anything goes wrong.
------------------------------------------------------------------------------------------ */
if ( ! originalFile.contentEquals(replacementFile))
{
cOut.titledSeverityPrintf
(
Const.HALT,
CLASS_NAME,
"I/O Error: Original file <" +
originalFile.getCanonicalPath() +
"> is not an exact copy of the replacement file <" +
replacementFile.getCanonicalPath() +
">. A recovery copy of the original file is in <" +
recoveryFile.getCanonicalPath() +
">."
);
throw new Exception("Copy of replacement file to original file failed");
}
/*.
==========================================================================================
Unless the "Save My Ass" file needs to be kept as a recovery file, delete it.
------------------------------------------------------------------------------------------ */
if (!keeprecoveryFile)
{
if (!recoveryFile.delete())
{
throw new Exception
(
"I/O Error: Cannot delete temporary recovery file. (It's a copy of the original file). " +
"The requested changes WERE successfully made to the original file. Hence, the " +
"recovery file is no longer needed. So an attempt was made to delete it, but failed.\n" +
"\n" +
"=> Original file ----------- <" + originalFile.getCanonicalPath() + ">\n" +
"=> Temporary recovery file - <" + recoveryFile.getCanonicalPath() + ">\n" +
"\n" +
"Other than investigating why this I/O operation failed and fixing the problem, " +
"no user action is required. However, you may want to go occasionally to the " +
"temp directory and clean out leftover junk like this unneeded recovery file."
);
}
recoveryFile = null;
}
/*.
==========================================================================================
Delete the replacement file.
------------------------------------------------------------------------------------------ */
if ( ! replacementFile.delete())
{
throw new Exception
(
"I/O Error: Cannot delete temporary replacement file. (It was used during the " +
"modification of the original file). " +
"The requested changes WERE successfully made to the original file and the " +
"replacement file is no longer needed. So an attempt was made to delete it, but " +
"failed.\n" +
"\n" +
"=> Original file -------------- <" + originalFile.getCanonicalPath() + ">\n" +
"=> Temporary replacement file - <" + replacementFile.getCanonicalPath() + ">\n" +
"\n" +
"Other than investigating why this I/O operation failed and fixing the problem, " +
"no user action is required. However, you may want to go occasionally to the " +
"temp directory and clean out leftover junk like this unneeded replacement file."
);
}
replacementFile = null;
}
/*: :METHOD:083:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method supports a pattern I use over and over. The pattern is that a file is to be modified in
place. The pathname of the file to modify is provided and must be validated to ensure that it exists
and that it is not a directory. Then a temporary file is created. A call is made to another method
(call it the "modifying method") and it is passed the pathnames for the file to modify and the
temporary file. The modifying method arranges to modify the file by reading the file to modify,
modifying the content as it reads it, and placing the modified content into the temporary file. When
it's done, it returns here and this method applies XFile's robust replaceFile() method to replace
the original file with the temporary file containing the modifications.
<P><B>Implementation: </B><A HREF="XFile.java.html#083">View source</A>
@param
pInPathname is the name of the file to modify
@param
pMethodStack is a stack of Methods. This method pops the stack and that method is the one that is
used as the modifying method . What's left of the stack is passed along to the modifying method
that is called from in here.
@param
pArguments is a variable list of arguments containing anywhere from 0 to n additional arguments
which this method passes along to the modifying method it calls.
*//*
---------------------------------------------------------------------------------------------------- */
public static <Type1> Type1 modifyXFileInPlace(String pInPathname, Stack<Method> pMethodStack, Object... pArguments) throws Exception
{
Type1 result;
/*.
==========================================================================================
Get the arguments we're interested in from pArguments. PArguments[0] is always a
Stack<Method> with the first element being the method we will call from in this method.
------------------------------------------------------------------------------------------ */
Method runMethod = pMethodStack.pop();
/*.
==========================================================================================
Get file for input, create file for output
------------------------------------------------------------------------------------------ */
File inFile = new File(pInPathname);
File outFile = new XFile(File.createTempFile(CLASS_NAME.toString() + ".modifyXFileInPlace",".tmp"));
/*.
==========================================================================================
Get file pathnames
------------------------------------------------------------------------------------------ */
String outPathname = outFile.getCanonicalPath();
pInPathname = inFile.getCanonicalPath();
/*.
==========================================================================================
Make sure the input file exists.
------------------------------------------------------------------------------------------ */
if ( ! inFile.exists())
{
outFile.delete();
inFile = null;
outFile = null;
cOut.titledSeverityPrintf(Const.HALT, CLASS_NAME, "I/O Error: <" + pInPathname +"> does not exist.");
throw new Exception("Input file does not exist.");
}
/*.
==========================================================================================
Make sure we're not messing with a directory.
------------------------------------------------------------------------------------------ */
if ( ! inFile.isFile())
{
outFile.delete();
inFile = null;
outFile = null;
cOut.titledSeverityPrintf(Const.HALT, CLASS_NAME, "I/O Error: <" + pInPathname +"> is a directory.");
throw new Exception("Input file cannot be a directory.");
}
/*.
==========================================================================================
We just needed the pathnames so free the Files for the garbage collector.
------------------------------------------------------------------------------------------ */
inFile = null;
outFile = null;
/*.
==========================================================================================
Call the next method in the stack
------------------------------------------------------------------------------------------ */
if (pMethodStack.size() == 0) result = Util.invoke(runMethod, pInPathname, outPathname, pArguments);
else result = Util.invoke(runMethod, pInPathname, outPathname, pMethodStack, pArguments);
/*.
==========================================================================================
Delete the original file and replace it with the new file.
------------------------------------------------------------------------------------------ */
XFile.replaceFile(pInPathname, outPathname);
return result;
}
/*: :METHOD:084:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method sets the ConsoleStream for this object.
<P><B>Implementation: </B><A HREF="XFile.java.html#084">View source</A>
@return
A reference to this object
@param
pConsole is a ConsoleStream through which this objects sends its output.
*//*
---------------------------------------------------------------------------------------------------- */
public XFile setOut(ConsoleStream pConsole)
{
cOut = pConsole;
return this;
}
/*: :METHOD:085:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This boilerplate method is used for testing an instantiated object of this class and may include any
code the developer chooses.
<P><B>Implementation: </B><A HREF="XFile.java.html#085">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public XFile test() throws Exception
{
cOut.titledPrintf
(
"\"HELLO WORLD!\"",
"%s %s %s",
"I'm an object of the", CLASS_NAME, "class, and I approved this message."
);
return this;
}
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Protected ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Private ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */
/*.
==========================================================================================
Class Constants
CLASS_NAME : the name of this class DFLT_LINE_LEN : the default line length for word
wrapping
------------------------------------------------------------------------------------------ */
private static final XString CLASS_NAME = new XString(XFile.class.getName());
private static final int DFLT_LINE_LEN = ConsoleMessage.defaultLineLength();
private static final int MAX_BKUPS = 3;
/*.
==========================================================================================
Class variables
cOut : console output.
------------------------------------------------------------------------------------------ */
private static ConsoleStream cOut = ConsoleStream.getSingleton();
/*.
==========================================================================================
Instance variables
iOut : console output. ICipher : the cipher object used to encrypt/decrypt this XFile
------------------------------------------------------------------------------------------ */
private FileCipher iCipher = null;
/*: :METHOD:086:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method deletes the file or directory denoted by this abstract pathname.
<P><B>Implementation: </B><A HREF="XFile.java.html#086">View source</A>
@return
True if and only if the file or directory is successfully deleted; false otherwise
*//*
---------------------------------------------------------------------------------------------------- */
private static boolean deleteFile(File pFile)
{
/*.
==========================================================================================
HACK (NEW) - 2013.12.08: Got this additional tip from:
Http://stackoverflow.com/questions/991489/i-cant-delete-a-file-in-java
------------------------------------------------------------------------------------------ */
pFile.setWritable(true);
/*.
==========================================================================================
HACK - I should just be able to call delete() here and return its result. In fact, I used
to do just that and this method always worked fine. Now with this new version of Java
(1.5.0), delete (and other file methods) sometimes don't work on the first try. This is
because file objects that have been closed are hung onto, pending garbage collection. By
suggesting garbage collection, the next time, the delete() usually (but not always) works.
I'm not the only one with this issue. See: http://java.itags.org/java-essentials/79385/
------------------------------------------------------------------------------------------ */
for (int i=0; i<20; i++)
{
if (pFile.delete())
{
return true;
}
System.gc();
Util.sleep(50);
}
return false;
}
/*: :METHOD:087:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method deletes the file or directory denoted by this abstract pathname.
<P><B>Implementation: </B><A HREF="XFile.java.html#087">View source</A>
@return
True if and only if the file or directory is successfully deleted; false otherwise
*//*
---------------------------------------------------------------------------------------------------- */
private boolean deleteFile() throws IOException
{
File file = new File(this.getCanonicalPath());
return deleteFile(file);
}
/*: :METHOD:088:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method wipes the file denoted by this abstract pathname.<P>
WipeFile() is a security tool, which allows you to completely remove sensitive data from your hard
disk by overwriting it with random data.
Caveats:
1) On a journaling filesystem like NTFS there is actually no way to securely erase a single file
Without wiping all the free space on the drive. The problem is that the new blocks (which
you've presumably overwritten with random data) are not guaranteed to be in the same place on
disk as the old ones.
2) On systems with buffered IO subsystems, there is no guarantee that this method will work to
Actually overwrite the file blocks on disk because the IO subsystem buffering mechanism may
not commit the bytes to disk immediately and there is no way to force it to. It is possible
that the bytes won't be committed to disk before the file is deleted. In that case, the IO
subsystem may simply release the contents of its internal buffers and delete the file without
ever committing the new bytes to disk.
Therefor, in order to keep your data secure, the only real solution you have is to completely
encrypt the drive
<P><B>Implementation: </B><A HREF="XFile.java.html#088">View source</A>
@return
True if and only if the file is successfully deleted; false otherwise
*//*
---------------------------------------------------------------------------------------------------- */
private static boolean wipeFile(File pFile)
{
try
{
if (pFile.exists())
{
/*.
==========================================================================================
1) the size of a file is given as a long. The size of a byte array is assumed by write()
To be given as an int.
2) we don't want Java to extend the file size (reallocating blocks and all that) so we
Don't want to pass in more data than will fit in the existing file (the blocks already
allocated) because our ultimate purpose here is overwrite those already allocated
blocks.
So the largest byte array that can be passed to write() is either the size of the file or
the maximum integer size, whichever is LESS. Furthermore, an array that is the maximum
integer size long would be 2Gb and we neither want to allocate that big of an array nor
have to generate that much random data to fill it with. So we'll allocate the file size or
a smaller integer of our choice, whichever is less.
------------------------------------------------------------------------------------------ */
long length = pFile.length();
int numBytes = (int)Math.min(length,(long)(2 * UMath.ONE_MEG));
if (numBytes > 0)
{
byte[] data = new byte[numBytes];
/*.
==========================================================================================
We're gonna overwrite the contents of the file with the contents of our byte array which
we fill with random data
------------------------------------------------------------------------------------------ */
Random randGenerator = new Random();
randGenerator.nextBytes(data);
/*.
==========================================================================================
We're gonna overwrite the contents of a file by treating it as a writable random access
file in which we set the write pointer to the first byte in the file by using the seek()
method.
------------------------------------------------------------------------------------------ */
RandomAccessFile raFile = new RandomAccessFile(pFile, "rws");
raFile.seek(0);
/*.
==========================================================================================
Write the random data byte array to the file as many times as it will completely fit
------------------------------------------------------------------------------------------ */
for (long i=1; i<(length/numBytes); i++)
{
raFile.write(data);
}
/*.
==========================================================================================
There will likely be a small chunk of the file remaining at the end (the last bit that is
less than numBytes long). Figure out how big it is, allocate a new byte array exactly that
long, fill it with random data and write it out to the end of the file.
------------------------------------------------------------------------------------------ */
numBytes = (int)(length % (long)numBytes);
if (numBytes > 0)
{
data = new byte[numBytes];
randGenerator.nextBytes(data);
raFile.write(data);
}
/*.
==========================================================================================
There is no guarantee that this method will work to actually overwrite the file blocks on
disk because the IO subsystem buffering mechanism may not commit the bytes to disk
immediately and there is no way to force it to. It is possible that the bytes won't be
committed to disk before the file is deleted in the next code section of this method. In
that case, the IO subsystem may simply release the contents of its internal buffers and
delete the file without ever committing the new bytes to disk. This section of code is
intended to give the IO subsystem a chance to commit the bytes by relinquishing the CPU
for a bit. It does not guarantee that the IO subsystem will commit the bytes though.
------------------------------------------------------------------------------------------ */
raFile.close();
Util.sleep(50);
}
/*.
==========================================================================================
Hopefully the bytes on disk were overwritten. Go ahead and delete the file now and hope
for the best.
------------------------------------------------------------------------------------------ */
return deleteFile(pFile);
}
return false;
}
catch (Exception e)
{
return false;
}
}
/*: :METHOD:089:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method wipes the file denoted by this abstract pathname.
WipeFile() is a security tool, which allows you to completely remove sensitive data from your hard
disk by overwriting it with random data.
Caveat: Caveat:
On a journaling filesystem like NTFS there is actually no way to securely erase a single file
without wiping all the free space on the drive. The problem is that the new blocks (which you've
presumably overwritten with random data) are not guaranteed to be in the same place on disk as
the old ones.
In order to keep your data secure, the only real solution you have is to completely encrypt the
drive
<P><B>Implementation: </B><A HREF="XFile.java.html#089">View source</A>
@return
True if and only if the file or directory is successfully wiped; false otherwise
*//*
---------------------------------------------------------------------------------------------------- */
private boolean wipeFile() throws IOException
{
File file = new File(this.getCanonicalPath());
return wipeFile(file);
}
/*: :METHOD:090:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method should not be used except from inside of the public backup() method.
This method makes a backup of this file if this file is a normal file. It does not do anything if
this file is a directory. It also backs up any existing backups of this file, up to the number of
backup files specified by the static value of MAX_BKUPS. This method does the multi backup work for
backup(). Here is an example of what this method does:
<BLOCKQUOTE>
<PRE id="unindent">
* if
* this is a normal file named \temp\x.x
* and MAX_BKUPS is 3
* and the backup directory is \backup
*
* then the first time this method is called on \temp\x.x
* \temp\x.x is copied to \backup\temp\x.x.1
*
* and the second time this method is called on \temp\x.x
* first, \backup\temp\x.x.1 is copied to \backup\temp\x.x.2
* then, \temp\x.x is copied to \backup\temp\x.x.1
*
* and the third and all subsequent times this method is called on \temp\x.x
* first, \backup\temp\x.x.2 is copied to \backup\temp\x.x.3
* next, \backup\temp\x.x.1 is copied to \backup\temp\x.x.2
* then, \temp\x.x is copied to \backup\temp\x.x.1
</PRE>
</BLOCKQUOTE>
This method preserves file dates. In other words, it sets the file dates on the backup file to match
the dates on the file that the backup file backs up.
<P><B>Implementation: </B><A HREF="XFile.java.html#090">View source</A>
@param
pBackupDirName is the name of the directory that this file will be backed up into. Set this value
to null for the first call to this recursive method.
@param
pBackupFileName is the name of the file to be backed up. Set this value to null for the first
call to this recursive method.
@param
pBackupRecursionLevel is the current recursion level for this method. Set this value to 0 for the
first call to this recursive method.
*//*
---------------------------------------------------------------------------------------------------- */
private <Type1,Type2> void backupNormalFile
(
Type1 pBackupDirName,
Type2 pBackupFileName,
int pBackupRecursionLevel
)
throws Exception
{
XString backupDirName = XString.toXString(pBackupDirName);
XString backupFileName = XString.toXString(pBackupFileName);
/*.
==========================================================================================
This method does not do back ups of directories. Use the public method backup() instead
for directories.
------------------------------------------------------------------------------------------ */
if (this.isDirectory())
{
return;
}
/*.
==========================================================================================
This is a recursive method. This code is what stops the recursion. If all MAX_BKUPS have
already been backed up then this code stops any further back up efforts and allows the
recursion process to unwind.
------------------------------------------------------------------------------------------ */
if (pBackupRecursionLevel >= MAX_BKUPS)
{
return;
}
/*.
==========================================================================================
If this is the first call to this recursive method, then initialize the arguments and
build the backup directory path for this file.
------------------------------------------------------------------------------------------ */
if (pBackupRecursionLevel == 0)
{
backupFileName = new XString(this.getName());
backupDirName = new XString(Const.BKUPDIR.concat(this.getDrivelessParent()));
File backupDir = new File(UString.toString(backupDirName));
backupDir.mkdirs();
}
/*.
==========================================================================================
Keep track of what level of recursion we are at so that the recursion process can be
stopped after the specified number of recursions.
------------------------------------------------------------------------------------------ */
pBackupRecursionLevel++;
/*.
==========================================================================================
Figure out what the name of the backup file will be and create a file object for it
------------------------------------------------------------------------------------------ */
XString backupName = new XString
(
backupDirName.string() +
"/" +
backupFileName.string() +
"." +
pBackupRecursionLevel
);
XFile backupFile = new XFile(backupName);
/*.
==========================================================================================
Recursively call this method to make a back up of this file's backup file.
------------------------------------------------------------------------------------------ */
backupFile.backupNormalFile(backupDirName,backupFileName,pBackupRecursionLevel);
/*.
==========================================================================================
Now back up this file.
------------------------------------------------------------------------------------------ */
if (this.exists())
{
this.copyTo(backupFile);
}
/*.
==========================================================================================
Pop the recursion level because we're going to return from this recursive call.
------------------------------------------------------------------------------------------ */
pBackupRecursionLevel--;
}
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Inner Classes ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Public Static Methods ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */
/*: :METHOD:091:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method allows this class file to be unit tested as a standalone application. It's the method
that's called when the class is invoked from the command line by using the java application launcher
- "java". Main() is not a required method, but the practice of putting one in each class and
wrapping class test code within it allows easy unit testing of the class; and main does not need to
be removed when testing is complete.
<P>
<DL>
<DT>
<B>
Command line usage:
</B>
<DD>
Java cosmicabyss.com.lib.XFile
</DD>
</DT>
</DL>
<P><B>Implementation: </B><A HREF="XFile.java.html#091">View source</A>
@param
pArgs contains the command line arguments with which this class was invoked as an application.
*//*
---------------------------------------------------------------------------------------------------- */
public static void main(String[] pArgs) throws Exception
{
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
XFile f1 = new XFile("C:/ABDITORY/bat/9xx/Cmplr/LLVM/config.guess");
f1.setCreated(1992, 6, 15);
f1.setLastModified(2017, 3, 5);
XFile f2 = new XFile("C:/ABDITORY/bat/9xx/Cmplr/LLVM/config.sub");
f2.setCreated(1992, 7, 15);
f2.setLastModified(2017, 4, 2);
}
} // class XFile
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Notes ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */