持久性队列<>或列表<>即使程序关闭或重新启动

时间:2015-09-30 17:17:10

标签: c#

我正在尝试使应用程序重启/崩溃/结束持久队列(或List ..)。即:我需要在应用程序运行时添加内容并在以后删除内容。在这两个位置之间,应用程序可以重新启动多次(或者崩溃,或者已经为我所知道的任务结束了。)

我的第一个想法就是简单地创建一个mylist.txt文件来逐行存储数据,并在我需要时添加行到最后一行,并在完成后删除第一行。

问题是一段时间后文本文件中可能有数千行,如果不读取并重写整个文件,就无法删除其中的第一行。

有没有什么好方法可以实现这一点,因为不断阅读和编写整个文件不是一种选择?

编辑1 :我正在研究SQLite,但我更愿意不再添加依赖项或.dll,如果可能的话,不能ILMerged。

编辑2:应用程序不能依赖任何外部服务器来跟踪它的内容。

编辑3:对ILMerge兼容的本地数据库的建议也是一种可接受的解决方案。

3 个答案:

答案 0 :(得分:2)

软件中持久队列的正确解决方案是使用持久性队列包。

我们称之为Message Queue库。

Microsoft Windows内置了一个名为MSMQ的内容。但是我建议使用RabbitMQ,或者如果你想要一个进程内解决方案,你可以尝试使用Ayende的Rhino Queues。

答案 1 :(得分:0)

使用数据库,持久化数据并编辑/删除它正是它们的用途,并且有一些好的免费的,试试mysql

答案 2 :(得分:0)

我自己实现了这个,只使用文件夹中的文件。它不是有史以来最快的列表,但它完成了工作,没有外部依赖。在我的笔记本电脑上,它在4秒钟内插入4000件物品,然后在12点读回。

非常欢迎任何有关如何更快或更好的建议;)

以下是测试用法:

PersistantQueue list = new PersistantQueue("queuefolder");
foreach (var i in Enumerable.Range(1, 100000))
{
    list.Add(i + "_" + Guid.NewGuid());
    if(i % 1000 == 0)
        Console.WriteLine("c: "+ DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss:fff ->") + i);
}

string msg = null;
int b = 0;
while ((msg = list.GetNext()) != null)
{
    b++;

    if (b % 1000 == 0)
        Console.WriteLine("r: " + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss:fff ->") + b);
}
Console.WriteLine("done");

和班级

public class PersistantQueue
{
    private string _FolderPath = "";
    private long _FileIdCounter = 0;
    private readonly object _LockObject = new object();

    public PersistantQueue()
    {
        Init("PersistantList");
    }

    public PersistantQueue(string folderPath)
    {
        Init(folderPath);
    }

    private void Init(string folderPath)
    {
        _FolderPath = folderPath;

        if (string.IsNullOrWhiteSpace(folderPath.Trim()) == true)
            throw new Exception("Invalid folder name");

        if (Directory.Exists(_FolderPath) == false)
            Directory.CreateDirectory(_FolderPath);
    }

    public void Add(string Item)
    {
        lock (_LockObject)
        {
            _FileIdCounter++;

            string file = DateTime.Now.ToString("yyyyMMddhhmmssfff") + "_" + _FileIdCounter;
            string path = (_FolderPath + @"\" + file);
            using (StreamWriter sw = File.CreateText(path))
            {
                sw.Write(Item);
            }
        }
    }

    public string GetNext()
    {
        string result = null;
        lock (_LockObject)
        {
            DirectoryInfo di = new DirectoryInfo(_FolderPath);

            var firstFileName = di.EnumerateFiles()
                        .Select(f => f.Name)
                        .FirstOrDefault();

            string path = (_FolderPath + @"\" + firstFileName);
            result = File.ReadAllText(path);
            File.Delete(path);
        }
        return result;
    }
}