Skip to content

Commit

Permalink
#72 Add documentation for rename file and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
srikanth-lingala committed Mar 1, 2020
1 parent ac5e326 commit 71ad155
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 5 deletions.
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,67 @@ if (fileHeader == null) {
zipFile.removeFile(fileHeader);
~~~~

### Rename entries in the zip file

There are three ways to rename an entry in a zip file with zip4j. One way is to pass in a file header and the new file
name:

~~~~
ZipFile zipFile = new ZipFile("sample.zip");
FileHeader fileHeader = zipFile.getFileHeader("entry-to-be-changed.pdf");
zipFile.renameFile(fileHeader, "new-file-name.pdf");
~~~~

Second way is to pass in just the file name to be changed (instead of the file header), and the new file name.

~~~~
new ZipFile("filename.zip").renameFile("entry-to-be-changed.pdf", "new-file-name.pdf");
~~~~

It is also possible to change multiple file names at once. In this case you have to use a map, with the key of the entry
in the map being the entry to be changed, and the value of the map being the new file name:

~~~~
Map<String, String> fileNamesMap = new HashMap<>();
fileNamesMap.put("firstFile.txt", "newFileFirst.txt");
fileNamesMap.put("secondFile.pdf", "newSecondFile.pdf");
fileNamesMap.put("some-folder/thirdFile.bin", "some-folder/newThirdFile.bin");
new ZipFile("filename.zip").renameFile("entry-to-be-changed.pdf", "new-file-name.pdf");
~~~~

To modify an entry name which is inside a folder, the new file name should contain the complete parent path as well.
For example, if an entry by the name `some-entry.pdf` is in the folder `some-folder/some-sub-folder/`, to modify this
entry name to `some-new-entry.pdf`:

~~~~
new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "some-folder/some-sub-folder/new-entry.pdf");
~~~~

if the parent path path is missing, then the file will be put at the root of the zip file. In the below example, after
the file is renamed, `some-new-entry.pdf` will exist at the root of the zip file instead of at `some-folder/some-sub-folder/`:

~~~~
new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "some-new-entry.pdf");
~~~~

This also gives the flexibility to "move" the entry to a different folder. The below example will move the
`some-entry.pdf` from `some-folder/some-sub-folder/` to `folder-to-be-moved-to/sub-folder/` and the file will also be
renamed to `new-entry.pdf`. To just move the file, use the same file name instead of a new file name.

~~~~
new ZipFile("filename.zip").renameFile("some-folder/some-sub-folder/some-entry.pdf", "folder-to-be-moved-to/sub-folder/new-entry.pdf");
~~~~

If the entry being modified is a directory, all entries that are part of that directory will be renamed so that all of
them have the new folder name as parent. In zip format, all entry names under a directory will contain the full name as their file name.
For example if there is an entry by the name `filename.txt` inside a directory `directoryName`, the file name for the entry
will be `directoryName/filename.txt`. And if the name of the directory has now been changed to `newDirectoryName`, the
entry under it will also be changed to `newDirectoryName/filename.txt`, so the when the zip file is extracted,
`filename.txt` will be under `newDirectoryName`.

Zip file format does not allow modifying split zip files, and zip4j will throw an exception if an attempt is made to
rename files in a split zip file.

### Merging split zip files into a single zip

This is the reverse of creating a split zip file, that is, this feature will merge a zip file which is split across
Expand Down
44 changes: 40 additions & 4 deletions src/main/java/net/lingala/zip4j/ZipFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -693,10 +693,17 @@ public void removeFile(FileHeader fileHeader) throws ZipException {
}

