Подтвердить что ты не робот

Ищете простой автономный постоянный словарь в С#

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

class PersistentDictionary<T,V> : IDictionary<T,V>
{
    public PersistentDictionary(string filename)
    {

    } 
}

Требования:

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

Похожие вопросы

4b9b3361

Ответ 1

  • bplustreedotnet

    Пакет bplusdotnet представляет собой библиотеку перекрестных совместимых реализаций структуры данных в С#, java и Python, которые полезны для приложений, которые должны хранить и извлекать постоянную информацию. Структуры данных bplusdotnet упрощают хранить строковые ключи, связанные со значениями постоянно.

  • Управляемый интерфейс ESENT

    Не 100% управляемый код, но стоит упомянуть его как неуправляемую библиотеку, уже являющуюся частью каждого окна Windows XP/2003/Vista/7

    ESENT - это встроенный механизм хранения базы данных (ISAM), который является частью Windows. Он обеспечивает надежное, транзакционное, одновременное высокопроизводительное хранилище данных с блокировкой на уровне строк, протоколированием на основе записи и изоляцией моментальных снимков. Это управляемая оболочка API ESENT Win32.

  • Akavache

    * Akavache - это асинхронный, постоянный кеш-ключ, созданный для записи родных настольных и мобильных приложений на С#. Подумайте об этом, как memcached для настольных приложений.

- Библиотека коллекций C5

C5 предоставляет функциональные возможности и структуры данных, не предоставленные стандартным пространством имен .Net System.Collections.Generic, например структуры стойких древовидных данных, очереди приоритетов с кучей, списки индексов массивов хешей и связанные списки и события on коллекция меняется. Забастовкa >

Ответ 2

Позвольте мне проанализировать это:

  • Получить информацию по ключу
  • Постоянное хранилище
  • Не нужно записывать весь файл, когда изменяется одно значение.
  • Если вы пережили аварии

Я думаю, что вам нужна база данных.

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

Ответ 3

Я реализовал вид PersistedDictionary, который вы ищете. Основным хранилищем является механизм базы данных ESENT, который встроен в окна. Код доступен здесь:

http://managedesent.codeplex.com/

Ответ 4

один из способов - использовать Extensible Storage Engine, встроенный в ветровые камеры для хранения ваших вещей. Это собственная база данных win, которая поддерживает индексирование, транзакции и т.д.

Ответ 5

Я работал над переносом EHCache в .NET. Взгляните на проект

http://sourceforge.net/projects/thecache/

Постоянное кэширование - это основная функциональность, которая уже реализована. Проходят все основные тесты. Я немного застрял в распределенном кешировании, но вам не нужна эта часть.

Ответ 6

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

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

(отредактировано, чтобы добавить пояснения)

Ответ 8

Я думаю, что ваша проблема, вероятно, будет последней точкой:

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

Это именно то, что делает БД - вы в основном описываете простую структуру таблиц на основе файлов.

Мы можем проиллюстрировать проблему, посмотрев на строки.

Строки в памяти - это гибкие вещи - вам не нужно знать длину строки в С# при объявлении ее типа.

В строках хранения данных и все остальное - фиксированные размеры. Сохраненный словарь на диске - это всего лишь набор байтов в порядке.

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

Вот почему большинство баз данных ограничивают текстовые и blob-поля фиксированными размерами. Новые функции, такие как varchar(max)/varbinary(max) в Sql 2005+, на самом деле являются умными упрощениями для строки, фактически сохраняющей указатель на реальные данные.

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

Вы можете сделать:

class PersistantDictionary<T,V> : Dictionary<T,V>
    where V:struct

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

Однако ваша модель не будет очень результативной - если вы посмотрите, как SQL-сервер и Oracle имеют дело с изменениями таблиц, они не изменяют такие значения. Вместо этого они отмечают старую запись как призрак и добавляют новую запись с новым значением. Старые затененные записи очищаются позже, когда БД менее занята.

Я думаю, вы пытаетесь изобрести колесо:

  • Если вы имеете дело с большими объемами данных, вам действительно нужно проверить использование полномасштабной БД. MySql или SqlLite оба хороши, но вы не найдете хорошую, простую, открытую исходную и облегченную реализацию.

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

Ответ 9

Я бы рекомендовал SQL Server Express или другую базу данных.

  • Это бесплатно.
  • Он очень хорошо интегрируется с С#, включая LINQ.
  • Это быстрее, чем самодельное решение.
  • Он более надежен, чем самодельное решение.
  • Это намного мощнее, чем простая структура данных на основе дисков, поэтому в будущем будет легко сделать больше.
  • SQL - это отраслевой стандарт, поэтому другие разработчики будут легче понимать вашу программу, и у вас будет навык, который будет полезен в будущем.

