чтение / запись в файл большого размера в Java - PullRequest
8 голосов
/ 01 апреля 2011

У меня есть двоичный файл в следующем формате:

[N bytes identifier & record length] [n1 bytes data] 
[N bytes identifier & record length] [n2 bytes data] 
[N bytes identifier & record length] [n3 bytes data]

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

этот файл очень большой и может содержать 3 миллиона записей.

Я хочу открыть этот файл приложением и позволить пользователю просматривать и редактировать записи.(Вставить / Обновить / Удалить записи)

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

  • есть ли библиотека (библиотека java), чтобы помочь мне реализовать это требование?

  • какие-либо рекомендации или опыт, которые вы считаете полезными?

----------------- РЕДАКТИРОВАТЬ ----------------------------------------------

Спасибо за руководства и предложения,

Дополнительная информация:

Исходный файл и его формат находятся вне моего контроля (это файл стороннего производителя), и я не могу изменить формат файла.но я должен прочитать его, позволить пользователю перемещаться по записям и редактировать некоторые из них (вставить новую запись / обновить существующую запись / удалить запись) и в конце сохранить ее обратно в исходный формат файла .

Вы все еще рекомендует базу данных вместо обычного индексного файла?

----------------- ВТОРОЕ РЕДАКТИРОВАНИЕ ----------------------------------------------

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

Большое спасибо

Ответы [ 6 ]

2 голосов
/ 01 апреля 2011

Наличие файла данных и индексного файла было бы основной базовой идеей для такой реализации, но вы наверняка столкнетесь с фрагментацией данных при повторном обновлении / удалении данных и т. Д. Этот вид проекта сам по себе, должен быть отдельным проектом и не должен быть частью вашего основного приложения.Однако, по сути, база данных - это то, что вам нужно, так как она специально разработана для таких операций и вариантов использования, а также позволит вам искать, сортировать и расширять (изменять) вашу структуру данных без необходимости рефакторинга собственной (пользовательской)решение.

Могу ли я предложить вам загрузить Apache Derby и создать локальную встроенную базу данных (derby делает это, если вы хотите создать новое встроенное соединение во время выполнения).Это будет не только быстрее, чем все, что вы будете писать самостоятельно, но и облегчит поддержку вашего приложения.

Apache Derby - это отдельный файл JAR, который вы можете просто включить и распространить вместе с вашим проектом (отметьте лицензия , если в вашем приложении может возникнуть какая-либо юридическая проблема).Нет необходимости в сервере базы данных или стороннем программном обеспечении;все это чисто Java.

Суть в том, что все зависит от того, насколько велико ваше приложение, нужно ли вам обмениваться данными между многими клиентами, если скорость является критическим аспектом вашего приложения и т. д.

Для автономного однопользовательского проекта я рекомендую Apache Derby.Для n-ярусного приложения вам может понадобиться MySQL , PostgreSQL или ( hrm ) даже Oracle .Использование уже созданных и протестированных решений не только разумно, но и сократит ваше время разработки (и усилия по обслуживанию).

Cheers.

2 голосов
/ 01 апреля 2011

Серьезно, вы НЕ должны использовать двоичный файл для этого.Вам следует использовать базу данных.

Проблемы с попыткой реализовать это как обычный файл проистекают из того факта, что операционные системы не позволяют вставлять дополнительные байты в середину существующего файла.Поэтому, если вам нужно вставить запись (в любом месте, кроме конца), обновить запись (с другим размером) или удалить запись, вам необходимо:

  • переписать другие записи (после вставки/ update / delete point), чтобы освободить или освободить место, или
  • реализовать какое-либо управление свободным пространством в файле.

Все это сложно и / или дорого.

К счастью, существует класс программного обеспечения, который реализует подобные вещи.Это называется программным обеспечением базы данных.Существует широкий спектр вариантов, начиная от использования полномасштабной СУБД до легких решений, таких как файлы BerkeleyDB.


В ответ на ваши 1-е и 2-е правки база данных будет по-прежнему проще.

