Я думаю, что нашел ошибку в java.util.zip.Deflater и его jni-материалах...
Я могу воспроизвести с помощью FileChannel.transferTo(), но не с помощью простого цикл с байтовыми буферами.
Полный код Java17 ниже.
Вы можете передать небольшой файл размером всего 100–150 байт, и проблема все равно будет видна.
Шаговое выполнение через Код дефлятора, по завершении результат вызова
result = deflateBytesBuffer(...) рядом со строкой 765 (jdk 17)
возвращает значение, биты которого сдвигаются на найдите прочитанные и записанные байты (строка 782/783). «Написанное» значение определенно неверно. Побочным эффектом является то, что дефлятор производит больше байтов, в основном повторяя часть того, что у него есть. Вот почему я использовал NO_COMPRESSION, чтобы с помощью простого короткого текстового файла можно было обнаружить повторяющийся шаблон.
Тестовый код:
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.StandardOpenOption;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
public class TestDeflaterBug2 {
static final boolean GZ = true;
public static void main(String[] args) throws IOException {
int complevel = Deflater.NO_COMPRESSION;
//int complevel = Deflater.DEFAULT_COMPRESSION;
test(args, complevel, false);
test(args, complevel, true);
}
static void test(String[] args, int complevel, boolean useTrfTo) throws IOException {
String inputFilename = args.length>0 ? args[0] : "x";
File f1 = new File(inputFilename);
if (!f1.isFile())
throw new IllegalArgumentException("input file does not exist: " + f1);
String outputFilename = inputFilename+"-L"+(complevel0) {
long len = inCh.transferTo(pos, remaining, deflChannel);
remaining -= len;
pos += len;
}
} else {
//ByteBuffer inBB = ByteBuffer.allocateDirect(8192);
ByteBuffer inBB = ByteBuffer.allocate(8192);
long lastDot = 0;
long pos = 0;
long end = inCh.size();
while(pos>> 20;
for (long d = lastDot + 1; d 2;
case Deflater.BEST_SPEED -> 4;
default -> 0;
});
workBuffer.put((byte)-1); //OS
workBuffer.flip();
while(workBuffer.hasRemaining())
out.write(workBuffer);
}
@Override
public boolean isOpen() {
return !closed;
}
@Override
public int write(ByteBuffer src) throws IOException {
if (deflater.finished())
throw new IOException("compression already finished");
int len = src.remaining();
if (len > 0) {
src.mark();
deflater.setInput(src);
while (!deflater.needsInput())
drainDeflaterOnce();
src.reset();
crc.update(src);
}
return len;
}
private void drainDeflaterOnce() throws IOException {
workBuffer.clear();
deflater.deflate(workBuffer);
workBuffer.flip();
while (workBuffer.hasRemaining()) //this is only efficient on blocking channel, else may spin fast...
out.write(workBuffer);
}
@Override
public void close() throws IOException {
if (closed)
return;
try {
finish();
} finally {
deflater.end();
out.close();
closed = true;
}
}
public void finish() throws IOException {
if (deflater.finished())
return;
deflater.finish();
while (!deflater.finished())
drainDeflaterOnce();
if(GZ)
writeFooter();
}
private void writeFooter() throws IOException {
workBuffer.clear().order(ByteOrder.LITTLE_ENDIAN);
workBuffer.putInt((int)crc.getValue());
workBuffer.putInt(deflater.getTotalIn());
workBuffer.flip();
while(workBuffer.hasRemaining())
out.write(workBuffer);
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/792 ... nel-transf
Ошибка? в Deflate из кучи ByteBuffer для направления ByteBuffer через FileChannel.transferTo() ⇐ JAVA
Программисты JAVA общаются здесь
1733369554
Anonymous
Я думаю, что нашел ошибку в java.util.zip.Deflater и его jni-материалах...
Я могу воспроизвести с помощью FileChannel.transferTo(), но не с помощью простого цикл с байтовыми буферами.
Полный код Java17 ниже.
Вы можете передать небольшой файл размером всего 100–150 байт, и проблема все равно будет видна.
Шаговое выполнение через Код дефлятора, по завершении результат вызова
result = deflateBytesBuffer(...) рядом со строкой 765 (jdk 17)
возвращает значение, биты которого сдвигаются на найдите прочитанные и записанные байты (строка 782/783). «Написанное» значение определенно неверно. Побочным эффектом является то, что дефлятор производит больше байтов, в основном повторяя часть того, что у него есть. Вот почему я использовал NO_COMPRESSION, чтобы с помощью простого короткого текстового файла можно было обнаружить повторяющийся шаблон.
Тестовый код:
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.StandardOpenOption;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
public class TestDeflaterBug2 {
static final boolean GZ = true;
public static void main(String[] args) throws IOException {
int complevel = Deflater.NO_COMPRESSION;
//int complevel = Deflater.DEFAULT_COMPRESSION;
test(args, complevel, false);
test(args, complevel, true);
}
static void test(String[] args, int complevel, boolean useTrfTo) throws IOException {
String inputFilename = args.length>0 ? args[0] : "x";
File f1 = new File(inputFilename);
if (!f1.isFile())
throw new IllegalArgumentException("input file does not exist: " + f1);
String outputFilename = inputFilename+"-L"+(complevel0) {
long len = inCh.transferTo(pos, remaining, deflChannel);
remaining -= len;
pos += len;
}
} else {
//ByteBuffer inBB = ByteBuffer.allocateDirect(8192);
ByteBuffer inBB = ByteBuffer.allocate(8192);
long lastDot = 0;
long pos = 0;
long end = inCh.size();
while(pos>> 20;
for (long d = lastDot + 1; d 2;
case Deflater.BEST_SPEED -> 4;
default -> 0;
});
workBuffer.put((byte)-1); //OS
workBuffer.flip();
while(workBuffer.hasRemaining())
out.write(workBuffer);
}
@Override
public boolean isOpen() {
return !closed;
}
@Override
public int write(ByteBuffer src) throws IOException {
if (deflater.finished())
throw new IOException("compression already finished");
int len = src.remaining();
if (len > 0) {
src.mark();
deflater.setInput(src);
while (!deflater.needsInput())
drainDeflaterOnce();
src.reset();
crc.update(src);
}
return len;
}
private void drainDeflaterOnce() throws IOException {
workBuffer.clear();
deflater.deflate(workBuffer);
workBuffer.flip();
while (workBuffer.hasRemaining()) //this is only efficient on blocking channel, else may spin fast...
out.write(workBuffer);
}
@Override
public void close() throws IOException {
if (closed)
return;
try {
finish();
} finally {
deflater.end();
out.close();
closed = true;
}
}
public void finish() throws IOException {
if (deflater.finished())
return;
deflater.finish();
while (!deflater.finished())
drainDeflaterOnce();
if(GZ)
writeFooter();
}
private void writeFooter() throws IOException {
workBuffer.clear().order(ByteOrder.LITTLE_ENDIAN);
workBuffer.putInt((int)crc.getValue());
workBuffer.putInt(deflater.getTotalIn());
workBuffer.flip();
while(workBuffer.hasRemaining())
out.write(workBuffer);
}
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79253325/bug-in-deflate-from-heap-bytebuffer-to-direct-bytebuffer-via-filechannel-transf[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия