Какие проблемы могут возникнуть с функциями zip и unzip при работе со строками
Что проверяют
Понимаете ли вы, что строка и сжатые байты это разные сущности, а граница между ними проходит через кодировку. Следом обычно просят показать, как сжать строку и сохранить результат в текстовое поле базы или в JSON.
Как отвечать
Сначала уточните, о каком zip речь. Чаще имеют в виду сжатие через java.util.zip, и тогда проблемы такие:
- кодировка на входе:
getBytes()без аргумента берёт кодировку по умолчанию. С Java 18 это везде UTF-8, но на старых JDK результат зависит от машины. Пишите явноgetBytes(StandardCharsets.UTF_8)и так жеnew String(bytes, UTF_8)на обратном пути; - сжатые байты не текст:
new String(compressed)портит данные, некорректные последовательности заменяются наU+FFFD, и распаковать это уже нельзя. Для хранения в строке нуженBase64; - короткие строки растут: у GZIP заголовок и хвост занимают около 18 байт, а Base64 добавляет ещё треть. Строку в сто символов сжимать бессмысленно;
- нативная память:
DeflaterиInflaterработают через zlib вне кучи. Безend()или закрытия потока-обёртки эта память держится до сборки мусора; - недоверенный вход: распаковка без лимита на размер результата открывает дорогу zip-бомбе. Читайте кусками и обрывайте на пороге;
- архивы:
ZipInputStreamпо умолчанию ждёт имена в UTF-8, архив из старого Windows-архиватора падает сMALFORMED, помогает конструктор сCharset. Имена вида../../etcбез проверки черезnormalize()иstartsWith()дают Zip Slip.
Если имелось в виду попарное объединение последовательностей, то в Stream API такого метода нет, а в Kotlin zip молча обрезает результат по более короткой стороне.
Где спотыкаются
Гоняют сжатые данные через String «для удобства», а потом ищут, почему Inflater бросает DataFormatException.
Сжимают всё подряд и не замечают, что на коротких значениях объём растёт, а процессор тратится впустую.
Распаковывают пользовательский файл целиком в память через readAllBytes() и получают OutOfMemoryError на архиве в пару мегабайт.