renaming file name inside a zip file - java

trying to rename internal file within a zip file without having to extract and then re-zip programatically.
example. test.zip contains test.txt, i want to change it so that test.zip will contain newtest.txt(test.txt renamed to newtest.txt, contents remain the same)
came across this link that works but unfortunately it expects test.txt to exist on the system. In the example the srcfile should exist on the server.
Blockquote Rename file in zip with zip4j
Then icame across zipnote on Linux that does the trick but unfortunately the version i have doesnt work for files >4GB.
Any suggestions on how to accomplish this? prefereably in java.

This should be possible using Java 7 Zip FileSystem provider, something like:
// syntax defined in java.net.JarURLConnection
URI uri = URI.create("jar:file:/directoryPath/file.zip");
try (FileSystem zipfs = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap())) {
Path sourceURI = zipfs.getPath("/pathToDirectoryInsideZip/file.txt");
Path destinationURI = zipfs.getPath("/pathToDirectoryInsideZip/renamed.txt");
Files.move(sourceURI, destinationURI);
}

Using zip4j, I am modifying and re-writing the file headers inside of the central directory section to avoid rewriting the entire zip file:
ArrayList<FileHeader> FHs = (ArrayList<FileHeader>) zipFile.getFileHeaders();
FHs.get(0).setFileName("namename.mp4");
FHs.get(0).setFileNameLength("namename.mp4".getBytes("UTF-8").length);
zipFile.updateHeaders ();
//where updateHeaders is :
public void updateHeaders() throws ZipException, IOException {
checkZipModel();
if (this.zipModel == null) {
throw new ZipException("internal error: zip model is null");
}
if (Zip4jUtil.checkFileExists(file)) {
if (zipModel.isSplitArchive()) {
throw new ZipException("Zip file already exists. Zip file format does not allow updating split/spanned files");
}
}
long offset = zipModel.getEndCentralDirRecord().getOffsetOfStartOfCentralDir();
HeaderWriter headerWriter = new HeaderWriter();
SplitOutputStream splitOutputStream = new SplitOutputStream(new File(zipModel.getZipFile()), -1);
splitOutputStream.seek(offset);
headerWriter.finalizeZipFile(zipModel, splitOutputStream);
splitOutputStream.close();
}
The name field in the local file header section remains unchanged, so there will be a mismatch exception in this library.
It's tricky but maybe problematic, I don't know..

Related

Creating temporary file and rename to actual file

I am trying to create a temporary file and then rename it to a usable file. The temp file is getting created in %temp% but not getting renamed:-
static void writeFile() {
try {
File tempFile = File.createTempFile("TEMP_FAILED_MASTER", "");
PrintWriter pw = new PrintWriter(tempFile);
for (String record : new String[] {"a","b"}) {
pw.println(record);
}
pw.flush();
pw.close();
System.out.println(tempFile.getAbsolutePath());
File errFile = new File("C:/bar.txt");
tempFile.renameTo(errFile);
System.out.println(errFile.getAbsolutePath());
System.out.println("Check!");
} catch (Exception e) {
e.printStackTrace();
}
}
There are a few reasons why a rename can fail. The common ones are:
You don't have write permission for the source or destination directory.
The file you are renaming is open (on Windows)
You are attempting to rename across different file systems.
It can be difficult to diagnose these (and other) failure reasons if you are using File.renameTo because all you get is a boolean return value.
I recommend using Files.move instead. It can cope with moving files between file systems, and will throw an exception if the file cannot be renamed.

Deleting file inside a zip in java

I have a folder which contains some files, now I want to append these files to a zip which already exists. If the file I am adding to the zip is already there, then I am replacing the old file with the new one. For zip operations I am using zip4j jar. This is the piece of my code
for(File entry : temp.listFiles())
{
String file = entry.getName();
if(trgZip.getFileHeader(file) != null)
{
trgZip.removeFile(file);
}
ZipParameters param = new ZipParameters();
trgZip.addFile(entry, param);
}
But I am getting this exception
net.lingala.zip4j.exception.ZipException: cannot delete old zip file
can anyone please suggest what should I do to correct this, or where I am going wrong, or how does this removeFile method works, so that I can try locate the point of error.
Thanks in advance
Try this... !! Provide path to you zip file as first argument and filename which you want to delete from zip file as your second argument.
public static void deleteFile(String zipFilePath,String fileName) throws Exception{
Map<String, String> zip_properties = new HashMap<>();
zip_properties.put("create", "false");
/* Specify the path to the ZIP File that you want to read as a File System */
URI zip_disk = URI.create("jar:file:"+zipFilePath);
/* Create ZIP file System */
try (FileSystem zipfs = FileSystems.newFileSystem(zip_disk, zip_properties)) {
/* Get the Path inside ZIP File to delete the ZIP Entry */
Path pathInZipfile = zipfs.getPath(fileName);
System.out.println("About to delete an entry from ZIP File" + pathInZipfile.toUri() );
/* Execute Delete */
Files.delete(pathInZipfile);
System.out.println("File successfully deleted");
}
}

Locate a specific file in a directory by name plus saving a file to the local folder

