Conversor: uma linha em sua forma mais simples, qualquer ambiente em sua forma mais flexível
O pacote converter do Aspose.Cells for Go via C++ Toolkits reduz cada necessidade de “transformar uma planilha em outro formato” a uma única função de entrada:
converter.Convert(source, saveOption, sink) error
Ele tem apenas três parâmetros, e cada um responde exatamente a uma pergunta:
| Parâmetro | Tipo | Pergunta que responde | Valores típicos |
|---|---|---|---|
source | datasource.DataSource | De onde vem a entrada? | FilePathSource(path), BytesSource(data), NewReaderSource(r) |
saveOption | saveoptions.SaveOption | Qual o formato de saída e como está ajustado? | formats.Get("pdf") para padrões por nome, ou pdf.New(pdf.WithOnePagePerSheet(true)) para controle fino |
sink | datasource.DataSink | Para onde a saída vai? | FilePathSink(path), &BytesSink{}, NewWriterSink(w) |
Para o estilo mais conciso, use o padrão em todos os três eixos; para o mais flexível, ajuste cada controle independentemente. Como os três eixos são independentes, o mesmo Convert se adapta naturalmente a ambientes de arquivo, memória, HTTP e lote. (Existe também um one‑liner legado, ConvertSpreadsheetToFile, para o caso simples de arquivo→arquivo — comparado na seção 1 abaixo.) O restante deste artigo passa do mais conciso ao mais flexível, expandindo o trecho anterior a cada passo em vez de mudar para uma API diferente.
1. O mais simples: uma chamada para um formato
1.1 Um one-liner interno de arquivo→arquivo: ConvertSpreadsheetToFile
O pacote também inclui uma entrada mais antiga e ainda mais curta para o caso clássico “converter este arquivo naquele arquivo”. Tudo o que é necessário são dois caminhos:
package main
import (
"log"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/core"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/converter"
_ "github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/register" // registers every output format
)
func main() {
defer core.Cleanup()
// Both ends are files; the output format is inferred from the extension.
if err := converter.ConvertSpreadsheetToFile("input.xlsx", "output.pdf"); err != nil {
log.Fatal(err)
}
}
Obsoleto.
ConvertSpreadsheetToFileé um wrapper fino mantido para compatibilidade retroativa; novo código é direcionado paraconverter.Convertabaixo. Para o caso arquivo→arquivo, os dois são exatamente equivalentes — isso é tudo queConvertSpreadsheetToFilefaz:
opt := formats.Get(strings.TrimPrefix(filepath.Ext("output.pdf"), ".")) // "pdf"
converter.Convert(
datasource.FilePathSource("input.xlsx"), // input: a file
opt, // format: taken from the extension
datasource.FilePathSink("output.pdf"), // output: a file
)
ConvertSpreadsheetToFile e a forma Convert acima produzem resultados idênticos; o que difere é o cenário, como comparado a seguir.
1.2 A linha única recomendada: Convert com padrões
package main
import (
"log"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/core"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/converter"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/datasource"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/saveoptions/pdf"
)
func main() {
defer core.Cleanup()
if err := converter.Convert(
datasource.FilePathSource("input.xlsx"), // input: a file
pdf.New(), // format: PDF, all defaults
datasource.FilePathSink("output.pdf"), // output: a file
); err != nil {
log.Fatal(err)
}
}
Todos os três parâmetros assumem seus valores padrão: input = um arquivo, format = pdf.New() sem nenhuma configuração, output = um arquivo. Essa é a forma “mais concisa” — sem os.Open/os.Create manual, sem alocação de objeto, sem fechamento de manipulador; a fonte/destino gerenciam os recursos para você.
1.3 As duas formas file→file comparadas
ConvertSpreadsheetToFile(in, out) | converter.Convert(source, opt, sink) | |
|---|---|---|
| Entrada | apenas um caminho de arquivo | qualquer DataSource: caminho, []byte, ou leitor |
| Saída | apenas um caminho de arquivo | qualquer DataSink: caminho, bytes, ou io.Writer |
| Formato de saída | sempre inferido a partir da extensão, apenas padrões | qualquer saveOption: padrão ou ajuste específico ao formato |
| Importação extra | necessita que o formato seja registrado (_ "…/register", ou o subpacote correspondente saveoptions/*) | nenhum, quando você passa um construtor como pdf.New() |
| Status | wrapper fino obsoleto (estável, mantido para compatibilidade) | o ponto de entrada único documentado para novo código |
Mesmo arquivo→resultado do arquivo, dois cenários diferentes:
ConvertSpreadsheetToFile— você literalmente tem dois caminhos e está satisfeito com as configurações padrão do mecanismo para o formato de destino. Ideal para scripts de conversão pontuais, lotes de migração e auxiliares de teste. Seu custo: a entrada, a saída e as configurações nunca podem sair da forma “caminho do arquivo + padrões” — e está obsoleto.converter.Convert— você quer a mesma linha única, mas qualquer um dos três argumentos pode ser substituído: amanhã a entrada será um[]bytede upload, o destino precisa depdf.WithOnePagePerSheet(true), ou a saída deve ir direto para uma resposta HTTP. Esses são exatamente os cenários das seções 3 e 4 — escreva uma vez comConvert, e cada mudança é uma edição de um argumento.
2. O mais simples × N: uma função para todos os 32 formatos
O próximo nível de concisão é usar a mesma função independentemente do formato que você deseja. Como saveOption pode ser calculado a partir da extensão do arquivo de saída, extrair essa inferência resulta em um “universal file converter”:
package main
import (
"errors"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/core"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/converter"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/datasource"
toolkiterrors "github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/errors"
"github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/formats"
_ "github.com/aspose-cells/aspose-cells-go-cpp-toolkits/v26/register" // registers every output format
)
// convert re-saves in as out; the output format is read from out's extension.
// The same code handles every built-in format (pdf/csv/html/md/xlsx/png/…).
// It is exactly what the deprecated ConvertSpreadsheetToFile does internally.
func convert(in, out string) error {
opt := formats.Get(strings.TrimPrefix(filepath.Ext(out), ".")) // ".pdf" -> "pdf"
if opt == nil {
return fmt.Errorf("%w: %q", toolkiterrors.ErrUnsupportedFormat, filepath.Ext(out))
}
return converter.Convert(
datasource.FilePathSource(in), // where the input comes from
opt, // what to produce: decided by the extension
datasource.FilePathSink(out), // where the output goes
)
}
func main() {
defer core.Cleanup()
if len(os.Args) != 3 {
log.Fatalf("usage: %s <input.xlsx> <output.ext>", os.Args[0])
}
if err := convert(os.Args[1], os.Args[2]); err != nil {
if errors.Is(err, toolkiterrors.ErrUnsupportedFormat) {
log.Printf("no registered output format for %q", filepath.Ext(os.Args[2]))
}
log.Fatal(err)
}
fmt.Println("done")
}
O uso permanece idêntico — apenas a extensão de saída muda:
$ go run . input.xlsx report.pdf # to PDF
$ go run . input.xlsx report.csv # to CSV
$ go run . input.xlsx report.html # to HTML
$ go run . input.xlsx notes.md # to Markdown
$ go run . input.xlsx sheet.png # to a PNG image
$ go run . input.xlsx legacy.xls # to legacy Excel
O que é essa importação vazia _ "…/register"?
Existem duas maneiras de obter um saveOption; este é o único conceito que o estilo “mais conciso” precisa entender:
- Consulte-o no registro pelo nome do formato (
formats.Get): a extensão deve estar presente no registroformats. Cada subpacotesaveoptions/*registra a si mesmo em seu próprioinit(), mas somente quando importado. Importe os subpacotes que você precisa um a um (apenaspdf, por exemplo, se você converte para PDF), ou importe em branco…/registeruma vez, o que registra todos os 32 formatos de uma só vez — o “conversor universal” acima depende dessa única linha. - Chame um construtor diretamente (
pdf.New(),markdown.New()): contorna o registro, não é necessário importarregister; o custo é uma linha de importação por formato que você usar.
Em resumo: use _ "…/register" apenas quando você resolve via formats.Get + a extensão de saída; passar um construtor diretamente não requer nada extra. A importação em branco é inofensiva e está sempre presente nos exemplos oficiais.
3. O mais flexível: ajuste cada botão independentemente
Quando a necessidade vai além de “arquivo para arquivo com configurações padrão”, você não altera a API — os três parâmetros Convert podem ser trocados independentemente.
1. Entrada (origem): de um arquivo, para memória, para qualquer fluxo
datasource.FilePathSource("input.xlsx") // a file on disk
datasource.BytesSource(data) // []byte already in memory (downloads, cached reuse)
datasource.NewReaderSource(r.Body) // any io.Reader (HTTP body, compressed stream, …)
Nota: o mecanismo subjacente precisa de acesso aleatório a todo o conteúdo, portanto
ReaderSourcearmazena em buffer o fluxo completamente no primeiro acesso; cadaOpenposterior serve uma cópia desse buffer. Use‑o com confiança para HTTP, apenas saiba que não é uma verdadeira “conversão enquanto transmite”.
2. Formato (saveOption): padrões, ou ajustado
| Cenário | Estilo de escrita | Por quê |
|---|---|---|
| Algum formato com configurações padrão | formats.Get("pdf") | pesquisado por extensão; sem distinção entre maiúsculas e minúsculas; nil se não registrado |
| Um formato com opções específicas de formato | pdf.New(pdf.WithOnePagePerSheet(true)) | opções funcionais |
| Configurações padrão, formato explícito | ooxml.New() / csv.New() / … | um construtor sem argumentos por formato |
| Um formato privado personalizado | formats.Register("fmt", factory) | conectar ao registro — veja docs/register.md |
Opções funcionais aparecem apenas nos formatos que as possuem: uma página por planilha no PDF é WithOnePagePerSheet; imagens embutidas no HTML são WithExportImagesAsBase64; TSV é formats.Get("tsv"). As opções são semântica de ponteiro: omitir = o padrão do mecanismo; passar false explicitamente também conta.
3. Saída (sink): um arquivo, bytes ou um io.Writer
datasource.FilePathSink("output.pdf") // to disk (parent dirs are created)
&out // into memory; read it back with out.Bytes()
datasource.NewWriterSink(w) // straight into any io.Writer (http.ResponseWriter, buffer, socket)
BytesSink e WriterSink são as duas chaves para “mais flexível”: eles permitem que o resultado da conversão ignore completamente o disco e flua diretamente para uma resposta HTTP, armazenamento de objetos, um zip, etc. Todos os três são implementações diferentes do mesmo parâmetro sink, portanto qualquer coisa que aceite []byte ou um io.Writer pode ser conectada ao conversor.
4. Exemplos em ambiente real: um Convert, muitas formas
A. Converter na memória; o endpoint de download transmite PDF
O cenário comum do lado do servidor — um usuário envia xlsx, o endpoint retorna PDF, sem arquivos temporários:
func handleExcelToPDF(w http.ResponseWriter, r *http.Request) {
var out datasource.BytesSink
if err := converter.Convert(
datasource.NewReaderSource(r.Body), // input: the request body
pdf.New(pdf.WithOnePagePerSheet(true)), // format: PDF, one page per sheet
&out, // output: memory
); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/pdf")
w.Header().Set("Content-Disposition", `attachment; filename="report.pdf"`)
_, _ = w.Write(out.Bytes())
}
Para entregar CSV / Excel / HTML em vez disso, troque apenas o saveOption (por exemplo formats.Get("csv")); nada mais muda.
B. Leia uma vez, exporte em lote para vários formatos
Leia a entrada uma única vez, depois reutilize-a através de BytesSource para qualquer número de saídas — ideal para “exportar cada relatório”:
data, err := os.ReadFile("input.xlsx")
if err != nil {
log.Fatal(err)
}
for _, ext := range []string{"pdf", "csv", "html", "json", "md"} {
var out datasource.BytesSink
if err := converter.Convert(datasource.BytesSource(data), formats.Get(ext), &out); err != nil {
log.Fatalf("%s: %v", ext, err)
}
if err := os.WriteFile("output."+ext, out.Bytes(), 0o644); err != nil {
log.Fatal(err)
}
}
C. “Salvar como” dentro da família de planilhas (migração / compatibilidade)
Migração de formato dentro da família de planilhas, por exemplo xlsx → xls, xlsx → xlsb, xlsx → ods, e os modelos xltx/xltm — ainda um Convert, apenas a saveOption muda:
src := datasource.FilePathSource("input.xlsx")
converter.Convert(src, formats.Get("xls"), datasource.FilePathSink("legacy.xls")) // legacy Excel
converter.Convert(src, formats.Get("xlsb"), datasource.FilePathSink("binary.xlsb")) // binary Excel
converter.Convert(src, formats.Get("ods"), datasource.FilePathSink("open.ods")) // OpenDocument
converter.Convert(src, formats.Get("xltx"), datasource.FilePathSink("template.xltx")) // template
D. Ajustar opções por formato, somente quando necessário
As opções funcionais aparecem quando você precisa de controle fino — observe que cada chamada abaixo é real e tipada corretamente:
// PDF: one page per worksheet + a compliance level
pdf.New(
pdf.WithOnePagePerSheet(true),
pdf.WithCompliance("pdf15"),
pdf.WithProducer("my-report-app"),
)
// HTML: single file, images inlined as base64, CSS prefix (avoids style clashes)
html.New(
html.WithSaveAsSingleFile(true),
html.WithExportImagesAsBase64(true),
html.WithCellCssPrefix("tbl_"),
)
// CSV: custom separator and encoding
// (the separator is a byte, and the encoding is a name — matched case- and
// punctuation-insensitively, so "UTF-8", "utf8" and "UTF8" are one name)
csv.New(
csv.WithSeparator(';'),
csv.WithEncoding("UTF-8"),
)
// Image: pick the type (the only switch the image package currently exposes)
image.New(image.WithImageType("png")) // or "jpg" / "svg" / "gif" / "tif" / …
Dica: para saídas de arquivo único, como CSV/HTML/imagem, o mecanismo exporta apenas a planilha que considera “ativa” por padrão. Para controlar o escopo, use as próprias opções do formato — por exemplo,
html.WithExportActiveWorksheetOnly(true)(apenas a planilha ativa?),html.WithShowAllSheets(true), oucsv.WithExportAllSheets(true). Qualidade de imagem em nível de pixel, escolha exata de quais planilhas são renderizadas e outros controles avançados ainda existem na camada do mecanismo, mas o pacoteimageatual expõe apenas a opçãoWithImageType— acesse a ligação subjacente se precisar de mais; o conjunto de ferramentas continuará incorporando opções ao longo do tempo.
E. Conversão em lote em um diretório
O trabalho cotidiano “converter esta pasta de Excels para PDF” torna-se muito curto com inferência de extensão:
func convertAll(inputDir, outputDir string) error {
if err := os.MkdirAll(outputDir, 0o755); err != nil {
return err
}
return filepath.Walk(inputDir, func(path string, info os.FileInfo, err error) error {
if err != nil || info.IsDir() {
return err
}
ext := strings.ToLower(filepath.Ext(path))
if ext != ".xlsx" && ext != ".xls" && ext != ".xlsm" && ext != ".csv" {
return nil
}
out := filepath.Join(outputDir, strings.TrimSuffix(filepath.Base(path), ext)+".pdf")
if err := convert(path, out); err != nil { // reuse the convert from section 2
return fmt.Errorf("convert %s: %w", path, err)
}
fmt.Printf("done: %s -> %s\n", path, out)
return nil
})
}
F. Classificando erros
Os erros do conversor são erros sentinela classificáveis; combine‑os com errors.Is para um tratamento preciso:
err := convert("in.xlsx", "out.xyz")
switch {
case errors.Is(err, toolkiterrors.ErrUnsupportedFormat):
log.Println("this extension has no registered output format")
case errors.Is(err, os.ErrNotExist):
log.Println("the input file does not exist")
default:
log.Printf("conversion failed: %v", err)
}
formats.List() retorna todas as extensões atualmente registradas (ordenadas, seguras para concorrência) — útil para gerar uma lista de “formatos suportados” ou uma dica de erro.
5. Formatos suportados em um relance (32 registrados por padrão)
| Família | Extensões de saída | Pacote de ajuste |
|---|---|---|
| Excel | xlsx xlsm xltx xltm xls xlsb | saveoptions/ooxml, xls, xlsb |
| OpenDocument | ods xml dif dbf | saveoptions/ods, xml, dif, dbf |
| Texto / dados | csv txt tsv json sql | saveoptions/csv, txt, json, sqlScript |
| Documentos / layout | pdf docx pptx xps pcl epub | saveoptions/pdf, docx, pptx, xps, pcl, ebook |
| Web | html md | saveoptions/html, markdown |
| Imagens | png jpg jpeg gif bmp svg emf tif tiff | saveoptions/image |
Para manter o binário enxuto, importe apenas os subpacotes que você usa (como pdf); para conveniência ou despacho genérico, faça um import em branco de …/register. Importar um subpacote aciona seu registro; as buscas no registro não diferenciam maiúsculas de minúsculas; uma extensão não registrada retorna nil (não é um erro), deixando a decisão de fallback ao chamador.
6. Melhores práticas e ressalvas
Um ponto de entrada — não o reinvente. File-to-file usa
Convert(FilePathSource, formats.Get(ext)/constructor, FilePathSink); troque os sinks somente quando precisar de bytes ou de um stream. Não implemente manualmenteos.Open → ReadAll → … → os.WriteFile; o source/sink gerencia recursos e cria diretórios pai para você.Concorrência e licenciamento. O mecanismo subjacente é nativo: não compartilhe um objeto
SaveOption/workbook entre goroutines no mesmo processo; para trabalhos em massa, processe os arquivos sequencialmente ou paralelize entre processos. A compilação de avaliação limita carregamentos (cerca de cem carregamentosNewWorkbook_Streampor processo) — para benchmarks grandes, reinicie o processo para resetar o contador.Leia a entrada uma vez, depois reutilize-a. Para gerar vários formatos a partir de uma única entrada, use
os.ReadFilepara carregá‑la em um[]byteprimeiro e converta repetidamente comBytesSource, evitando leituras repetidas do disco e recarregamentos.Streams são armazenados em buffer.
NewReaderSourcefaz buffer no primeiro acesso, portanto é adequado para entradas pontuais como o corpo de uma requisição HTTP, não para streaming real de arquivos muito grandes (useFilePathSourceapontando diretamente para o disco nesses casos).Saiba quem decide o layout de saída.
Converté “uma entrada → um arquivo de saída”. Se precisar de um arquivo por planilha ou de um zip, isso é feito commanipulator.Splitusando umFolderSink/ZipSink— não force isso através doConvert.
