Pergunta

Eu estou escrevendo um aplicativo que leva o usuário de dados e armazena-a localmente para uso posterior.O aplicativo será iniciado e parado com bastante frequência, e eu gostaria de fazer é salvar/carregar os dados no aplicativo de início/fim.

Seria relativamente simples se eu utilizados arquivos simples, como os dados não realmente precisa ser protegido (ele só vai ser armazenados no PC).As opções que eu acredito que são assim:

  • Arquivos simples
  • XML
  • BANCO DE DADOS SQL

Televisão arquivos necessitam de um pouco mais de esforço para manter (não construído em classes como com XML), no entanto eu não tenho usado a XML e SQL parece um exagero para esta tarefa relativamente fácil.

Existem outros lugares que vale a pena explorar?Se não, qual dessas é a melhor solução?


Editar:Para adicionar um pouco mais de dados para o problema, basicamente, a única coisa que eu gostaria de armazenamento é um Dicionário que se parece com isso

Dictionary<string, List<Account>> 

onde a Conta é outro tipo personalizado.

Eu iria serializar o dict como o xmlroot e, em seguida, o tipo de Conta como atributos?


Atualização 2:

Portanto, é possível serializar um dicionário.O que torna complicado é que o valor para este dict é um genérico em si, que é uma lista de complexas estruturas de dados do tipo Conta.Cada Conta é bastante simples, é só um monte de propriedades.

É meu entendimento que o objetivo aqui é tentar acabar com este:

<Username1>
    <Account1>
        <Data1>data1</Data1>
        <Data2>data2</Data2>
    </Account1>
</Username1>
<Username2>
    <Account1>
        <Data1>data1</Data1>
        <Data2>data2</Data2>
    </Account1>
    <Account2>
        <Data1>data1</Data1>
        <Data2>data2</Data2>
    </Account2>
 </Username2>

Como você pode ver o heirachy é

  • Nome de utilizador (cadeia de dict) >
  • Conta (cada conta na Lista) >
  • Conta de dados (ou seja, propriedades de classe).

Como obter este layout a partir de um Dictionary<Username, List<Account>> é a parte complicada, e a essência da questão.

Há uma abundância de 'como' respostas aqui no serialisation, que é minha culpa, pois eu não torná-lo mais claro no início, mas agora eu estou olhando para uma solução definitiva.

Foi útil?

Solução

Eu armazenaria o arquivo como JSON. Como você está armazenando um dicionário que é apenas uma lista de nomes/pares, é para isso que o JSON foi projetado.
Há algumas bibliotecas decentes e gratuitas .NET JSON - aqui estão 1 Mas você pode encontrar uma lista completa no primeiro link.

Outras dicas

Realmente depende do que você está armazenando. Se você está falando de dados estruturados, o XML ou um SQL RDBMS muito leves como SQLite ou SQL Server Compact Edition funcionará bem para você. A solução SQL se torna especialmente atraente se os dados se moverem além de um tamanho trivial.

Se você estiver armazenando grandes peças de dados relativamente não estruturados (objetos binários como imagens, por exemplo), obviamente nem um banco de dados nem a solução XML são apropriados, mas, dada a sua pergunta, acho que é mais do primeiro que o último.

O XML é fácil de usar, via serialização. Usar Armazenamento isolado.

Veja também Como decidir onde armazenar o estado por usuário? Registro? Dados do aplicativo? Armazenamento isolado?

public class UserDB 
{
    // actual data to be preserved for each user
    public int A; 
    public string Z; 

    // metadata        
    public DateTime LastSaved;
    public int eon;

    private string dbpath; 

    public static UserDB Load(string path)
    {
        UserDB udb;
        try
        {
            System.Xml.Serialization.XmlSerializer s=new System.Xml.Serialization.XmlSerializer(typeof(UserDB));
            using(System.IO.StreamReader reader= System.IO.File.OpenText(path))
            {
                udb= (UserDB) s.Deserialize(reader);
            }
        }
        catch
        {
            udb= new UserDB();
        }
        udb.dbpath= path; 

        return udb;
    }