Однако есть альтернатива, что может работать лучше для этого варианта использования , чем при использовании БД ... без сложного управления свободным пространством.

  1. Считайте файл и создайте индекс в памяти , который сопоставляет идентификаторы с местоположениями файлов.

  2. Создайте второй файл для храненияновые и обновленные записи.

  3. Выполнение записи добавляет / обновляет / удаляет:

    1. Добавление обрабатывается путем записи новой записи в конецвторого файла и добавление для него записи индекса.

    2. Обновление обрабатывается путем записи обновленной записи в конец второго файла и изменения существующей записи индекса в точкук нему.

    3. Удаление обрабатывается deletдобавление записи индекса для ключа записи.

  4. Упакуйте файл следующим образом:

    1. Создайте новый файл.

    2. Считайте каждую запись в старом файле по порядку и проверьте индекс для ключа записи.Если запись по-прежнему указывает на местоположение записи, скопируйте запись в новый файл.В противном случае пропустите его.

    3. Повторите шаг 4.2 для второго файла.

  5. Если мы выполнили все вышеперечисленноеуспешно удалите старый файл и второй файл.

Обратите внимание, что это зависит от возможности сохранить индекс в памяти.Если это невозможно, то реализация будет более сложной ... и больше похожа на базу данных.

1 голос
/ 01 апреля 2011

Как правило, вам лучше позволить библиотеке или базе данных сделать всю работу за вас.

Возможно, вы не захотите иметь базу данных SQL, и существует множество простых баз данных, которые не используют SQL.http://nosql -database.org / перечисляет 122 из них.

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


В зависимости от размера записей, 3 миллиона не так много, и я бы посоветовал вам сохранить в памяти как можно больше.

Проблема, с которой вы сталкиваетесьскорее всего, это обеспечит согласованность данных и восстановление данных в случае повреждения.Вторая проблема - это эффективная работа с фрагментацией (с этим сталкиваются самые яркие умы, работающие с GC). Третья проблема, вероятно, заключается в том, чтобы поддерживать индекс в режиме транзакций с исходными данными, чтобы гарантировать отсутствие несоответствий.1014 * Поначалу это может показаться простым, но есть значительные сложности в обеспечении того, чтобы данные были надежными, поддерживаемыми и к ним можно было эффективно обращаться.Вот почему большинство разработчиков используют существующую библиотеку базы данных / хранилища данных и концентрируются на функциях, не связанных с их приложением.

0 голосов
/ 02 апреля 2011

Как утверждают другие, база данных может показаться лучшим решением. Следующие базы данных Java SQL могут быть использованы: H2 , Derby или HSQLDB

Если вы хотите использовать индексный файл, посмотрите на Berkley DB или Нет Sql

Если есть какая-то причина для использования файла, посмотрите JRecord . Имеет

  1. Несколько классов для чтения / записи файлов с двоичными записями переменной длины (они были записаны для файлов Cobol VB). Любая структура файлов Mainframe / Fujitsu / Open Cobol VB должна выполнять эту работу.
  2. Редактор для редактирования JRecord файлов. Последняя версия редактора может обрабатывать большие файлы (он использует сжатие / разлив файла). Редактор страдает от необходимости загрузки всего файла, и только один пользователь может редактировать файл одновременно.

Решение JRecord будет работать, только если

  • Существует ограниченное количество (предпочтительно один) пользователей, все они находятся в одном месте
  • Быстрая инфоструктура
0 голосов
/ 01 апреля 2011

Вставить / Обновить / Удалить записи

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

Формат файла, который вы предлагаете, принципиально не подходит для тех операций, которые вы хотите выполнить. Другие предложили использовать базу данных. Если вы не хотите заходить так далеко, добавьте индексный файл (как вы предлагаете). Я рекомендую делать индексные записи одинаковой длины.

0 голосов
/ 01 апреля 2011

(Примечание: мой ответ касается проблемы в целом, не учитывая какие-либо библиотеки Java или - как и другие предложенные ответы - используя базу данных (библиотеку), что может быть лучше, чем изобретать колесо)

* 1002Идея создания индекса хороша и будет очень полезна с точки зрения производительности (хотя вы написали «индексный файл», я думаю, он должен храниться в памяти).Генерирование индекса должно быть достаточно быстрым, если вы читаете идентификатор и длину записи для каждой записи, а затем просто пропускаете данные при поиске файла.

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

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

...