GZIPInputStream показывает неверные данные

#java #libgdx

#java #libgdx

Вопрос:

Короче говоря, проблема в том, что всякий раз, когда я добавляю GZIPInputStream и GZIPOutputStream, мои данные становятся поврежденными. Без них все работает нормально.

У меня есть следующий код:

 public boolean loadAll() {
    FileHandle file = Gdx.files.external("TinyVoxel/world_comp.lvl");
    if (!file.exists())
        return false;

    InputStream in = file.read();

    try {
        in = new GZIPInputStream(in);

        int count = in.read();
        ErrorHandler.log("Count loading grids: "   count);

        int it = 0;
        while(in.available() > 0) {
            int x = in.read();
            int y = in.read();
            int z = in.read();

            Grid grid = createGrid(x, y, z);
            grid.loadGrid(in);

            it  ;

            if (it % 10 == 0) {
                System.out.println("Loading: "   ((float)it * 100f / (float)count));
            }
        }
        in.close();
    } catch (IOException ex) {
        ErrorHandler.log("Failure saving!");
    }

    return true;
}
  

Если я удаляю GZIPInputStream и не сжимаю исходные данные с помощью GZIPOutputStream (см. Ниже, Я удаляю GZIPOutputStream), все работает отлично.

 public void saveAll() {
    Iterator<ObjectMap.Entry<List<Integer>, Grid>> it = terrainMap.entries().iterator();
    int count = 0;
    OutputStream out = Gdx.files.external("TinyVoxel/world_comp.lvl").write(false);

    try {
        out = new GZIPOutputStream(out);

        out.write(terrainMap.size);
        ErrorHandler.log("Count writing grids: "   terrainMap.size);

        while (it.hasNext()) {
            ObjectMap.Entry<List<Integer>, Grid> entry = it.next();
            List<Integer> pos = entry.key;
            final Grid grid = entry.value;
            grid.saveGrid(out);

            if (count % 10 == 0)
                System.out.println("Saving: "   ((float)count * 100f / (float) terrainMap.size));

            count  ;
        }

        out.close();
    } catch (IOException ex) {
        ErrorHandler.log("Failure saving!");
    }

    ErrorHandler.log("Complete saving!");
}
  

Примечательно, что я сохраняю и загружаю байты в grid.loadGrid и grid.saveGrid. Это может быть вызвано этими операциями, но почему он отлично работает с обычными потоками вывода и ввода?

Редактировать

Кроме того, код для функций grid.loadGrid и grid.saveGrid — части, которые имеют значение, по крайней мере.

 public boolean loadGrid(InputStream in) throws IOException {
    int count = in.read();

    palettesTotal = 0;
    for (int gx = 0; gx < Config.GRID_SIZE_X; gx  )
        for (int gy = 0; gy < Config.GRID_SIZE_Y; gy  )
            for (int gz = 0; gz < Config.GRID_SIZE_Z; gz  ) {
                grids[gx][gy][gz] = (byte)0xff;
            }

    for (int i = 0; i < count; i  ) {

        int gx = in.read();
        int gy = in.read();
        int gz = in.read();

        grids[gx][gy][gz] = (byte) (palettesTotal amp; 0xff);

        palettesTotal  ;

        byte[] buff = new byte[Config.TINY_GRID_SIZE * 2];
        TinyGridContainer tinyGrid = bytePool.obtain();
        for (int ty = 0; ty < Config.TINY_GRID_SIZE; ty  )
            for (int tz = 0; tz < Config.TINY_GRID_SIZE; tz  ) {
                in.read(buff, 0, buff.length);
                for (int tx = 0; tx < Config.TINY_GRID_SIZE; tx  ) {
                    tinyGrid.grid[tx][ty][tz] = (short) ((buff[tx * 2] >> 2) amp; 0xff   buff[tx * 2   1] amp; 0xff);
                }
            }

        tinyGrids.put(Position.create(gx, gy, gz), tinyGrid);
    }
    ....
}

public void saveGrid(OutputStream out) throws IOException {
    out.write(x);
    out.write(y);
    out.write(z);

    out.write(palettesTotal);

    for (int gx = 0; gx < Config.GRID_SIZE_X; gx  )
       for (int gy = 0; gy < Config.GRID_SIZE_Y; gy  )
           for (int gz = 0; gz < Config.GRID_SIZE_Z; gz  ) {
               if (grids[gx][gy][gz] != (byte) 0xff) {
                   // add tiny grid to pixmap
                   List<Integer> pos = Position.create(gx, gy, gz);
                   TinyGridContainer tinyGrid = tinyGrids.get(pos);

                   out.write(gx);
                   out.write(gy);
                   out.write(gz);

                   Position.free(pos);

                   byte[] buff = new byte[Config.TINY_GRID_SIZE * 2];
                   for (int ty = 0; ty < Config.TINY_GRID_SIZE; ty  )
                       for (int tz = 0; tz < Config.TINY_GRID_SIZE; tz  ) {
                           for (int tx = 0; tx < Config.TINY_GRID_SIZE; tx  ) {
                               buff[tx*2] = (byte)((tinyGrid.grid[tx][ty][tz] >> 2) amp; 0xff);
                               buff[tx*2 1] = (byte)(tinyGrid.grid[tx][ty][tz] amp; 0xff);
                           }
                           out.write(buff, 0, buff.length);
                       }
               }
           }
   }
  

Комментарии:

1. Не могли бы вы, пожалуйста, показать код этих двух функций?

2. Я добавил две функции; loadGrid и saveGrid.

3. Будьте осторожны с методом чтения , который принимает буфер в качестве параметра. Он возвращает количество прочитанных байтов, которое не обязательно соответствует размеру буфера.

4. Спасибо, это исправлено, мистер Смит.

5. Пожалуйста. Как вы можете видеть, API сложный. Еще одно предостережение, которое вы, вероятно, знаете, заключается read в том, что метод, который возвращает int, фактически возвращает один байт, заключенный в int. Наконец, попробуйте закрыть ресурсы в предложениях finally или используйте Java 8 try-with-resources

Ответ №1:

Комментарий мистера Смита направил меня в правильном направлении.

         byte[] buff = new byte[Config.TINY_GRID_SIZE * 2];
        TinyGridContainer tinyGrid = bytePool.obtain();
        for (int ty = 0; ty < Config.TINY_GRID_SIZE; ty  )
            for (int tz = 0; tz < Config.TINY_GRID_SIZE; tz  ) {
                int cnt = 0;
                for (int tx = 0; tx < Config.TINY_GRID_SIZE; tx  ) {
                    int id = tx * 2;

                    if (cnt <= id) {
                        cnt  = in.read(buff, cnt, buff.length - cnt);
                    }

                    tinyGrid.grid[tx][ty][tz] = (short) ((buff[id] >> 2) amp; 0xff);

                    id  ;
                    if (cnt <= id) {
                        cnt  = in.read(buff, cnt, buff.length - cnt);
                    }

                    tinyGrid.grid[tx][ty][tz]  = (short) (buff[id] amp; 0xff);
                }
            }
  

Комментарии:

1. Возможно, вам пригодится метод IOUtils. прочитайте в Apache Commons. Он блокируется до тех пор, пока буфер не будет полностью прочитан.