Ошибка при чтении GZip в java, но не в python

#java #gzip

#java #gzip

Вопрос:

Я записываю некоторые данные в двоичный файл GZIP, используя приведенный ниже Java-код

     public static void WriteDictAndIndex(HashMap<String, Term> terms, int index){

        try{
            GZIPOutputStream postingListOutput = new GZIPOutputStream(new FileOutputStream(String.format("./generated/posting_list_%d", index)));
            GZIPOutputStream dictionaryOutput = new GZIPOutputStream(new FileOutputStream(String.format("./generated/dictionary_%d", index)));
            Integer START=0, SIZE=0, VOCAB=0;
            for(String s : terms.keySet()){
                ArrayList<Pair<Integer, Byte>> postingList = terms.get(s).postingList;
                SIZE = postingList.size()*5;

                // Write one posting list to the file system
                ByteBuffer list_buffer = ByteBuffer.allocate(SIZE);
                int totalCount = 0;
                for(Pair<Integer, Byte> p : postingList) {
                    // Write the docID (4 bytes)
                    list_buffer.putInt(p.getValue0()); 
                    // Write the term frequency (1 byte)
                    byte termFrequency = p.getValue1();
                    list_buffer.put(termFrequency);
                    // Counter for the total occurrences of words
                    totalCount  = (int)termFrequency;
                }
                if(index == 0 amp;amp; totalCount == 1)
                    continue;
                postingListOutput.write(list_buffer.array());

                // Write one dictionary entry to the file system
                byte[] token = s.getBytes();
                ByteBuffer dict_buffer = ByteBuffer.allocate(16 token.length);
                dict_buffer.putInt(token.length);
                dict_buffer.put(token);
                dict_buffer.putInt(terms.get(s).documentFrequency);
                dict_buffer.putInt(START);
                dict_buffer.putInt(SIZE);
                dictionaryOutput.write(dict_buffer.array());

                START  = SIZE;
                VOCAB  = 1;
            }
            //INFO
            System.out.println(String.format("Vocabulary Size: %d", VOCAB));
            postingListOutput.close();
            dictionaryOutput.close();
        }catch(IOException e){
            System.err.println(e);
        }
    }
  

Теперь, когда я читаю первые 695 байт этого файла с помощью python, он читается так, как ожидалось. Но когда я читаю файл с помощью java GZIP, есть некоторые расхождения (последние 10 байт из первых 695 байт, которые я прочитал, отличаются)

Я пытаюсь прочитать, используя следующий код:

 try{
            GZIPInputStream postingList = new GZIPInputStream(new FileInputStream(new File(args[1])));
            GZIPInputStream dictionary = new GZIPInputStream(new FileInputStream(new File(args[2])));
            byte[] buf = new byte[4];
            while(true){
                // Get the size of the token from the dictionary
                dictionary.read(buf);
                int tokenSize = ByteBuffer.wrap(buf).getInt();

                // Read the token
                byte[] tokenBuffer = new byte[tokenSize];
                dictionary.read(tokenBuffer);
                String token = new String(tokenBuffer, StandardCharsets.UTF_8);
                
                // Read the document frequency
                dictionary.read(buf);
                int documentFrequency = ByteBuffer.wrap(buf).getInt();

                // Read the starting index of the posting list
                dictionary.read(buf);
                int START = ByteBuffer.wrap(buf).getInt();

                // Read the size of the posting list
                dictionary.read(buf);
                int SIZE = ByteBuffer.wrap(buf).getInt();

                // Read the posting list
                
                for(int i=0; i<documentFrequency; i  ){
                    byte[] ID = new byte[4];
                    postingList.read(ID);
                    int docID = ByteBuffer.wrap(ID).getInt();

                    byte[] frequency = new byte[1];
                    postingList.read(frequency);
                    System.out.println(String.format("%d: %d: %d",i, docID, frequency[0]));
                }
                break;
            }
            postingList.close();
            dictionary.close();
        }
        catch(IOException e){
            System.err.println(e);
        }

  

Приведенная выше инструкция print выведет несколько строк с после чтения целого числа (4 байта) и байта в каждой строке.
Последние 2 сообщения о печати должны иметь форму (которую python отлично читает)
137: 81257: 1
138: 81737: 1
Но я получаю (используя приведенный ниже Java-код)
137: 65536: 61
138: 1761673217: 63

Какие-либо указания на то, что может быть ошибкой?

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

1. 65536 вызывает подозрение. Это точная степень 2 (например, 2 ^ 16). Поэтому я бы проверил, действительно ли вы выравниваете смещения / длины чтения и записи. На самом деле это не похоже на GZip, связанное со мной (просто удалите сжатие GZip и проверьте).

2. @GPI я записываю по 5 байт за раз в двоичный файл 139 раз. Я распечатал значение байта, и обнаруженное мной несоответствие заключается в том, что python считывает последовательность {{0 1 59 219 1} {0 1 61 105 1} } это правильно, но в java есть 2 дополнительных нуля, и я не знаю, как они туда проникли. {{0 1 59 219 1} {0 1 0 0 61 105 1}

3. Я нашел проблему. Я выделил 4 байта (предполагая, что он будет читать 4, поскольку они есть во входном потоке) при чтении, но java фактически прочитала только 2, хотя впереди были тысячи байтов. Мне просто нужно было синхронизировать чтение с выравниванием байтов.

4.Всегда всегда проверяйте значение, возвращаемое stream.read() методом :-). более новые версии Java (я думаю, 9 ) предоставляют readExactly методы, которые упрощают задачу, но у вас всегда будут угловые случаи (например, вы хотите прочитать ровно 4 байта, но осталось только 3).

5. Я имел readNBytes в виду, а не readExactly ^^