Запись манипуляций в плоских файлах в Java - PullRequest
3 голосов
/ 06 января 2012

Это мой первый пост здесь, в StackOverflow. Я не новичок в Java, но я не эксперт и не профессиональный программист. Уже давно у меня в голове были некоторые идеи, и я не знаю, как их правильно реализовать.

В общем, я пишу программное обеспечение (на самом деле много отдельных приложений) для управления списком вещей (скажем, списком телефонных номеров). Мое приложение должно содержаться в одном файле (jar) или папке / каталоге. Это должно быть приложение «Удалить из коробки и нажать и запустить». Создание графического интерфейса в Java не является проблемой.

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

В настоящее время мне приходят в голову 2 типичные идеи для CRUDing (CRUD = Создать, Читать, Удалить, Удалить) данные в файле. Они заключаются в следующем: -

1 Не использовать коллекцию.

  • создать - добавить запись в файл
  • чтение - чтение полного файла
  • update - скопировать все записи в новый файл, за исключением того, который требуется заменить, скопировать новые данные; удалить старый файл; переименовать новый файл в старый файл
  • delete - скопировать все записи в новый файл, кроме того, который необходимо удалить; удалить старый файл; переименуйте новый файл в старый файл.
  • Преимущество : Меньше требований к памяти.
  • Недостаток : много файловых операций ввода-вывода.

2 Использовать коллекцию

  • Запуск приложения - загрузить все записи в коллекцию из файла
  • Приложение Stop - сохранить все записи из коллекции в файл
  • создать - добавить запись в коллекцию
  • читать - читать все элементы коллекции
  • update - обновить запись прямо в коллекции
  • удалить - удалить запись из коллекции
  • Преимущество : очень меньше файлового ввода-вывода.
  • Недостаток : большие требования к памяти. Приложение завершается сбоем, если при загрузке всех записей не осталось памяти.

Оба метода имеют свои плюсы и минусы. Есть ли другой способ? Или есть ли путь между этими двумя способами? Мне отчаянно нужно какое-то руководство здесь. Занимался этой проблемой очень давно. Любые теории, предложения или указатели приветствуются!


Будет ли приемлем следующий подход? Будет ли это вредно или плохо в любом случае? Я имею в виду, что будет его недостатком?

Примечание: r -> Запись. Каждая запись находится на новой строке. Поля в каждой записи разделены некоторым разделителем, скажем, «::». Поэтому я бы использовал BufferedReader, чтобы легко получить каждую строку. Размеры только гипотетические или просто для того, чтобы дать вам картину.

Файл = {r1 r2 r3 r4 r5 ... r500} // файл имеет 500 записей
Collection cPrev, cCurrent, cNext // 3 объекта коллекции, содержащих последовательные записи; каждый холдинг (скажем) 30 записей

Итак, в начале
cPrev = {}
cCurrent = {r1 r2 r3 ... r30} // заполнен основным потоком
cNext = {r31 r32 r33 ... r60} // заполняется дочерним потоком при просмотре пользователем cCurrent

cCurrent доступен для просмотра пользователем. Пользователь может прокручивать вверх и вниз (или в любом направлении) и просматривать все 30 записей. Теперь пользователь хочет увидеть следующий набор записей. Так
cPrev = cCurrent // основной поток
cCurrent = cNext // основной поток
Поэтому
cPrev = {r1 r2 r3 ... r30}
cCurrent = {r31 r32 r33 ... r60}
cNext = {r61 r62 r63 ... r90} // заполняется дочерним потоком при просмотре пользователем cCurrent

Рассмотрим следующее состояние
cPrev = {r121 r121 r123 ... r150}
cCurrent = {r151 r152 r153 ... r180}
cNext = {r181 r182 r183 ... r210}

Если пользователь хочет видеть записи до r151, тогда
cNext = cCurrent // основной поток
cCurrent = cPrev // основной поток

Итак, cPrev = {r90 r91 r92 ... r120} // заполняется дочерним потоком при просмотре пользователем cCurrent
cCurrent = {r121 r121 r123 ... r150}
cNext = {r151 r152 r153 ... r180}

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

Но как насчет «предыдущей» операции?единственное решение, которое приходит мне в голову: [1] закрыть текущее файловое соединение [2] открыть новое файловое соединение [3] начать чтение с начала файла до достижения соответствующей записи и [4] затем назначить набор записей в коллекцию,(Я не знаю, как это спросить) Что не так с этим подходом?Плюс, есть ли лучший способ или алгоритм здесь?Ребята, держите это простым, но не сжатым.Я не гуру Java.

Ответы [ 3 ]

2 голосов
/ 06 января 2012

встроенная база данных , например Java DB .Хранит в файле, имеет хорошие учебники.Это позволяет масштабировать до большой базы данных: это дает не очень хорошее впечатление, когда приложение слишком быстро замедляется со временем.

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

1 голос
/ 06 января 2012

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

Тогда почему бы не использовать Hibernate / JPA вместе со встроенной базой данных? Таким образом, вы можете использовать CRUD для простых данных, но при необходимости легко масштабировать до реляционной модели. Встроенная база данных управляет кэшированием, транзакциями, блокировками ... Недостатком является крутая кривая обучения.

Так что, если вы хотите избежать крутой кривой обучения, я предлагаю вам использовать метод Коллекции. Вас беспокоит сбой вашего приложения, если ему не хватает памяти. Это реальная проблема или только теоретическая? Разве вы не можете нарезать ваши данные на части, загружая только одну часть в память в любой момент времени и сериализуя остальные на диск. Что-то вроде:

private List<DataSlice> slices;
public class DataSlice {
  private ArrayList<Object> data;
  private File backingFile;

  private void load() {
    data = deserialize(backingFile);
  }

  private void release() {
    if(dirty) save(data, backingFile);
    data = null; // data is garbage collected, but there is a risk the objects are still referenced in memory
  }

  private void doCrudOperation() {
    dirty = true;
    doSomething();
  }
}

Это уже реализовано в "vanilla-java" (пакет HugeCollections): http://code.google.com/p/vanilla-java/

Имейте в виду, что, вероятно, лучше использовать встроенную БД в долгосрочной перспективе. Вам нужно узнать о Java Entity Beans и персистентности Java, но вы сможете использовать это на долгие годы.

1 голос
/ 06 января 2012

Я могу придумать следующий способ -

Использовать какой-то механизм «кэширования» вместе с какой-то стратегией (LIFO, FIFO) и читать до 100 записей в памяти, остальные остаются в плоском файле.

Напишите фоновый поток, который будет обрабатывать обновления / добавления / удаления коллекции и соответственно обновлять плоский файл.

...