TecnoFisc.Sped.Core
0.5.0
Prefix Reserved
dotnet add package TecnoFisc.Sped.Core --version 0.5.0
NuGet\Install-Package TecnoFisc.Sped.Core -Version 0.5.0
<PackageReference Include="TecnoFisc.Sped.Core" Version="0.5.0" />
<PackageVersion Include="TecnoFisc.Sped.Core" Version="0.5.0" />
<PackageReference Include="TecnoFisc.Sped.Core" />
paket add TecnoFisc.Sped.Core --version 0.5.0
#r "nuget: TecnoFisc.Sped.Core, 0.5.0"
#:package TecnoFisc.Sped.Core@0.5.0
#addin nuget:?package=TecnoFisc.Sped.Core&version=0.5.0
#tool nuget:?package=TecnoFisc.Sped.Core&version=0.5.0
TecnoFisc.Sped
Família de bibliotecas .NET para leitura, geração e manipulação tipada de arquivos publicados pelos projetos do SPED — Sistema Público de Escrituração Digital (Receita Federal do Brasil).
Status atual: 0.5.0 publicado. Cobre EFD Contribuições V006 (leitura + geração, round-trip validado) e EFD ICMS-IPI baseline V015 + incrementos V016 → V020 (leiaute vigente em 2026, modo read-only — parser e modelo tipado, sem geração). Os números
006(EFD Contribuições) e015–020(EFD ICMS-IPI) são oCOD_VERdo registro0000de cada leiaute (não devem ser confundidos com a versão do Guia Prático). A0.5.0é breaking — revisa a convenção de nomenclatura (verbos/factories em inglês, substantivos do domínio em português) e adiciona helpers de persistência (OfType<T>(),Batch(n),WithContext(), dispatcherIRegistroSpedVisitor). Próximos passos rastreados noARCHITECTURE.md(ECD, ECF e pacotes XML — todos planejados como read-only). Veja oCHANGELOG.mdpara detalhes.
Visão geral
A biblioteca expõe registros fortemente tipados para cada projeto SPED, com leitura
e escrita simétricas (round-trip preservado), parser baseado em
System.IO.Pipelines para arquivos de múltiplos gigabytes e zero dependências
externas em tempo de execução.
Cada projeto SPED é distribuído como um pacote NuGet independente. Esta organização mantém os layouts isolados — quando a Receita publica um novo layout, somente o pacote afetado é versionado.
| Projeto SPED | Pacote NuGet | Status |
|---|---|---|
| EFD Contribuições | TecnoFisc.Sped.EfdContribuicoes |
0.5.0 — leiaute V006 completo (leitura + geração) |
| EFD ICMS-IPI | TecnoFisc.Sped.EfdIcmsIpi |
0.5.0 — baseline V015 + incrementos V016 → V020 (vigente), read-only |
| ECD | TecnoFisc.Sped.Ecd |
planejado (read-only) — baseline 2021 + incrementos até o leiaute vigente |
| ECF | TecnoFisc.Sped.Ecf |
planejado (read-only) |
| NF-e | TecnoFisc.Sped.NFe |
planejado (XML, read-only) |
| NFC-e | TecnoFisc.Sped.NFCe |
planejado (XML, read-only) |
| CT-e | TecnoFisc.Sped.CTe |
planejado (XML, read-only) |
| Metapacote agregador | TecnoFisc.Sped |
planejado — referencia todos os leiautes acima em uma única dependência |
Modo de operação. O único pacote com geração de arquivo confirmada é
TecnoFisc.Sped.EfdContribuicoes(leitura + escrita, round-trip simétrico). Todos os demais — EFD ICMS-IPI, ECD, ECF, NF-e, NFC-e, CT-e — são planejados como read-only (parser + modelo tipado). Promoção para read+write em qualquer um deles depende de confirmação externa e entra como stage dedicada (ARCHITECTURE.md§2.5).
TecnoFisc.Sped.Core é a infraestrutura compartilhada (value objects fiscais, parser/gerador
genérico, abstrações de catálogo, identificador dinâmico de arquivos SPED) consumida por
todos os pacotes de leiaute. TecnoFisc.Sped.Core.SourceGenerators é o source generator que
produz, em tempo de compilação, o catálogo estático de registros — referenciado como
Analyzer pelos projetos de leiaute, não embarca no runtime do consumidor.
Escopo definitivo. A biblioteca cobre exatamente os sete leiautes listados na tabela
acima mais o metapacote agregador. Outros projetos SPED (eSocial, EFD-Reinf, NFS-e, MDF-e,
e-Financeira, DeRE, Central de Balanços) ficam fora do escopo e não serão
implementados — ver ARCHITECTURE.md §3 para a tabela autoritativa.
Quickstart
Instalação
dotnet add package TecnoFisc.Sped.EfdContribuicoes
Leitura buffered (modelo completo em memória)
using TecnoFisc.Sped.EfdContribuicoes;
using TecnoFisc.Sped.EfdContribuicoes.Parser;
var parser = new ParserEfdContribuicoes();
await using var entrada = File.OpenRead("PISCOFINS-202401.txt");
ArquivoEfdContribuicoes arquivo = await parser.ReadAsync(entrada);
foreach (var registro in arquivo.Bloco0.EnumerarRegistros())
Console.WriteLine(registro.Codigo);
Leitura streaming (memory-bounded)
using TecnoFisc.Sped.EfdContribuicoes.Parser;
var parser = new ParserEfdContribuicoes();
await using var entrada = File.OpenRead("arquivo-grande.txt");
await foreach (var registro in parser.ReadStreamingAsync(entrada))
{
// Um registro por vez. Memória usada não cresce com o tamanho do arquivo.
}
Persistir em banco com OfType<T>() + Batch(n)
TecnoFisc.Sped.Core.Streaming traz dois helpers que removem o boilerplate comum
de ingestão SPED → banco. OfType<T> filtra o stream pelo tipo concreto sem cast
manual; Batch(n) agrupa em lotes para bulk-insert.
using TecnoFisc.Sped.Core.Streaming;
using TecnoFisc.Sped.EfdContribuicoes.Parser;
using TecnoFisc.Sped.EfdContribuicoes.Registros.BlocoC;
var parser = new ParserEfdContribuicoes();
await using var entrada = File.OpenRead("PISCOFINS-202401.txt");
await foreach (var lote in parser.ReadStreamingAsync(entrada)
.OfType<RegistroC100>()
.Batch(1000))
{
// lote é IReadOnlyList<RegistroC100> com até 1.000 registros tipados.
// Use com Dapper, EF Core AddRangeAsync, SqlBulkCopy, etc.
await conexao.BulkInsertAsync(lote);
}
Memória continua bounded — OfType e Batch não bufferizam o arquivo inteiro;
apenas o lote corrente fica em memória. Pattern matching do OfType é resolvido
em compile-time (zero reflection, zero boxing).
IDs surrogate para FK com WithContext()
Para modelos relacionais é comum precisar de PK/FK consistentes ao inserir o
registro pai antes do filho. WithContext() enriquece o stream com um
ContextoPersistencia contendo o ID surrogate do registro atual e o ID do
pai já emitido.
using TecnoFisc.Sped.Core.Streaming;
using TecnoFisc.Sped.EfdContribuicoes.Parser;
using TecnoFisc.Sped.EfdContribuicoes.Registros.BlocoC;
await foreach (var (registro, ctx) in parser.ReadStreamingAsync(stream).WithContext())
{
switch (registro)
{
case RegistroC100 c100:
await conexao.ExecuteAsync(
"INSERT INTO docs (id, num_doc, vl_doc) VALUES (@id, @n, @v)",
new { id = ctx.IdRegistroAtual, n = c100.NumDoc, v = c100.VlDoc });
break;
case RegistroC170 c170:
await conexao.ExecuteAsync(
"INSERT INTO itens (id, doc_id, num_item) VALUES (@id, @doc, @n)",
new { id = ctx.IdRegistroAtual, doc = ctx.IdPai, n = c170.NumItem });
break;
}
}
ctx.IdPai é null para registros raiz (0000, 9990, 9999). Para retomar
import multi-arquivo sem colidir com IDs já persistidos, use o overload
WithContext(startAt: <ultimo-id-do-arquivo-anterior + 1>).
Visitor dispatcher tipado (source-generated)
Para processar muitos tipos de registro sem escrever um switch de 200+ casos,
implemente a interface IRegistroSpedVisitor (emitida pelo source generator
no namespace <Projeto>.Generated). Cada overload VisitAsync(TipoConcreto)
tem implementação default vazia — sobrescreva só o que importa. O despacho via
DispatchAsync() é resolvido em compile-time (zero reflection).
using TecnoFisc.Sped.EfdContribuicoes.Generated;
public sealed class GravadorBanco : IRegistroSpedVisitor
{
public ValueTask VisitAsync(Registro0000 r, CancellationToken ct) { /* INSERT escrituracoes */ return default; }
public ValueTask VisitAsync(RegistroC100 r, CancellationToken ct) { /* INSERT docs */ return default; }
public ValueTask VisitAsync(RegistroC170 r, CancellationToken ct) { /* INSERT itens */ return default; }
// Demais registros: default vazio, ignorados sem nada a fazer.
}
await parser.ReadStreamingAsync(stream).DispatchAsync(new GravadorBanco());
Registros de outros assemblies (caso o consumidor componha streams de
projetos diferentes) caem no VisitUnknownAsync(RegistroSped).
Geração
using TecnoFisc.Sped.EfdContribuicoes;
using TecnoFisc.Sped.EfdContribuicoes.Gerador;
var gerador = new GeradorEfdContribuicoes();
await using var saida = File.Create("saida.txt");
await gerador.WriteAsync(saida, arquivo);
O gerador injeta automaticamente os totalizadores X990 (encerramento por bloco)
e 9999 (contagem global) — basta entregar a árvore de registros.
Princípios
- Auto-contido. Sem banco de dados, sem arquivos de configuração externos, sem chamadas de rede. Streams entram, streams saem.
- Independência de formato. Projetos específicos nunca dependem uns dos outros —
registros que parecem iguais (ex.:
RegistroC100na EFD Contribuições e na ICMS-IPI) são classes distintas, propositalmente duplicadas. - Performance em primeiro lugar.
PipeReader,ReadOnlySpan<byte>,Utf8Parser.TryParsee catálogos gerados em tempo de compilação. Sem reflexão no caminho quente. - Tipagem forte de ponta a ponta. Consumidores nunca lidam com
stringoustring[]— recebemCnpj,Cfop,DateOnly,decimal, enums. - Round-trip simétrico onde há geração. Nos pacotes read+write (hoje apenas
EfdContribuicoes), ler → gerar → ler precisa devolver o mesmo arquivo (modulo normalizações deliberadas). Invariante coberta por testes. Nos pacotes read-only (EFD ICMS-IPI; ECD/ECF/NFe/NFCe/CTe planejados), a invariante é apenas leitura estável: a mesma entrada sempre produz o mesmo modelo tipado.
Arquivos assinados pelo PVA
Arquivos emitidos pelo PVA da Receita Federal trazem um bloco de assinatura
digital PKCS#7 anexado após o registro |9999|. O parser encerra o consumo
no |9999| e descarta silenciosamente todo o conteúdo posterior — não é
necessário pré-processar o arquivo para remover a assinatura. A geração não
re-anexa nenhuma assinatura: a saída contém apenas a porção textual de
registros. Quem precisar reassinar deve fazê-lo fora da biblioteca, com um
provedor PKCS#7/CMS dedicado.
Requisitos
- .NET SDK 10.0 (preview) ou superior
- Windows, Linux ou macOS
Build local
dotnet build TecnoFisc.Sped.slnx
dotnet test TecnoFisc.Sped.slnx
dotnet pack TecnoFisc.Sped.slnx -c Release
Filtrar testes:
dotnet test TecnoFisc.Sped.slnx --filter "FullyQualifiedName~Cnpj"
dotnet test TecnoFisc.Sped.slnx --filter "FullyQualifiedName~Cnpj.ValidaDigito"
Rodar benchmarks:
dotnet run -c Release --project benchmarks/TecnoFisc.Sped.Benchmarks -- --filter "*StreamingVsBufferedBenchmark*"
dotnet run -c Release --project benchmarks/TecnoFisc.Sped.Benchmarks -- --filter "*ParserCatalogoBenchmark*"
dotnet run -c Release --project benchmarks/TecnoFisc.Sped.Benchmarks -- --probe peak
Estrutura do repositório
TecnoFisc.Sped/
├── src/
│ ├── TecnoFisc.Sped.Core/ # Value objects fiscais + infra compartilhada + sniffer
│ ├── TecnoFisc.Sped.Core.SourceGenerators/ # Source generator do catálogo (analyzer)
│ ├── TecnoFisc.Sped.EfdContribuicoes/ # Leiaute EFD Contribuições V006
│ └── TecnoFisc.Sped.EfdIcmsIpi/ # Leiaute EFD ICMS-IPI baseline V015 + V016-V020 (read-only)
│ # Stages futuros (planejados): Ecd, Ecf, NFe, NFCe, CTe + metapacote TecnoFisc.Sped
├── tests/
│ ├── TecnoFisc.Sped.Core.Tests/
│ ├── TecnoFisc.Sped.EfdContribuicoes.Tests/
│ └── TecnoFisc.Sped.EfdIcmsIpi.Tests/
├── benchmarks/
│ └── TecnoFisc.Sped.Benchmarks/ # BenchmarkDotNet (.NET 10)
├── sped/
│ ├── STAGE_4_REGISTROS.md # Decomposição do Stage 4 (EFD Contribuições)
│ ├── STAGE_8_EFD_ICMS_IPI_V015.md # Decomposição do Stage 8 (EFD ICMS-IPI V015)
│ └── guides/ # PDFs oficiais Receita Federal (gitignored)
├── ARCHITECTURE.md # Documento mestre (inglês, para LLMs)
├── CHANGELOG.md # Notas de release por pacote
└── CLAUDE.md # Instruções para Claude Code
Convenções
- Português para substantivos do domínio SPED: classes de registro
(
Registro0000,RegistroC100), value objects fiscais (Cnpj,Cfop,Ncm), enums fiscais (IndicadorOperacao,ModeloDocumento), campos (IndOper,VlDoc), tipos top-level (ArquivoEfdContribuicoes,BlocoC). - Inglês para verbos, factories estáticos e predicados booleanos:
Cnpj.Create(...),parser.ReadAsync(...),parser.ReadStreamingAsync(...),gerador.WriteAsync(...),cfop.IsEntrada,inscricao.IsIsento,CodigosUf.IsValid(uf). - Inglês também para infraestrutura técnica universal:
Parser,Generator,Reader,Writer,Builder, tipos da BCL, palavras-chave de C#. - Encoding dos
.txtSPED: Latin1 / Windows-1252. UTF-8 apenas para os pacotes XML (família NF-e). - Commits seguem Conventional Commits
(prefixo em inglês:
feat:,fix:,refactor:...) com corpo em português.
Detalhes completos em ARCHITECTURE.md §1.3 e §13.
Licença
MIT — © 2026 TecnoFisc Micro Sistemas.
Contribuição
Repositório em fase inicial e mantido internamente. Issues e pull requests externos
ainda não são aceitos. Para colaboradores internos, leia primeiro
ARCHITECTURE.md (documento mestre) e CLAUDE.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on TecnoFisc.Sped.Core:
| Package | Downloads |
|---|---|
|
TecnoFisc.Sped.EfdContribuicoes
Implementação .NET do layout EFD Contribuições (PIS/COFINS) — leitura, escrita e modelo tipado dos registros publicados pela Receita Federal. |
|
|
TecnoFisc.Sped.EfdIcmsIpi
Implementação .NET do layout EFD ICMS-IPI (Escrituração Fiscal Digital) — leitura, escrita e modelo tipado dos registros publicados pela Receita Federal. Cobre o leiaute V015 (Nota Técnica EFD ICMS-IPI nº 2020.001, vigente a partir de janeiro/2021) dentro da janela fiscal de 5 anos. Incrementos posteriores (V016+) entram conforme novas Notas Técnicas são publicadas. |
GitHub repositories
This package is not used by any popular GitHub repositories.