24

Вопрос по .net, c# – Ищем простую автономную постоянную реализацию словаря в C # [закрыто]

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

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

    } 
}

Требования:

  • Open Source, with no dependency on native code (no sqlite)
  • Ideally a very short and simple implementation
  • When setting or clearing a value it should not re-write the entire underlying file, instead it should seek to the position in the file and update the value.

Similar Questions

  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceededmanagedesent.codeplex.com/discussions/217114

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit Exceeded

    от Sam Saffron
  • Error: User Rate Limit ExceededA persistent sorted collection implements interface IPersistentSorted<T> and is a sorted collection of which one can efficiently make a read-only snapshot, or a “copy” that is not affected by updates to the original collection. It describes a method Snapshot() that returns a sorted collection with exactly the same items as the persistent sorted collection. The TreeSet<T> and TreeBag<T> collection classes are persistent sorted collections; their Snapshot() methods take constant time, but sub- sequent updates to the given tree take more time and spaceError: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceededen.wikipedia.org/wiki/Persistent_data_structure

    от
  • Вы издеваетесь надо мной. Вопрос, заданный Сэмом Шафроном, закрыт как не по теме? Вы, люди, чертовски безумны.

    от Chris Marisic
  • с / настойчивым / постоянным / г

    от eleven81
  • Проверять, выписываться:PersistentDictionary учебный класс

    от KMån
17 ответов
  • 23

    bplustreedotnet

    The bplusdotnet package is a library of cross compatible data structure implementations in C#, java, and Python which are useful for applications which need to store and retrieve persistent information. The bplusdotnet data structures make it easy to store string keys associated with values permanently.

    ESENT Managed Interface

    Not 100% managed code but it's worth mentioning it as unmanaged library itself is already part of every windows XP/2003/Vista/7 box

    ESENT is an embeddable database storage engine (ISAM) which is part of Windows. It provides reliable, transacted, concurrent, high-performance data storage with row-level locking, write-ahead logging and snapshot isolation. This is a managed wrapper for the ESENT Win32 API.

    Akavache

    *Akavache is an asynchronous, persistent key-value cache created for writing native desktop and mobile applications in C#. Think of it like memcached for desktop apps.

    - The C5 Generic Collection Library

    C5 provides functionality and data structures not provided by the standard .Net System.Collections.Generic namespace, such as persistent tree data structures, heap based priority queues, hash indexed array lists and linked lists, and events on collection changes.

  • 0

    Рассмотрим файл сопоставления памяти. Я не уверен

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

  • 0

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

  • 8

    Я реализовал тот тип PersistedDictionary

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

    http://managedesent.codeplex.com/

  • 0

    Я рекомендую

    SQL Server Express или другая база данных.

    It's free. It integrates very well with C#, including LINQ. It's faster than a homemade solution. It's more reliable than a homemade solution. It's way more powerful than a simple disk-based data structure, so it'll be easy to do more in the future. SQL is an industry standard, so other developers will understand your program more easily, and you'll have a skill that is useful in the future.

  • 0

    Я на самом деле не использовал его

    но этот проект, по-видимому, предоставляет реализацию, похожую на mmap () в C #

    ММАП

  • 2

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

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

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

  • 6

    Одним из способов является использование

    Расширяемый механизм хранения встроенный в хранилище для хранения ваших вещей. Это собственная база данных win, которая поддерживает индексацию, транзакции и т. Д.

  • 1

    Я сам написал реализацию

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

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

    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;
    }
    

  • 1

    Звучит круто

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

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

    (отредактировано для добавления пояснения)

  • 0

    Я ничего не знаю

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

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

  • 1

    Проверьте этот блог:

    http://ayende.com/Blog/archive/2009/01/17/rhino.dht-ndash-persistent-amp-distributed-storage.aspx

    Похоже, именно то, что вы ищете.

  • 1

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

    When setting or clearing a value it should not re-write the entire underlying file, instead it should seek to the position in the file and update the value.

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

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

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

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

    Если вы замените значение в середине, оно должно быть точно такого же размера, или вам придетсяrewrite every byte that comes after it.

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

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

    Вы могли бы сделать:

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

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

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

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

    If you're dealing with large amounts of data then you really need to check out using a full-blown DB. MySql or SqlLite are both good, but you're not going to find a good, simple, open-source and lite implementation.

    If you aren't dealing with loads of data then I'd go for whole file serialisation, and there are already plenty of good suggestions here on how to do that.

  • 1

    Я нашел эту ссылку и звучит как то

    что вы ищете. Он запрограммирован на Java, но не должно быть так сложно перенести его на C #:

    http://www.javaworld.com/javaworld/jw-01-1999/jw-01-step.html

  • 13

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

    Retrieve information by key Persistant storage Do not want to write back the whole file when 1 value changes Should survive crashes

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

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

  • -1

    Я не большой программист

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

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

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

    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 в памяти с точки зрения производительности, с этим довольно легко справиться. В зависимости от ваших требований, вам может вообще не понадобиться словарь.

  • 0

    Как сказал Дуглас

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

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