Ответ 10

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

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

class PersistentDictManager {
    const int SaveAllThreshold = 1000;

    PersistentDictManager(string logpath) {
        this.LogPath = logpath;
        this.mydictionary = new Dictionary<string, string>();
        this.LoadData();
    }

    public string LogPath { get; private set; }

    public string this[string key] {
        get{ return this.mydictionary[key]; }
        set{
            string existingvalue;
            if(!this.mydictionary.TryGetValue(key, out existingvalue)) { existingvalue = null; }
            if(string.Equals(value, existingvalue)) { return; }
            this[key] = value;

            // store in log
            if(existingvalue != null) { // was an update (not a create)
                if(this.IncrementSaveAll()) { return; } // because we're going to repeat a key the log
            }
            this.LogStore(key, value);
        }
    }

    public void Remove(string key) {
        if(!this.mydictionary.Remove(key)) { return; }
        if(this.IncrementSaveAll()) { return; } // because we're going to repeat a key in the log
        this.LogDelete(key);
    }

    private void CreateWriter() {
        if(this.writer == null) {
            this.writer = new BinaryWriter(File.Open(this.LogPath, FileMode.Open)); 
        }
    }

    private bool IncrementSaveAll() {
        ++this.saveallcount;
        if(this.saveallcount >= PersistentDictManager.SaveAllThreshold) {
            this.SaveAllData();
            return true;
        }
        else { return false; }
    }

    private void LoadData() {
        try{
            using(BinaryReader reader = new BinaryReader(File.Open(LogPath, FileMode.Open))) {
                while(reader.PeekChar() != -1) {
                    string key = reader.ReadString();
                    bool isdeleted = reader.ReadBoolean();
                    if(isdeleted) { this.mydictionary.Remove(key); }
                    else {
                        string value = reader.ReadString();
                        this.mydictionary[key] = value;
                    }
                }
            }
        }
        catch(FileNotFoundException) { }
    }

    private void LogDelete(string key) {
        this.CreateWriter();
        this.writer.Write(key);
        this.writer.Write(true); // yes, key was deleted
    }

    private void LogStore(string key, string value) {
        this.CreateWriter();
        this.writer.Write(key);
        this.writer.Write(false); // no, key was not deleted
        this.writer.Write(value);
    }

    private void SaveAllData() {
        if(this.writer != null) {
            this.writer.Close();
            this.writer = null;
        }
        using(BinaryWriter writer = new BinaryWriter(File.Open(this.LogPath, FileMode.Create))) {
            foreach(KeyValuePair<string, string> kv in this.mydictionary) {
                writer.Write(kv.Key);
                writer.Write(false); // is not deleted flag
                writer.Write(kv.Value);
            }
        }
    }

    private readonly Dictionary<string, string> mydictionary;
    private int saveallcount = 0;
    private BinaryWriter writer = null;
}

Ответ 12

Просто используйте сериализацию. Посмотрите на класс BinaryFormatter.

Ответ 13

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

Это означает, что нормальные строки отсутствуют.

Ответ 14

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

Тем не менее, реализация словаря, поддерживаемого файлом, довольно проста, и вы можете использовать класс BinaryWriter для записи типов на диск после наследования или инкапсуляции класса Dictionary<TKey, TValue>.

Ответ 15

Рассмотрим файл с отображением памяти. Я не уверен, есть ли прямая поддержка в .NET, но вы можете вызывать вызовы Win32.

Ответ 16

Я на самом деле не использовал его, но этот проект, по-видимому, обеспечивает реализацию mmap() в С#

Mmap

Ответ 17

Я не очень программист, но не создавал бы действительно простой XML-формат для хранения ваших данных, трюк?

<dico> 
   <dicEntry index="x">
     <key>MyKey</key>
     <val type="string">My val</val>
   </dicEntry>
   ...
</dico>

Оттуда вы загрузите файл DOM XML и заполните свой словарь, как вам нравится,

XmlDocument xdocDico = new XmlDocument();
string sXMLfile;
public loadDico(string sXMLfile, [other args...])
{
   xdocDico.load(sXMLfile);
   // Gather whatever you need and load it into your dico
}
public flushDicInXML(string sXMLfile, dictionary dicWhatever)
{
   // Dump the dic in the XML doc & save
}
public updateXMLDOM(index, key, value)
{
   // Update a specific value of the XML DOM based on index or key
}

Затем, когда вы хотите, вы можете обновить DOM и сохранить его на диске.

xdocDico.save(sXMLfile);

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