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

24

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

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

    } 
}
</code>

Требования:

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

Persistent Binary Tree / Hash table in .Net Disk backed dictionary/cache for c# PersistentDictionary<Key,Value>
Проверять, выписываться:PersistentDictionary учебный класс KMån
с / настойчивым / постоянным / г eleven81
Вы издеваетесь надо мной. Вопрос, заданный Сэмом Шафроном, закрыт как не по теме? Вы, люди, чертовски безумны. Chris Marisic

Ваш Ответ

17   ответов
0

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

1
Error: User Rate Limit Exceeded Sam Saffron
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.
Error: User Rate Limit Exceeded Sam Saffron
Error: User Rate Limit Exceeded
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.

Error: User Rate Limit Exceeded
0

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

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

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Sam Saffron
13

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

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

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

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

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
0

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

ММАП

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.

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 Exceededen.wikipedia.org/wiki/Persistent_data_structure
Error: User Rate Limit Exceeded Sam Saffron
Error: User Rate Limit Exceeded
1

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

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

8

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

http://managedesent.codeplex.com/

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededmanagedesent.codeplex.com/discussions/217114
2

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

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

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

Error: User Rate Limit Exceeded Sam Saffron
6

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

Error: User Rate Limit Exceeded Sam Saffron
1

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

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

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

Error: User Rate Limit Exceeded Sam Saffron
0

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

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

Error: User Rate Limit Exceeded
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;
}
Error: User Rate Limit Exceeded
0

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

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Sam Saffron
Error: User Rate Limit Exceeded Sam Saffron

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