I'm using this script on WINDOWS
public void copyFile(File sourceDirectory, File targetFile, File targetDirectory) throws IOException{
String temp = targetFile.getAbsolutePath();
String relativeD = temp.substring(sourceDirectory.getAbsolutePath().length(), targetFile.getAbsolutePath().length());
String rootD = sourceDirectory.getName();
String fullPath = targetDirectory.getAbsolutePath() + rootD + relativeD;
File fP = new File( fullPath );
System.out.println("PATH: " + fullPath);
FileChannel inChannel = new FileInputStream(targetFile).getChannel();
FileChannel outChannel = new FileOutputStream( fP ).getChannel();
int maxCount = (64 * 1024 * 1024) - (32 * 1024);
long size = inChannel.size();
long position = 0;
while (position < size) {
position += inChannel.transferTo(position, maxCount, outChannel);
}
if (inChannel != null) inChannel.close();
if (outChannel != null) outChannel.close();
}
What I'm doing is simple. I need to copy a file from a location to another but I have to keep the directories they're in.
So with relativeD I'm taking something like this: dir/files.sql or simply files.sql.
This is happening because for specific directories I need to copy them recursively respecting the tree structure.
The problem is this method is not working. I don't know why because if I use a simple
FileChannel outChannel = new FileOutputStream( new File( targetDirectory, targetFile ) ).getChannel();
it works. I suppose this is happening because in this case it's copying the file under an existing directory.
According to this article (top Google search hit for 'java mkdir recursive'):
Have a look at the java.io.File : it does the job perfectly, with the mkdirs function :
new File("c:/aaa/bbb/ccc/ddd").mkdirs();
Related
I have a program that needs to be able to create an executable JAR-file of itself, but I'm unfortunately having some trouble making it work. This is the method I'm currently using to create the JAR:
public static void createJar() throws IOException {
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, "JarTest");
JarOutputStream jos = null;
try {
String jarPath = System.getProperty("user.dir") + "/Test.jar";
jos = new JarOutputStream(new FileOutputStream(jarPath), manifest);
}
catch (IOException e) {e.printStackTrace();}
ArrayList<String> fileList = new ArrayList<String>();
String codeDir = System.getProperty("user.dir") + "/bin/jartest/";
Files.list(Paths.get(codeDir)).forEach(entry -> {
fileList.add(((Path)entry).toString());
});
int len = 0;
byte[] buffer = new byte[1024];
for(String file : fileList ) {
//create JarEntry
JarEntry je = new JarEntry(file);
je.setComment("Creating Jar");
je.setTime(Calendar.getInstance().getTimeInMillis());
System.out.println(je);
jos.putNextEntry(je);
//write the bytes of file into jar
InputStream is = new BufferedInputStream(new FileInputStream(file));
while((len = is.read(buffer, 0, buffer.length)) != -1)
jos.write(buffer, 0, len);
is.close();
jos.closeEntry();
System.out.println("Done");
}
jos.close();
}
When I execute this no errors happen and I do get a JAR file called "Test.jar" generated in my Eclipse project folder. But when I open the JAR the .class files are not there, instead I see this:
I know that it's finding the .class files since the line System.out.println(je); successfully prints out the absolute path of each of them, so why aren't they getting put into the JAR?
It solved itself when I changed these two lines:
String jarPath = System.getProperty("user.dir") + "/Test.jar";
String codeDir = System.getProperty("user.dir") + "/bin/jartest/";
To these:
String jarPath = "Test.jar";
String codeDir = "bin/jartest/";
I can now see the .class files inside the JAR.
Scenario: Uncompress a tar file using Apache commons.
Problem: The tar i am using is a build tar which gets deployed into a web server. This tar contains duplicate entries like below.
appender_class.xml
APPENDER_CLASS.xml
when extracting using the below code only appender_class.xml is extracted but i want both the files how can i do that ? Renaming in fly is fine but how can i accomplish that?
public static void untar(File[] files) throws Exception {
String path = files[0].toString();
File tarPath = new File(path);
TarEntry entry;
TarInputStream inputStream = null;
FileOutputStream outputStream = null;
try {
inputStream = new TarInputStream(new FileInputStream(tarPath));
while (null != (entry = inputStream.getNextEntry())) {
int bytesRead;
System.out.println("tarpath:" + tarPath.getName());
System.out.println("Entry:" + entry.getName());
String pathWithoutName = path.substring(0, path.indexOf(tarPath.getName()));
System.out.println("pathname:" + pathWithoutName);
if (entry.isDirectory()) {
File directory = new File(pathWithoutName + entry.getName());
directory.mkdir();
continue;
}
byte[] buffer = new byte[1024];
outputStream = new FileOutputStream(pathWithoutName + entry.getName());
while ((bytesRead = inputStream.read(buffer, 0, 1024)) > -1) {
outputStream.write(buffer, 0, bytesRead);
}
System.out.println("Extracted " + entry.getName());
}
}
Try opening your FileOutputstream like this instead:
File outputFile = new File(pathWithoutName + entry.getName());
for(int i = 2; outputFile.exists(); i++) {
outputFile = new File(pathWithoutName + entry.getName() + i);
}
outputStream = new FileOutputStream(outputFile);
It should generate a file called APPENDER_CLASS.xml2 if it encounters a previously created file called APPENDER_CLASS.xml. If a APPENDER_CLASS.xml2 exists it will create a APPENDER_CLASS.xml3, ad infinitum.
File.exists() takes case sensitivity into account (windows filenames are case insensitive, whereas unix, linux and mac are case sensitive). Thus with the above code on case insensitive filesystems the file would be renamed and on case sensitive filesystems the file would not be renamed.
I am using jtar-1.1 to try extract files from a tar file, im using the following code to try extract the files
String tarFile = "c:/test/test.tar";
String destFolder = "c:/test/myfiles";
// Create a TarInputStream
TarInputStream tis = new TarInputStream(new BufferedInputStream(new FileInputStream(tarFile)));
while (( entry = tis.getNextEntry() ) != null) {
System.out.println( "Extracting: " + entry.getName() );
int count;
byte data[] = new byte[BUFFER];
if (entry.isDirectory()) {
new File( destFolder + "/" + entry.getName() ).mkdirs();
continue;
} else {
int di = entry.getName().lastIndexOf( '/' );
if (di != -1) {
new File( destFolder + "/" + entry.getName().substring( 0, di ) ).mkdirs();
}
}
FileOutputStream fos = new FileOutputStream( destFolder + "/" + entry.getName() );
BufferedOutputStream dest = new BufferedOutputStream( fos );
while (( count = tis.read( data ) ) != -1) {
dest.write( data, 0, count );
}
dest.flush();
dest.close();
}
}
EDIT:
I have edited the code above to check is the entry a directory and once i done this it got rid of the FileNotFound error... the above code now works
I think you need to create the path before opening the FileOutputStream.
Similar Thread Here
Just off the cuff, perhaps the issue is that the entry you are receiving contains a subfolder that hasn't been created yet: 'LAB3'? In this case the directory 'LAB3' doesn't exist in the file system because you haven't created it and the file 'sg5' intends to be placed there so when you try to create a file on the fully qualified path that includes LAB3 it complains.
NOTE: This is a followup to my question here.
I have a program that takes the contents of a directory and bundles everything into a JAR file. The code I use to do this is here:
try
{
FileOutputStream stream = new FileOutputStream(target);
JarOutputStream jOS = new JarOutputStream(stream);
LinkedList<File> fileList = new LinkedList<File>();
buildList(directory, fileList);
JarEntry jarAdd;
String basePath = directory.getAbsolutePath();
byte[] buffer = new byte[4096];
for(File file : fileList)
{
String path = file.getPath().substring(basePath.length() + 1);
path.replaceAll("\\\\", "/");
jarAdd = new JarEntry(path);
jarAdd.setTime(file.lastModified());
jOS.putNextEntry(jarAdd);
FileInputStream in = new FileInputStream(file);
while(true)
{
int nRead = in.read(buffer, 0, buffer.length);
if(nRead <= 0)
break;
jOS.write(buffer, 0, nRead);
}
in.close();
}
jOS.close();
stream.close();
So, all is well and good and the jar gets created, and when I explore its contents with 7-zip it has all the files I need. However, when I try to access the contents of the Jar via a URLClassLoader (the jar is not on the classpath and I don't intend it to be), I get null pointer exceptions.
The odd thing is, when I use a Jar that I've exported from Eclipse, I can access the contents of it in the way I want. This leads me to believe that I'm somehow not creating the Jar correctly, and am leaving something out. Is there anything missing from the method up above?
I figured it out based on this question - the problem was me not properly handling backslashes.
Fixed code is here:
FileOutputStream stream = new FileOutputStream(target);
JarOutputStream jOS = new JarOutputStream(stream);
LinkedList<File> fileList = new LinkedList<File>();
buildList(directory, fileList);
JarEntry entry;
String basePath = directory.getAbsolutePath();
byte[] buffer = new byte[4096];
for(File file : fileList)
{
String path = file.getPath().substring(basePath.length() + 1);
path = path.replace("\\", "/");
entry = new JarEntry(path);
entry.setTime(file.lastModified());
jOS.putNextEntry(entry);
FileInputStream in = new FileInputStream(file);
while(true)
{
int nRead = in.read(buffer, 0, buffer.length);
if(nRead <= 0)
break;
jOS.write(buffer, 0, nRead);
}
in.close();
jOS.closeEntry();
}
jOS.close();
stream.close();
I am working with some file manipulations, just simple read and writes using the java APIs File object.
so here is what I do. first the application receives a zip file, then it extracts the contents on a TEMPFOLDER. And then another class, totally independent, will work on the TEMPFOLDER. It will check the number of files and it should count them all. then it will do stuff to perform some database functions to write the contents of the zip file to the DB
but here is the problem, when I use the application for the first time it goes well smoothly. then WHEN I DO IT THE SECOND TIME AROUND it will fail because the second class which is supposed to check the TEMPFOLDER return 0 as the number of files in the said folder but when I check it manually, it has some contents.
and the pattern it does when I test it continously, it will work, then it will not work, it will work, then it will not work. it acts like that. the reason it does not work is because the application cannot determine correctly the number of files in a folder. it has files but the file object is returning that it has no items in it. but after the error, if you run it again it will work as it is supposed to work.
if you could give out some suggestions from my explanation which is a thousand feet view, i would appreciate it and try it for my debugging. but if you would need some codes, i will post them later
by the way, I am using a web browser and a servlet to accept the zip file
here is the method that i used to write to file system.
public void extractZipAndWriteContentsToFileSystem(ZipFile zipFile) throws IOException, Exception {
Enumeration en = zipFile.entries();
while (en.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) en.nextElement();
String name = zipEntry.getName();
long size = zipEntry.getSize();
long compressedSize = zipEntry.getCompressedSize();
File file = new File(zipExtractsTempRepo+name);
if (name.endsWith("/")) {
file.mkdirs();
continue;
}
File parent = file.getParentFile();
if (parent != null) {
parent.mkdirs();
}
InputStream is = zipFile.getInputStream(zipEntry);
FileOutputStream fos = new FileOutputStream(file);
byte[] bytes = new byte[1024];
int length;
while ((length = is.read(bytes)) >= 0) {
fos.write(bytes, 0, length);
}
file = null;
parent = null;
is.close();
fos.close();
}
zipFile.close();
traverse(new File(zipExtractsTempRepo));
}
/**
* this method traverses through a folder and its subfolders
* and its subfolders and ...
*
* this method retrieves objects that are files. if it is not
* a file, (then a directory) it looks inside it to look
* for other files
*
* #param file
* #throws IOException
*/
public void traverse(File file) throws IOException {
if (file.isDirectory()) {
File[] allFiles = file.listFiles();
for (File aFile : allFiles) {
traverse(aFile);
}
} else {
FileInputStream in = new FileInputStream(file);
FileOutputStream out = new FileOutputStream(
new File(this.tempRepo + file.getName()));
byte[] bytes = new byte[1024];
int length;
while ((length = in.read(bytes)) >= 0) {
out.write(bytes, 0, length);
}
out.write(4024);
in.close();
out.close();
}
}
now this is the method on the second class to verify the number of file written on a folder
private File[] files;
private File[] zipExtracts;
// location of the tempfolder
tempFolder = new File(RawZipFileHandler.tempRepo);
files = tempFolder.listFiles();
public void checkNumberOfFiles() throws Exception {
Util.out("will check number of files");
// check the number of documents on the tempfile folder
if (files.length != 8) {
throw new Exception ("Number of files expected not met. Expected is 8 got " + files.length);
}
}
comments for my not so pretty code are also welcomed.