/**
* Renames the current entry
* @param fileHeader
* @param newFileName
* @throws ZipException
* Renames file name of the entry represented by file header. If the file name in the input file header does not
* match any entry in the zip file, the zip file will not be modified.
*
* If the file header is a folder in the zip file, all sub-files and sub-folders in the zip file will also be renamed.
*
* Zip file format does not allow modifying a split zip file. Therefore if the zip file being dealt with is a split
* zip file, this method throws an exception
*
* @param fileHeader file header to be changed
* @param newFileName the file name that has to be changed to
* @throws ZipException if fileHeader is null or newFileName is null or empty or if the zip file is a split file
*/
public void renameFile(FileHeader fileHeader, String newFileName) throws ZipException {
if (fileHeader == null) {
Expand All @@ -706,6 +713,22 @@ public void renameFile(FileHeader fileHeader, String newFileName) throws ZipExce
renameFile(fileHeader.getFileName(), newFileName);
}

/**
* Renames file name of the entry represented by input fileNameToRename. If there is no entry in the zip file matching
* the file name as in fileNameToRename, the zip file will not be modified.
*
* If the entry with fileNameToRename is a folder in the zip file, all sub-files and sub-folders in the zip file will
* also be renamed. For a folder, the fileNameToRename has to end with zip file separator "/". For example, if a
* folder name "some-folder-name" has to be modified to "new-folder-name", then value of fileNameToRename should be
* "some-folder-name/". If newFileName does not end with a separator, zip4j will add a separator.
*
* Zip file format does not allow modifying a split zip file. Therefore if the zip file being dealt with is a split
* zip file, this method throws an exception
*
* @param fileNameToRename file name in the zip that has to be renamed
* @param newFileName the file name that has to be changed to
* @throws ZipException if fileNameToRename is empty or newFileName is empty or if the zip file is a split file
*/
public void renameFile(String fileNameToRename, String newFileName) throws ZipException {
if (!Zip4jUtil.isStringNotNullAndNotEmpty(fileNameToRename)) {
throw new ZipException("file name to be changed is null or empty");
Expand All @@ -718,6 +741,19 @@ public void renameFile(String fileNameToRename, String newFileName) throws ZipEx
renameFiles(Collections.singletonMap(fileNameToRename, newFileName));
}

/**
* Renames all the entries in the zip file that match the keys in the map to their corresponding values in the map. If
* there are no entries matching any of the keys from the map, the zip file is not modified.
*
* If any of the entry in the map represents a folder, all files and folders will be renamed so that their parent
* represents the renamed folder.
*
* Zip file format does not allow modifying a split zip file. Therefore if the zip file being dealt with is a split
* zip file, this method throws an exception
*
* @param fileNamesMap map of file names that have to be changed with values in the map being the name to be changed to
* @throws ZipException if map is null or if the zip file is a split file
*/
public void renameFiles(Map<String, String> fileNamesMap) throws ZipException {
if (fileNamesMap == null) {
throw new ZipException("fileNamesMap is null");
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/net/lingala/zip4j/tasks/RenameFileTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ public RenameFileTask(ZipModel zipModel, HeaderWriter headerWriter, RawIO rawIO,

@Override
protected void executeTask(RenameFileTaskParameters taskParameters, ProgressMonitor progressMonitor) throws IOException {
File temporaryFile = getTemporaryFile(zipModel.getZipFile().getPath());
Map<String, String> fileNamesMap = filterNonExistingEntriesAndAddSeparatorIfNeeded(taskParameters.fileNamesMap);
if (fileNamesMap.size() == 0) {
return;
}

File temporaryFile = getTemporaryFile(zipModel.getZipFile().getPath());
try(RandomAccessFile inputStream = new RandomAccessFile(zipModel.getZipFile(), RandomAccessFileMode.WRITE.getValue());
OutputStream outputStream = new FileOutputStream(temporaryFile)) {

Expand Down
17 changes: 17 additions & 0 deletions src/test/java/net/lingala/zip4j/RenameFilesInZipIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.io.File;
import java.io.IOException;
Expand All @@ -26,6 +28,21 @@

public class RenameFilesInZipIT extends AbstractIT {

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void testRenameSplitZipFileThrowsException() throws IOException {
ZipFile zipFile = new ZipFile(generatedZipFile);
zipFile.createSplitZipFile(Collections.singletonList(getTestFileFromResources("file_PDF_1MB.pdf")),
new ZipParameters(), true, InternalZipConstants.MIN_SPLIT_LENGTH);

expectedException.expect(ZipException.class);
expectedException.expectMessage("Zip file format does not allow updating split/spanned files");

zipFile.renameFile("file_PDF_1MB.pdf", "some_name.pdf");
}

@Test
public void testRenameWithFileHeaderRenamesSuccessfully() throws IOException {
ZipFile zipFile = createDefaultZipFile();
Expand Down

0 comments on commit 71ad155

Please sign in to comment.