оценка размера файла на диске при использовании ObjectOutputStream

Я пытаюсь записать свои пространственные данные из таблицы в файл. Но мне нужно знать точный размер данных на диске перед записью на диск. В качестве примера предположим, что я пишу на диск, используя следующий код:

    FileOutputStream fos = new FileOutputStream("t.tmp",false);
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeInt(gid);
    oos.writeUTF(fullname);
    oos.writeInt(d.shape.length);
    oos.write(d.shape);

    oos.close();
    fos.close();

Я думал, что размер файла на диске равен:

size= 4B {for gid, int} + fullname.getBytes.length() {string} + 4B {d.shape.length, int} + d.shape.length

но на самом деле это сильно отличается от реального размера файла на диске.

Я также заметил, что даже создание пустого файла с помощью ObjectOutputstream приводит к 4 байтам места на диске.

Любая помощь в том, как рассчитать размер файла на диске?

(Я не могу записать данные на диск, а затем прочитать реальный размер. Это снизит производительность. Вместо этого мне нужно рассчитать размер данных на диске на основе значений данных, хранящихся в памяти.)


person reza    schedule 26.06.2012    source источник
comment
Кроме того, можете ли вы рассказать о проблеме с производительностью, которую вы ощущаете при использовании файловой системы после записи байтов?   -  person Greg Kopff    schedule 26.06.2012
comment
с точки зрения проблемы с производительностью. У меня есть 40 ГБ данных в моей таблице, и многие из них являются пространственными данными. Я разделяю свою таблицу таким образом, чтобы общий размер данных, хранящихся в каждом файле, был меньше определенного значения (max_file_size). В первом раунде я вычисляю размер на диске каждой строки моей таблицы, а в следующих раундах я суммирую столько из них, сколько может поместиться в файл с общим размером файла меньше, чем max_file_size. Таким образом, запись каждого файла, а затем измерение реального размера файла на диске невозможна.   -  person reza    schedule 26.06.2012
comment
с точки зрения использования ObjectOutputStream, я не уверен, что это лучший способ записи на диск. У меня есть несколько полей для ввода varchar(x) в дополнение к геометрии, которая представляет собой массив байтов переменной длины. Я думал, что ObjectOutputStream будет самым простым способом чтения/записи в файл. На самом деле, до сих пор это работало нормально. Единственная проблема заключается в том, что я должен заранее рассчитать размер на диске на основе значений данных. Любое предложение?   -  person reza    schedule 26.06.2012
comment
Полезность ObjectOutputStream заключается в его способности автоматически сериализовать сложный граф объектов. Однако это не похоже на то, что вы делаете, поэтому я бы посоветовал вам отказаться от ObjectOutputStream и просто написать байты самостоятельно, используя DataOutputStream. DataOutputStream ничего не делает автоматически, так что вы сможете выполнять расчеты размера, которые ожидаете. Обратите внимание на Javadoc для DataOutputStream.writeUTF(), так как он записывает 2 байта данных длины, а затем String.   -  person Greg Kopff    schedule 26.06.2012
comment
@reza, если у вас 40 ГБ данных, я сомневаюсь, что ObjectOutputStream — лучший выбор. Он разработан, чтобы быть универсальным, простым и гибким, но не компактным и не очень эффективным. Если вам нужно знать размер заранее, вам гораздо лучше использовать собственный формат диска, если емкость является проблемой. Зачем вообще нужно знать размер?   -  person Peter Lawrey    schedule 26.06.2012


Ответы (2)


Предполагая, что вы не возражаете тратить немного памяти, вы можете сначала записать все это в ByteArrayOutputStream, а затем получить размер.

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(boas);
oos.writeInt(gid);
oos.writeUTF(fullname);
oos.writeInt(d.shape.length);
oos.write(d.shape);

oos.close();
boas.close();
int size = boas.size();
person wolfcastle    schedule 26.06.2012
comment
отличный. это отлично работает, если я хочу рассчитать размер одной строки данных. Я вычисляю это для каждой строки данных и сохраняю в своей таблице в столбце block_size. Затем я выбираю столько строк, чтобы их совокупный размер блока был меньше определенного значения. Проблема в том, что сумма значений block_size двух строк больше, чем размер файла двух строк, записанных на диск. Любая идея о том, как решить эту часть? - person reza; 26.06.2012
comment
@reza Если вам нужно, чтобы это было точно, вы должны сначала сериализовать всю структуру данных в памяти (или во временный файл). Сериализация Java удалит повторяющиеся объекты и строки до такой степени, что вы не можете предположить, что удвоение данных займет дважды столько же места. - person Peter Lawrey; 26.06.2012
comment
спасибо, в итоге я использовал DataOutputStream. Таким образом, мой расчетный размер точно соответствует размеру файла на диске. спасибо за предложения. - person reza; 26.06.2012

Я пытаюсь записать свои пространственные данные из таблицы в файл. Но мне нужно знать точный размер данных на диске перед записью на диск.

Вы не должны использовать ObjectOutputStream. ObjectOutputStream может автоматически сериализовать для вас сложный граф объектов, но это не является одним из ваших требований. Как часть этой сериализации, ObjectOutputStream записывает некоторую информацию заголовка потока (это 4 байта, которые вы обнаружили в начале), а также отслеживает объекты, записанные ранее, чтобы он мог записывать значения специальных маркеров, а не записывать весь объект снова. .

Вместо этого просто используйте DataOutputStream. Он обеспечивает ту же функциональность, которую вы хотите:

Поток вывода данных позволяет приложению записывать примитивные типы данных Java в поток вывода переносимым способом. Затем приложение может использовать поток ввода данных для обратного чтения данных.

FileOutputStream fos = new FileOutputStream("t.tmp",false);
DataOutputStream dos = new DataOutputStream(fos);
dos.writeInt(gid);                 // write 4 bytes
dos.writeUTF(fullname);            // write 2 bytes of length, then variable length string (UTF encoded)
dos.writeInt(d.shape.length);      // write 4 bytes
dos.write(d.shape);                // write a variable length byte array

dos.close();
fos.close();

Здесь не будет никаких сюрпризов (при условии, что вы знаете, сколько байтов получит ваша строка в кодировке UTF), и вы можете выполнить арифметические действия, чтобы вычислить точный размер файла.

(Если вы имели дело со строками, которые не просто равнялись одному символу и одному байту, вы могли бы сначала преобразовать строку в массив байтов, используя кодировщик набора символов).

person Greg Kopff    schedule 26.06.2012
comment
большое спасибо. это решило проблему. Кажется, мне нужно освежить память о потоках Java. Вы рекомендуете какой-либо учебник по потокам Java? - person reza; 26.06.2012