#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
^^