Convertitore: una riga nella sua forma più semplice, qualsiasi ambiente nella sua massima flessibilità
Il pacchetto converter di Aspose.Cells for Go via C++ Toolkits riduce ogni esigenza di “convertire un foglio di calcolo in un altro formato” a una singola funzione di ingresso:
converter.Convert(source, saveOption, sink) error
Ha solo tre parametri e ciascuno risponde esattamente a una domanda:
| Parametro | Tipo | Domanda a cui risponde | Valori tipici |
|---|---|---|---|
source | datasource.DataSource | Da dove proviene l’input? | FilePathSource(path), BytesSource(data), NewReaderSource(r) |
saveOption | saveoptions.SaveOption | Quale formato di output, come è configurato? | formats.Get("pdf") per impostazioni predefinite per nome, oppure pdf.New(pdf.WithOnePagePerSheet(true)) per controllo fine |
sink | datasource.DataSink | Dove va l’output? | FilePathSink(path), &BytesSink{}, NewWriterSink(w) |
Per lo stile più conciso, usa le impostazioni predefinite su tutti e tre gli assi; per lo stile più flessibile, regola ogni manopola indipendentemente. Poiché i tre assi sono indipendenti, lo stesso Convert si adatta naturalmente a file, memoria, HTTP e ambienti batch. (Esiste anche un one‑liner legacy, ConvertSpreadsheetToFile, per il caso semplice file→file — confrontato nella sezione 1 più sotto.) Il resto di questo articolo passa dal più conciso al più flessibile, ampliando lo snippet precedente a ogni passo invece di passare a un’API diversa.
1. Il più semplice: una chiamata per un formato
1.1 Una one-liner integrata file→file: ConvertSpreadsheetToFile
Il pacchetto fornisce anche una voce più vecchia e ancora più breve per il classico caso “converti questo file in quello”. Tutto ciò che serve sono due percorsi:
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)
}
}
Deprecato.
ConvertSpreadsheetToFileè un involucro leggero mantenuto per compatibilità retroattiva; il nuovo codice è indirizzato aconverter.Convertqui sotto. Per il caso file→file i due sono esattamente equivalenti — questo è tutto ciò che faConvertSpreadsheetToFile.
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 la forma Convert sopra producono risultati identici; ciò che differisce è lo scenario, come mostrato di seguito.
1.2 Il one-liner consigliato: Convert con impostazioni predefinite
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)
}
}
Tutti e tre i parametri assumono il valore predefinito: input = un file, format = pdf.New() con zero configurazione, output = un file. Questo è il formato “più conciso” — nessun os.Open/os.Create manuale, nessuna allocazione di oggetti, nessuna chiusura di handle; la sorgente/destinazione gestiscono le risorse per te.
1.3 Le due forme file→file confrontate
ConvertSpreadsheetToFile(in, out) | converter.Convert(source, opt, sink) | |
|---|---|---|
| Input | solo un percorso file | qualsiasi DataSource: percorso, []byte, o lettore |
| Output | solo un percorso file | qualsiasi DataSink: percorso, byte, o io.Writer |
| Formato di output | sempre inferito dall’estensione, solo valori predefiniti | qualsiasi saveOption: predefinito o ottimizzazione specifica del formato |
| Importazione aggiuntiva | richiede la registrazione del formato (_ "…/register", o il sottopacchetto corrispondente saveoptions/*) | nessuno, quando si passa un costruttore come pdf.New() |
| Stato | wrapper sottile deprecato (stabile, mantenuto per compatibilità) | il singolo punto di ingresso documentato per il nuovo codice |
Stesso file→esito del file, due scenari diversi:
ConvertSpreadsheetToFile— hai letteralmente due percorsi e sei soddisfatto delle impostazioni predefinite del motore per il formato di destinazione. Ideale per script di conversione una tantum, batch di migrazione e helper di test. Il suo prezzo: l’input, l’output e le impostazioni non possono mai uscire dalla forma “file path + defaults” — ed è deprecato.converter.Convert— vuoi lo stesso one-liner, ma uno dei tre argomenti può essere sostituibile: domani l’input è un[]bytecaricato, la destinazione richiedepdf.WithOnePagePerSheet(true), o l’output deve andare direttamente in una risposta HTTP. Questi sono esattamente gli scenari delle sezioni 3 e 4 — scrivilo una volta conConvert, e ogni modifica è una modifica a un singolo argomento.
2. Il più semplice × N: una funzione per tutti i 32 formati
Il livello successivo di concisione consiste nell’utilizzare la stessa funzione indipendentemente dal formato di destinazione. Poiché saveOption può essere calcolato dall’estensione del file di output, estrarre tale inferenza produce un “convertitore universale di file”:
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")
}
L’uso rimane identico — cambia solo l’estensione dell’output:
$ 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
Che cos’è quell’importazione vuota _ "…/register"?
Ci sono due modi per ottenere un saveOption; questo è l’unico concetto che lo stile “most concise” deve comprendere:
- Cercalo nel registro per nome del formato (
formats.Get): l’estensione deve essere presente nel registroformats. Ogni sottopacchettosaveoptions/*si registra nel proprioinit(), ma solo quando importato. Importa i sottopacchetti di cui hai bisogno uno per volta (ad esempio solopdf, se converti in PDF), oppure importa vuoto…/registeruna volta, che registra tutti i 32 formati in una volta — il “convertitore universale” sopra si basa su quella singola riga. - Chiama direttamente un costruttore (
pdf.New(),markdown.New()): aggira il registro, non è necessario importareregister; il costo è una riga di import per ogni formato che utilizzi.
In breve: usa _ "…/register" solo quando risolvi tramite formats.Get + l’estensione di output; passare direttamente un costruttore non richiede nulla di extra. L’importazione vuota è innocua ed è sempre presente negli esempi ufficiali.
3. Il più flessibile: ruota ogni manopola indipendentemente
Quando la necessità supera “file to file with default settings”, non si modifica l’API — i tre parametri Convert sono intercambiabili in modo indipendente.
1. Input (origine): da un file, in memoria, a qualsiasi stream
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: il motore sottostante richiede l’accesso casuale all’intero contenuto, quindi
ReaderSourcememorizza l’intero flusso in buffer al primo accesso; ogni successivoOpenfornisce una copia di quel buffer. Usalo con fiducia per HTTP, ma sappi che non è una vera “conversione in streaming”.
2. Formato (saveOption): predefiniti, o ottimizzati
| Scenario | Stile di scrittura | Perché |
|---|---|---|
| Alcuni formato con impostazioni predefinite | formats.Get("pdf") | ricercato per estensione; non sensibile al maiuscolo/minuscolo; nil se non registrato |
| Un formato con opzioni specifiche del formato | pdf.New(pdf.WithOnePagePerSheet(true)) | opzioni funzionali |
| Impostazioni predefinite, formato esplicito | ooxml.New() / csv.New() / … | un costruttore senza argomenti per formato |
| Un formato privato personalizzato | formats.Register("fmt", factory) | collegare al registro — vedi docs/register.md |
Le opzioni funzionali compaiono solo nei formati che le supportano: una pagina per foglio di lavoro in PDF è WithOnePagePerSheet; le immagini in linea in HTML sono WithExportImagesAsBase64; TSV è formats.Get("tsv"). Le opzioni hanno semantica puntatore: omettere = il valore predefinito del motore; passare esplicitamente false conta comunque.
3. Output (sink): un file, byte o un 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 sono le due chiavi per la “massima flessibilità”: consentono al risultato della conversione di saltare completamente il disco e di fluire direttamente in una risposta HTTP, storage di oggetti, un file zip, ecc. Tutti e tre sono implementazioni diverse dello stesso parametro sink, quindi qualsiasi cosa accetti []byte o un io.Writer può essere collegata al convertitore.
4. Esempi in ambiente reale: un Convert, molte forme
A. Converti in memoria; l’endpoint di download trasmette PDF
Lo scenario comune lato server — un utente carica un file xlsx, il endpoint restituisce un PDF, senza file temporanei:
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())
}
Per distribuire CSV / Excel / HTML invece, sostituisci solo il saveOption (ad esempio formats.Get("csv")); nient’altro cambia.
B. Leggi una volta, esporta in batch in molti formati
Leggi l’input una sola volta, quindi riutilizzalo tramite BytesSource per un numero qualsiasi di output — ideale per “esporta ogni rapporto”.
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. “Salva con nome” nella famiglia di fogli di calcolo (migrazione / compatibilità)
Migrazione di formato all’interno della famiglia dei fogli di calcolo, ad es. xlsx → xls, xlsx → xlsb, xlsx → ods, e i modelli xltx/xltm — ancora un unico Convert, solo il saveOption cambia:
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. Regola le opzioni per formato, solo quando necessario
Le opzioni funzionali compaiono quando hai bisogno di un controllo fine — nota che ogni chiamata qui sotto è reale e correttamente tipizzata:
// 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" / …
Suggerimento: per output a file singolo come CSV/HTML/immagine, il motore esporta solo il foglio di lavoro che considera “attivo” per impostazione predefinita. Per controllare l’ambito, usa le opzioni specifiche del formato — ad es.
html.WithExportActiveWorksheetOnly(true)(solo il foglio attivo?),html.WithShowAllSheets(true), ocsv.WithExportAllSheets(true). La qualità dell’immagine a livello di pixel, la scelta esatta dei fogli da renderizzare e altri controlli avanzati esistono ancora a livello del motore, ma l’attuale pacchettoimageespone solo l’opzioneWithImageType— ricorre al binding sottostante se ti serve di più; il toolkit continuerà a incorporare opzioni nel tempo.
E. Conversione batch su una directory
L’operazione quotidiana “converti questa cartella di Excel in PDF” diventa molto breve con l’inferenza dell’estensione:
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. Classificazione degli errori
Gli errori del convertitore sono errori sentinel classificabili; abbinali a errors.Is per una gestione precisa:
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() restituisce ogni estensione attualmente registrata (ordinata, thread‑safe) — utile per generare un elenco di “formati supportati” o un suggerimento di errore.
5. Formati supportati a colpo d’occhio (32 registrati per impostazione predefinita)
| Famiglia | Estensioni di output | Pacchetto di ottimizzazione |
|---|---|---|
| Excel | xlsx xlsm xltx xltm xls xlsb | saveoptions/ooxml, xls, xlsb |
| OpenDocument | ods xml dif dbf | saveoptions/ods, xml, dif, dbf |
| Testo / dati | csv txt tsv json sql | saveoptions/csv, txt, json, sqlScript |
| Documenti / layout | pdf docx pptx xps pcl epub | saveoptions/pdf, docx, pptx, xps, pcl, ebook |
| Web | html md | saveoptions/html, markdown |
| Immagini | png jpg jpeg gif bmp svg emf tif tiff | saveoptions/image |
Per mantenere il binario snello, importa solo i sottopacchetti che utilizzi (ad esempio pdf); per comodità o per un dispatch generico, importa in bianco …/register. L’importazione di un sottopacchetto attiva la sua registrazione; le ricerche nel registro non distinguono tra maiuscole e minuscole; un’estensione non registrata restituisce nil (non un errore), lasciando la decisione di fallback al chiamante.
6. Best practice e avvertenze
- Un unico punto di ingresso — non reinventarlo. File-to-file utilizza
Convert(FilePathSource, formats.Get(ext)/constructor, FilePathSink); cambia i sink solo quando ti servono byte o uno stream. Non scrivere manualmenteos.Open → ReadAll → … → os.WriteFile; la sorgente/sink gestiscono le risorse e creano le directory genitore per te. - Concorrenza e licenze. Il motore sottostante è nativo: non condividere un oggetto
SaveOption/workbook tra goroutine nello stesso processo; per lavori in blocco elabora i file in sequenza o parallelizza tra processi. La build di valutazione limita i caricamenti (circa cento caricamentiNewWorkbook_Streamper processo) — per benchmark di grandi dimensioni, riavvia il processo per azzerare il contatore. - Leggi l’input una sola volta, poi riutilizzalo. Per generare diversi formati da un unico input, prima usa
os.ReadFileper caricarlo in un[]bytee converti ripetutamente conBytesSource, evitando letture ripetute dal disco e ricaricamenti. - Gli stream vengono bufferizzati.
NewReaderSourceeffettua il buffering al primo accesso, quindi è adatto a input una tantum come il corpo di una richiesta HTTP, non a streaming vero di file molto grandi (usaFilePathSourceche punta direttamente al disco per questi casi). - Sappi chi decide il layout dell’output.
Convertè “un input → un file di output”. Se ti serve un file per foglio di lavoro o un zip, utilizzamanipulator.Splitcon unFolderSink/ZipSink— non forzarlo tramiteConvert.