I would like to locate a file named SAVE.properties. I have looked at different questions that seem like they would answer me, but I can't see that they do.
For example, I would like to check to see whether or not SAVE.properties exists within a directory (and its subfolders).
I would also like to know how I could save a .properties file (and then read it afterwards from this location) to the directory where my program is being run from. If it is run from the desktop, it should save the .properties file there.
Saving properties can easily be achieved through the use of Properties#store(OutputStream, String), this allows you to define where the contents is saved to through the use of an OutputStream.
So you could use...
Properties properties = ...;
//...
try (FileOutputStream os = new FileOutputStream(new File("SAVE.properties"))) {
properties.store(os, "Save");
} catch (IOException exp) {
exp.printStackTrace();
}
You can also use Properties#load(InputStream) to read the contents of a "properties" file.
Take a closer look at Basic I/O for more details.
Locating a File is as simple as using
File file = new File("SAVE.properties");
if (file.exists) {...
This checks the current working directory for the existence of the specified file.
Searching the sub directories is little more involved and will require you to use some recursion, for example...
public File find(File path) {
File save = new File(path, "SAVE.properties");
if (!save.exists()) {
save = null;
File[] dirs = path.listFiles(new FileFilter() {
#Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for (File dir : dirs) {
save = find(dir);
if (save != null) {
break;
}
}
}
return save;
}
Using find(new File(".")) will start searching from the current working directory. Just beware, under the right circumstances, this could search your entire hard disk.

Is it possible to create a NEW zip file using the java FileSystem?

I've successfully modified the contents of a (existing) zip file using the FileSystem provided by java 7, but when I tried to create a NEW zip file by this method it fails, with the error message that says: "zip END header not found", it is logical because of the way I'm doing it, first I create the file (Files.createFile) which is a completely empty file, and then I try to access to its file system , and since the file is empty its impossible to find any header inside the zip, my question is is there any way to create a new zip file completely empty using this method?; the hack that I've considered is adding an empty new ZipEntry to a the zip file and then using that new empty file to crate the file system based on it, but i really want to think that the guys of oracle implemented a better (easier) way to do this with nio and the filesystems...
this is my code (the error appears when creating the file system):
if (!zipLocation.toFile().exists()) {
if (creatingFile) {
Files.createFile(zipLocation);
}else {
return false;
}
} else if (zipLocation.toFile().exists() && !replacing) {
return false;
}
final FileSystem fs = FileSystems.newFileSystem(zipLocation, null);
.
.
.
zipLocation is a Path
creatingFile is a boolean
ANSWER:
in my particular case the answer given didn't work appropriately because of the spaces in the path, therefore i have to do it the way i didn't want to:
Files.createFile(zipLocation);
ZipOutputStream out = new ZipOutputStream(
new FileOutputStream(zipLocation.toFile()));
out.putNextEntry(new ZipEntry(""));
out.closeEntry();
out.close();
it does not mean that the given answer is wrong, it just didn't work for my particular case
As described in The Oracle Site:
public static void createZip(Path zipLocation, Path toBeAdded, String internalPath) throws Throwable {
Map<String, String> env = new HashMap<String, String>();
// check if file exists
env.put("create", String.valueOf(Files.notExists(zipLocation)));
// use a Zip filesystem URI
URI fileUri = zipLocation.toUri(); // here
URI zipUri = new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null);
System.out.println(zipUri);
// URI uri = URI.create("jar:file:"+zipLocation); // here creates the
// zip
// try with resource
try (FileSystem zipfs = FileSystems.newFileSystem(zipUri, env)) {
// Create internal path in the zipfs
Path internalTargetPath = zipfs.getPath(internalPath);
// Create parent directory
Files.createDirectories(internalTargetPath.getParent());
// copy a file into the zip file
Files.copy(toBeAdded, internalTargetPath, StandardCopyOption.REPLACE_EXISTING);
}
}
public static void main(String[] args) throws Throwable {
Path zipLocation = FileSystems.getDefault().getPath("a.zip").toAbsolutePath();
Path toBeAdded = FileSystems.getDefault().getPath("a.txt").toAbsolutePath();
createZip(zipLocation, toBeAdded, "aa/aa.txt");
}

can file.renameTo replace a existing file?

// File (or directory) to be moved
File file = new File("filename");
// Destination directory
File dir = new File("directoryname");
// Move file to new directory
boolean success = file.renameTo(new File(dir, file.getName()));
if (!success) {
// File was not successfully moved
//can it be because file with file name already exists in destination?
}
If the file with name 'filename' already exists in the destination will it be replaced with a new one?
According to Javadoc:
Many aspects of the behavior of this method are inherently platform-dependent: The rename operation might not be able to move a file from one filesystem to another, it might not be atomic, and it might not succeed if a file with the destination abstract pathname already exists. The return value should always be checked to make sure that the rename operation was successful.
From Javadoc:
The rename operation might not be able
to move a file from one filesystem to
another, it might not be atomic, and
it might not succeed if a file with
the destination abstract pathname
already exists.
I tested the following code:
It works the first time, second time it fails as expected.
To move a file you should delete or rename the destination if required.
public class Test {
public static void main(String[] args) throws IOException {
File file = new File( "c:\\filename" );
file.createNewFile();
File dir = new File( "c:\\temp" );
boolean success = file.renameTo( new File( dir, file.getName() ) );
if ( !success ) {
System.err.println( "succ:" + success );
}
}
}
As it is system dependent you should not expect it to behave this or other way. Check it and implement your own logic.

Categories