jodd-core/src/main/java/jodd/io/ZipUtil.java
public static void addToZip(final ZipOutputStream zos, final File file, String path, final String comment, final boolean recursive) throws IOException {
		if (!file.exists()) {
			throw new FileNotFoundException(file.toString());
		}

		if (path == null) {
			path = file.getName();
		}

		while (path.length() != 0 && path.charAt(0) == '/') {
			path = path.substring(1);
		}

		boolean isDir = file.isDirectory();

		if (isDir) {
			// add folder record
			if (!StringUtil.endsWithChar(path, '/')) {
				path += '/';
			}
		}

		ZipEntry zipEntry = new ZipEntry(path);
		zipEntry.setTime(file.lastModified());

		if (comment != null) {
			zipEntry.setComment(comment);
		}

		if (isDir) {
			zipEntry.setSize(0);
			zipEntry.setCrc(0);
		}

		zos.putNextEntry(zipEntry);

		if (!isDir) {
			InputStream is = new FileInputStream(file);
			try {
				StreamUtil.copy(is, zos);
			} finally {
				StreamUtil.close(is);
			}
		}

		zos.closeEntry();

		// continue adding

		if (recursive && file.isDirectory()) {
			boolean noRelativePath = StringUtil.isEmpty(path);

			final File[] children = file.listFiles();

			if (children != null && children.length != 0) {
				for (File child : children) {
					String childRelativePath = (noRelativePath ? StringPool.EMPTY : path) + child.getName();
					addToZip(zos, child, childRelativePath, comment, recursive);
				}
			}
		}

	}
public static void addToZip(final ZipOutputStream zos, final File file, String path, final String comment, final boolean recursive) throws IOException {
		if (!file.exists()) {
			throw new FileNotFoundException(file.toString());
		}

		if (path == null) {
			path = file.getName();
		}

		while (path.length() != 0 && path.charAt(0) == '/') {
			path = path.substring(1);
		}

		boolean isDir = file.isDirectory();

		if (isDir) {
			// add folder record
			if (!StringUtil.endsWithChar(path, '/')) {
				path += '/';
			}
		}

		ZipEntry zipEntry = new ZipEntry(path);
		zipEntry.setTime(file.lastModified());

		if (comment != null) {
			zipEntry.setComment(comment);
		}

		if (isDir) {
			zipEntry.setSize(0);
			zipEntry.setCrc(0);
		}

		zos.putNextEntry(zipEntry);

		if (!isDir) {
			InputStream is = new FileInputStream(file);
			try {
				StreamUtil.copy(is, zos);
			} finally {
				StreamUtil.close(is);
			}
		}

		zos.closeEntry();

		// continue adding

		if (recursive && file.isDirectory()) {
			boolean noRelativePath = StringUtil.isEmpty(path);

			final File[] children = file.listFiles();

			if (children != null && children.length != 0) {
				for (File child : children) {
					String childRelativePath = (noRelativePath ? StringPool.EMPTY : path) + child.getName();
					addToZip(zos, child, childRelativePath, comment, recursive);
				}
			}
		}

	}
Adds single entry to ZIP output stream.

@param zos zip output stream
@param file file or folder to add
@param path relative path of file entry; if <code>null</code> files name will be used instead
@param comment optional comment
@param recursive when set to <code>true</code> content of added folders will be added, too