    public void Save()
    {
        LastSaved= System.DateTime.Now;
        eon++;
        var s= new System.Xml.Serialization.XmlSerializer(typeof(UserDB));
        var ns= new System.Xml.Serialization.XmlSerializerNamespaces();
        ns.Add( "", "");
        System.IO.StreamWriter writer= System.IO.File.CreateText(dbpath);
        s.Serialize(writer, this, ns);
        writer.Close();
    }
}

Todos os acima são boas respostas, e normalmente resolve o problema.

Se você precisa de uma maneira fácil e gratuita de escala para milhões de pedaços de dados, experimentar o ESENT Interface de gestão de projeto em CodePlex.

ESENT é um de um banco de dados do mecanismo de armazenamento (ISAM), que é parte do Windows.Fornece confiável, e transacionados, em simultâneo, de alto desempenho e armazenamento de dados com bloqueio em nível de linha, write-ahead log e isolamento de instantâneo.Este é um wrapper gerenciado para o ESENT de API do Win32.

Ele tem uma PersistentDictionary objeto que é bastante fácil de usar.Pense nisso como um Dicionário() do objeto, mas é automaticamente carregado a partir de e salvos para o disco sem código extra.

Por exemplo:

/// <summary>
/// Ask the user for their first name and see if we remember 
/// their last name.
/// </summary>
public static void Main()
{
    PersistentDictionary<string, string> dictionary = new PersistentDictionary<string, string>("Names");
    Console.WriteLine("What is your first name?");
    string firstName = Console.ReadLine();
    if (dictionary.ContainsKey(firstName))
    {
        Console.WriteLine("Welcome back {0} {1}", firstName, dictionary[firstName]);
    }
    else
    {
        Console.WriteLine("I don't know you, {0}. What is your last name?", firstName);
        dictionary[firstName] = Console.ReadLine();
    }

A resposta de George pergunta:

Chave Suportados Tipos De

Apenas esses tipos são suportados como chaves de dicionário:

Boolean Byte Int16 UInt16 Int32 UInt32 Int64 UInt64 Flutuar Duplo Guid DateTime TimeSpan Cadeia

Suportados Tipos De Valor

Dicionário de valores pode ser qualquer um dos tipos de chave, Anulável versões do tipos de chave, Url, Endereço de ip ou um serializable estrutura.Uma estrutura é apenas considerados serializável se atende a todos estes critérios:

• A estrutura é marcada como serializable • Cada membro da a estrutura é:1.Um tipo de dados primitivo (por exemplo,Int32) 2.Uma Seqüência de caracteres ou um Uri ou IPAddress 3.Serializável estrutura.

Ou, para colocar de outra forma, um serializable estrutura não pode conter quaisquer referências a um objeto de classe.Este é feito para preservar a API de consistência.Adicionar um objeto a uma PersistentDictionary cria uma cópia de o objeto de serialização.Modificando o objeto original não modificar a cópia, o que levaria a confuso comportamento.Para evitar esses problemas a PersistentDictionary vai aceitar somente tipos de valor como valores.

Pode Ser Serializado [Serializable] struct Bom { público DateTime?Recebido;public string Nome;público Decimal do Preço;público Uri, Url;}

Não pode Ser Serializado [Serializable] struct Ruim { public byte[] Dados;// arrays não são suportados público de Erro de Exceção;// objeto de referência }

Eu recomendo a classe XML Reader/Writer para arquivos porque é facilmente serializada.

Serialização em C#

A serialização (conhecida como decapagem em Python) é uma maneira fácil de converter um objeto em uma representação binária que pode ser então escrita em disco ou enviada por um fio.

É útil, por exemplo, para facilitar a economia de configurações em um arquivo.

Você pode serializar suas próprias aulas se você as marcar com [Serializable]atributo. Isso serializa todos os membros de uma classe, exceto aqueles marcados como [NonSerialized].

A seguir, o código é para mostrar como fazer isso:

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;


namespace ConfigTest
{ [ Serializable() ]

    public class ConfigManager
    {
        private string windowTitle = "Corp";
        private string printTitle = "Inventory";

        public string WindowTitle
        {
            get
            {
                return windowTitle;
            }
            set
            {
                windowTitle = value;
            }
        }

        public string PrintTitle
        {
            get
            {
                return printTitle;
            }
            set
            {
                printTitle = value;
            }
        }
    }
}

Você então, talvez em uma configuração, ligue para sua classe ConfigManager e serialize -a!

public ConfigForm()
{
    InitializeComponent();
    cm = new ConfigManager();
    ser = new XmlSerializer(typeof(ConfigManager));
    LoadConfig();
}

private void LoadConfig()
{     
    try
    {
        if (File.Exists(filepath))
        {
            FileStream fs = new FileStream(filepath, FileMode.Open);
            cm = (ConfigManager)ser.Deserialize(fs);
            fs.Close();
        } 
        else
        {
            MessageBox.Show("Could not find User Configuration File\n\nCreating new file...", "User Config Not Found");
            FileStream fs = new FileStream(filepath, FileMode.CreateNew);
            TextWriter tw = new StreamWriter(fs);
            ser.Serialize(tw, cm);
            tw.Close();
            fs.Close();
        }    
        setupControlsFromConfig();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Depois de ser serializado, você pode chamar os parâmetros do seu arquivo de configuração usando CM.Windowtitle, etc.

Uma quarta opção para aqueles que você menciona são arquivos binários. Embora isso pareça arcano e difícil, é realmente fácil com a API de serialização no .NET.

Se você escolhe arquivos binários ou XML, pode usar a mesma API de serialização, embora usaria serializadores diferentes.

Para serializar uma classe binária, ela deve ser marcada com o atributo [serializável] ou implementar iserializável.

Você pode fazer algo semelhante com Xml, embora a interface seja chamada ixmlSerializable, e os atributos são [XMLROOT] e outros atributos no espaço names do System.xml.Serialization.

Se você deseja usar um banco de dados relacional, Edição compacta do SQL Server é gratuito e muito leve e com base em um único arquivo.

Se sua coleção ficar muito grande, descobri que a serialização XML fica bastante lenta. Outra opção para serializar seu dicionário seria "Roll Yours Own" usando um leitor de binários e binarywriter.

Aqui está algum código de exemplo apenas para você começar. Você pode criar esses métodos de extensão genérica para lidar com qualquer tipo de dicionário e funciona muito bem, mas é muito detalhado para postar aqui.

class Account
{
    public string AccountName { get; set; }
    public int AccountNumber { get; set; }

    internal void Serialize(BinaryWriter bw)
    {
        // Add logic to serialize everything you need here
        // Keep in synch with Deserialize
        bw.Write(AccountName);
        bw.Write(AccountNumber);
    }

    internal void Deserialize(BinaryReader br)
    {
        // Add logic to deserialize everythin you need here, 
        // Keep in synch with Serialize
        AccountName = br.ReadString();
        AccountNumber = br.ReadInt32();
    }
}


class Program
{
    static void Serialize(string OutputFile)
    {
        // Write to disk 
        using (Stream stream = File.Open(OutputFile, FileMode.Create))
        {
            BinaryWriter bw = new BinaryWriter(stream);
            // Save number of entries
            bw.Write(accounts.Count);

            foreach (KeyValuePair<string, List<Account>> accountKvp in accounts)
            {
                // Save each key/value pair
                bw.Write(accountKvp.Key);
                bw.Write(accountKvp.Value.Count);
                foreach (Account account in accountKvp.Value)
                {
                    account.Serialize(bw);
                }
            }
        }
    }

    static void Deserialize(string InputFile)
    {
        accounts.Clear();

        // Read from disk
        using (Stream stream = File.Open(InputFile, FileMode.Open))
        {
            BinaryReader br = new BinaryReader(stream);
            int entryCount = br.ReadInt32();
            for (int entries = 0; entries < entryCount; entries++)
            {
                // Read in the key-value pairs
                string key = br.ReadString();
                int accountCount = br.ReadInt32();
                List<Account> accountList = new List<Account>();
                for (int i = 0; i < accountCount; i++)
                {
                    Account account = new Account();
                    account.Deserialize(br);
                    accountList.Add(account);
                }
                accounts.Add(key, accountList);
            }
        }
    }

    static Dictionary<string, List<Account>> accounts = new Dictionary<string, List<Account>>();

    static void Main(string[] args)
    {
        string accountName = "Bob";
        List<Account> newAccounts = new List<Account>();
        newAccounts.Add(AddAccount("A", 1));
        newAccounts.Add(AddAccount("B", 2));
        newAccounts.Add(AddAccount("C", 3));
        accounts.Add(accountName, newAccounts);

        accountName = "Tom";
        newAccounts = new List<Account>();
        newAccounts.Add(AddAccount("A1", 11));
        newAccounts.Add(AddAccount("B1", 22));
        newAccounts.Add(AddAccount("C1", 33));
        accounts.Add(accountName, newAccounts);

        string saveFile = @"C:\accounts.bin";

        Serialize(saveFile);

        // clear it out to prove it works
        accounts.Clear();

        Deserialize(saveFile);
    }

    static Account AddAccount(string AccountName, int AccountNumber)
    {
        Account account = new Account();
        account.AccountName = AccountName;
        account.AccountNumber = AccountNumber;
        return account;
    }
}

Acabei de codificar o armazenamento de dados para o meu projeto atual. Aqui estão meus 5 centavos.

Comecei com serialização binária. Foi lento (cerca de 30 segundos para carga de 100.000 objetos) e estava criando um arquivo bastante grande no disco também. No entanto, levei algumas linhas de código para implementar e obtive todas as minhas necessidades de armazenamento cobertas. Para obter melhor desempenho, mudei para a serialização personalizada. Encontrou a estrutura FastSerialization por Tim Haynes no Código Projeto. De fato, é algumas vezes mais rápido (tenho 12 segundos para carga, 8 segundos para salvar, 100k registros) e leva menos espaço em disco. A estrutura é construída sobre a técnica descrita por Galacticjello em uma postagem anterior.

Depois, mudei -me para o SQLite e consegui obter 2 vezes 3 vezes mais desempenho - 6 segundos para carga e 4 segundos para salvar, 100k registros. Inclui a análise de tabelas ADO.NET para tipos de aplicativos. Também me deu um arquivo muito menor no disco. Este artigo explica como obter o melhor desempenho do ADO.NET: http://sqlite.phxsoftware.com/forums/t/134.aspx. Gerar declarações de inserção é uma ideia muito ruim. Você pode adivinhar como eu soube disso. :) De fato, a implementação do SQLite levou um pouco de tempo, além de uma medida cuidadosa do tempo que toma por praticamente todas as linhas do código.

Se seus dados forem complexos, com alta quantidade ou você precisar consultá -los localmente, os bancos de dados de objetos poderão ser uma opção válida. Eu sugiro olhar para Db4o ou Karvonite.

A primeira coisa que eu veria é um banco de dados. No entanto, a serialização é uma opção. Se você for para a serialização binária, eu faria evitar BinaryFormatter - tem uma tendência a ficar com raiva entre as versões se você mudar de campos etc. xml via XmlSerialzier Seria bom e pode ser compatível com lado a lado (ou seja, com as mesmas definições de classe) com o Protobuf-Net se você quiser experimentar a serialização binária baseada em contrato (oferecendo um serializador de arquivo plano sem nenhum esforço).

Muitas das respostas neste thread tentam excessivamente a solução. Se estiver correto, você só deseja armazenar as configurações do usuário.

Use um arquivo .ini ou app.config para isso.

Se eu estiver errado e você está armazenando dados que são mais do que apenas configurações, use um arquivo de texto plano no formato CSV. Estes são rápidos e fáceis sem a sobrecarga do XML. As pessoas gostam de fazer cocô isso, pois não são tão elegantes, não escalam bem e não parecem tão boas em um currículo, mas pode ser a melhor solução para você, dependendo do que você precisa.

Eu fiz vários aplicativos "independentes" que possuem um armazenamento de dados local. Eu acho que a melhor coisa a usar seria o SQL Server Compact Edition (anteriormente conhecido como SQLANY EURS).

É leve e grátis. Além disso, você pode continuar escrevendo uma camada de acesso a dados que é reutilizável em outros projetos, além de que o aplicativo precisar escalar para algo maior como o SQL Server completo, você só precisará alterar a string de conexão.

Minha primeira inclinação é um banco de dados de acesso. Os arquivos .mdb são armazenados localmente e podem ser criptografados se isso for considerado necessário. Embora XML ou JSON também funcionem para muitos cenários. Arquivos planos que eu usaria apenas para leitura apenas, informações não pesquisadas (somente leitura direta). Costumo preferir o formato CSV para definir a largura.

Depende da quantidade de dados que você deseja armazenar. Na realidade, não há diferença entre arquivos planos e xml. O XML provavelmente seria preferível, pois fornece uma estrutura ao documento. Na prática,

A última opção e muitos aplicativos usam agora é o registro do Windows. Eu pessoalmente não o recomendo (registro inchaço, corrupção, outros problemas em potencial), mas é uma opção.

Sem saber como são seus dados, ou seja, a complexidade, tamanho, etc ... XML é fácil de manter e facilmente acessível. Eu não usaria um banco de dados de acesso, e os arquivos planos são mais difíceis de manter a longo prazo, principalmente se você estiver lidando com mais de um campo/elemento de dados em seu arquivo.

Eu lido com grandes feeds de dados de arquivos planos diariamente em boas quantidades e, embora um exemplo extremo, dados de arquivos planos sejam muito mais difíceis de manter do que os feeds de dados XML que processem.

Um exemplo simples de carregar dados XML em um conjunto de dados usando C#:

DataSet reportData = new DataSet();

reportData.ReadXml(fi.FullName);

Você também pode conferir o LINQ para XML como uma opção para consultar os dados XML ...

HTH ...

Se você seguir a rota de serialização binária, considere a velocidade com que um membro específico do dado precisa ser acessado. Se for apenas uma pequena coleção, carregar todo o arquivo fará sentido, mas se for grande, você também poderá considerar um arquivo de índice.

Rastreando propriedades/campos da conta localizados em um endereço específico no arquivo pode ajudá -lo a acelerar o tempo de acesso, especialmente se você otimizar esse arquivo de índice com base no uso da chave. (Possivelmente mesmo quando você escreve no disco.)

Dependendo da oblexidade do seu objeto de conta, eu recomendaria o arquivo XML ou FLAT.

Se houver apenas alguns valores para armazenar para cada conta, você poderá armazená -los em um arquivo de propriedades, como este:

account.1.somekey=Some value
account.1.someotherkey=Some other value
account.1.somedate=2009-12-21
account.2.somekey=Some value 2
account.2.someotherkey=Some other value 2

... e assim por diante. A leitura de um arquivo de propriedades deve ser fácil, pois mapeia diretamente para um dicionário de string.

Quanto a onde armazenar esse arquivo, a melhor escolha seria armazenar na pasta AppData, dentro de uma subpasta para o seu programa. Este é um local em que os usuários atuais sempre terão acesso a gravar e é mantido a salvo de outros usuários pelo próprio sistema operacional.

Mantenha -o simples - como você disse, um arquivo plano é suficiente. Use um arquivo plano.

Isso assume que você analisou seus requisitos corretamente. Eu ignorava a serialização como etapa XML, exagerou para um dicionário simples. A mesma coisa para um banco de dados.

Na minha experiência, na maioria dos casos, o JSON em um arquivo é suficiente (principalmente você precisa armazenar uma matriz ou um objeto ou apenas um único número ou string). Eu raramente preciso de sqlite (que precisa de mais tempo para configurá -lo e usá -lo, na maioria das vezes é um exagero).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top