Convertisseur : une ligne dans sa forme la plus simple, tout environnement dans sa forme la plus flexible
Le package converter d’Aspose.Cells for Go via C++ Toolkits réduit chaque besoin de “transformer une feuille de calcul en un autre format” à une fonction d’entrée :
converter.Convert(source, saveOption, sink) error
Il n’a que trois paramètres, et chacun répond exactement à une question :
| Paramètre | Type | Question à laquelle il répond | Valeurs typiques |
|---|---|---|---|
source | datasource.DataSource | D’où provient l’entrée ? | FilePathSource(path), BytesSource(data), NewReaderSource(r) |
saveOption | saveoptions.SaveOption | Quel format de sortie, comment le régler ? | formats.Get("pdf") pour les valeurs par défaut par nom, ou pdf.New(pdf.WithOnePagePerSheet(true)) pour un contrôle fin |
sink | datasource.DataSink | Où va la sortie ? | FilePathSink(path), &BytesSink{}, NewWriterSink(w) |
Pour le style le plus concis, prenez la valeur par défaut sur les trois axes ; pour le plus flexible, tournez chaque bouton indépendamment. Comme les trois axes sont indépendants, le même Convert s’adapte naturellement aux environnements fichier, mémoire, HTTP et batch. (Il existe également un one‑liner hérité, ConvertSpreadsheetToFile, pour le cas simple fichier→fichier — comparé dans la section 1 ci‑dessous.) Le reste de cet article passe du plus concis au plus flexible, en développant le fragment précédent à chaque étape plutôt qu’en passant à une API différente.
1. Le plus simple : un appel pour un format
1.1 Une ligne de commande intégrée fichier→fichier : ConvertSpreadsheetToFile
Le package fournit également une entrée plus ancienne et encore plus courte pour le cas classique “convertir ce fichier en ce fichier”. Il suffit de deux chemins :
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)
}
}
Obsolète.
ConvertSpreadsheetToFileest un petit wrapper conservé pour la compatibilité ascendante ; le nouveau code doit être dirigé versconverter.Convertci‑dessous. Pour le cas fichier→fichier, les deux sont exactement équivalents — c’est tout ce que faitConvertSpreadsheetToFile.
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 et la forme Convert ci‑dessus produisent des résultats identiques ; ce qui diffère, c’est le scénario, comme indiqué ci‑après.
1.2 Le one-liner recommandé : Convert avec les valeurs par défaut
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)
}
}
Les trois paramètres prennent leurs valeurs par défaut : input = un fichier, format = pdf.New() avec zéro configuration, output = un fichier. C’est la forme la plus concise — pas de os.Open/os.Create manuels, pas d’allocation d’objet, pas de fermeture de handle ; la source/sink gèrent les ressources pour vous.
1.3 Les deux formes fichier→fichier comparées
ConvertSpreadsheetToFile(in, out) | converter.Convert(source, opt, sink) | |
|---|---|---|
| Entrée | un chemin de fichier uniquement | tout DataSource : chemin, []byte, ou lecteur |
| Sortie | un chemin de fichier uniquement | tout DataSink : chemin, octets, ou io.Writer |
| Format de sortie | toujours déduit de l’extension, uniquement les valeurs par défaut | tout saveOption : valeur par défaut ou réglage spécifique au format |
| Import supplémentaire | nécessite l’enregistrement du format (_ \"…/register\", ou le sous‑package correspondant saveoptions/*) | aucun, lorsque vous passez un constructeur comme pdf.New() |
| Statut | wrapper mince obsolète (stable, conservé pour la compatibilité) | le point d’entrée unique documenté pour le nouveau code |
Même fichier→résultat du fichier, deux scénarios différents :
ConvertSpreadsheetToFile— vous avez littéralement deux chemins et êtes satisfait des paramètres par défaut du moteur pour le format cible. Idéal pour les scripts de conversion ponctuels, les lots de migration et les aides de test. Son prix : l’entrée, la sortie et les paramètres ne peuvent jamais sortir de la forme « chemin de fichier + paramètres par défaut » — et il est obsolète.converter.Convert— vous voulez la même ligne unique, mais l’un des trois arguments reste remplaçable : demain l’entrée sera un[]byted’upload, la cible nécessitepdf.WithOnePagePerSheet(true), ou la sortie doit aller directement dans une réponse HTTP. Ce sont exactement les scénarios des sections 3 et 4 — écrivez‑le une fois avecConvert, et chaque changement devient une modification d’un seul argument.
2. Le plus simple × N : une fonction pour les 32 formats
Le niveau suivant de concision consiste à utiliser la même fonction quel que soit le format ciblé. Parce que saveOption peut être calculé à partir de l’extension du fichier de sortie, extraire cette inférence donne un “convertisseur de fichiers universel” :
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’utilisation reste identique — seule l’extension de sortie change :
$ 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
Qu’est‑ce que cet import vide _ "…/register" ?
Il existe deux façons d’obtenir un saveOption; c’est le seul concept que le style “most concise” doit comprendre :
- Recherchez-le dans le registre par nom de format (
formats.Get) : l’extension doit être présente dans le registreformats. Chaque sous‑packagesaveoptions/*s’enregistre dans son propreinit(), mais uniquement lorsqu’il est importé. Importez les sous‑packages dont vous avez besoin un par un (par exemple seulementpdfsi vous convertissez en PDF), ou importez en blanc…/registerune fois, ce qui enregistre les 32 formats en une seule fois — le « convertisseur universel » ci‑dessus repose sur cette ligne unique. - Appelez directement un constructeur (
pdf.New(),markdown.New()) : contourne le registre, aucun importregistern’est nécessaire ; le coût est une ligne d’importation par format que vous utilisez.
En bref : n’utilisez _ "…/register" que lorsque vous résolvez via formats.Get + l’extension de sortie ; passer un constructeur directement ne nécessite rien de plus. L’importation vide est inoffensive et est toujours présente dans les exemples officiels.
3. Le plus flexible : tourner chaque bouton indépendamment
Lorsque le besoin dépasse “file to file with default settings”, vous ne modifiez pas l’API — les trois paramètres Convert sont interchangeables de façon indépendante.
1. Entrée (source): depuis un fichier, en mémoire, vers n’importe quel flux
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, …)
Note : le moteur sous‑jacent nécessite un accès aléatoire à l’ensemble du contenu, donc
ReaderSourcemet en mémoire tampon le flux entièrement lors du premier accès ; chaqueOpenultérieur fournit une copie de ce tampon. Utilisez‑le en toute confiance pour HTTP, sachez simplement qu’il ne s’agit pas d’une véritable “conversion en streaming”.
2. Format (saveOption) : valeurs par défaut ou ajustées
| Scenario | Writing style | Why |
|---|---|---|
| Un format avec les paramètres par défaut | formats.Get("pdf") | recherché par extension ; insensible à la casse ; nil si non enregistré |
| Un format avec des options spécifiques au format | pdf.New(pdf.WithOnePagePerSheet(true)) | options fonctionnelles |
| Paramètres par défaut, format explicite | ooxml.New() / csv.New() / … | un constructeur sans arguments par format |
| Un format privé personnalisé | formats.Register("fmt", factory) | brancher dans le registre — voir docs/register.md |
Les options fonctionnelles n’apparaissent que sur les formats qui les possèdent : une page par feuille de calcul dans le PDF est WithOnePagePerSheet ; les images en ligne dans le HTML sont WithExportImagesAsBase64 ; le TSV est formats.Get("tsv"). Les options sont sémantiques de pointeur : omettre = la valeur par défaut du moteur ; passer false explicitement compte également.
3. Sortie (sink) : un fichier, des octets ou 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 et WriterSink sont les deux clés de la « plus grande flexibilité » : ils permettent au résultat de conversion de sauter le disque entièrement et de s’écouler directement dans une réponse HTTP, un stockage d’objets, un zip, etc. Les trois sont différentes implémentations du même paramètre sink, de sorte que tout ce qui accepte []byte ou un io.Writer peut être branché au convertisseur.
4. Exemples en environnement réel : un Convert, plusieurs formes
A. Convertir en mémoire ; le point de terminaison de téléchargement diffuse le PDF
Le scénario serveur le plus courant — un utilisateur télécharge un fichier xlsx, le point de terminaison renvoie un PDF, sans fichiers temporaires :
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())
}
Pour fournir CSV / Excel / HTML à la place, remplacez uniquement le saveOption (par exemple formats.Get("csv")) ; rien d’autre ne change.
B. Lire une fois, exporter en lot vers de nombreux formats
Lisez l’entrée une seule fois, puis réutilisez‑la via BytesSource pour n’importe quel nombre de sorties — idéal pour “exporter chaque rapport” :
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. “Enregistrer sous” dans la famille des feuilles de calcul (migration / compatibilité)
Migration de format au sein de la famille des feuilles de calcul, par ex. xlsx → xls, xlsx → xlsb, xlsx → ods, et les modèles xltx/xltm — toujours un Convert, seul le saveOption change :
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. Ajuster les options par format, uniquement si nécessaire
Les options fonctionnelles apparaissent lorsque vous avez besoin d’un contrôle fin — notez que chaque appel ci‑dessous est réel et correctement typé :
// 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" / …
Astuce : pour les sorties d’un seul fichier telles que CSV/HTML/image, le moteur n’exporte que la feuille de calcul qu’il considère « active » par défaut. Pour contrôler la portée, utilisez les options propres au format — par ex.
html.WithExportActiveWorksheetOnly(true)(seulement la feuille active ?),html.WithShowAllSheets(true), oucsv.WithExportAllSheets(true). La qualité d’image au niveau du pixel, le choix précis des feuilles à rendre, et d’autres contrôles approfondis existent toujours au niveau du moteur, mais le packageimageactuel n’expose que le commutateurWithImageType— accédez à la liaison sous‑jacente si vous avez besoin de plus ; la boîte à outils continuera d’ajouter des options au fil du temps.
E. Conversion par lots d’un répertoire
La tâche quotidienne “convert this folder of Excels to PDF” devient très courte avec l’inférence d’extension :
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. Classification des erreurs
Les erreurs du convertisseur sont des erreurs sentinelles classifiables ; associez‑les à errors.Is pour une gestion précise :
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() renvoie chaque extension actuellement enregistrée (triée, sûre pour la concurrence) — pratique pour générer une liste des “formats pris en charge” ou un indice d’erreur.
5. Formats pris en charge en un coup d’œil (32 enregistrés par défaut)
| Famille | Extensions de sortie | Package d’optimisation |
|---|---|---|
| Excel | xlsx xlsm xltx xltm xls xlsb | saveoptions/ooxml, xls, xlsb |
| OpenDocument | ods xml dif dbf | saveoptions/ods, xml, dif, dbf |
| Texte / données | csv txt tsv json sql | saveoptions/csv, txt, json, sqlScript |
| Documents / mise en page | pdf docx pptx xps pcl epub | saveoptions/pdf, docx, pptx, xps, pcl, ebook |
| Web | html md | saveoptions/html, markdown |
| Images | png jpg jpeg gif bmp svg emf tif tiff | saveoptions/image |
Pour garder le binaire léger, importez uniquement les sous‑packages que vous utilisez (comme pdf) ; pour plus de commodité ou un dispatch générique, effectuez un import vide …/register. L’import d’un sous‑package déclenche son enregistrement ; les recherches dans le registre sont insensibles à la casse ; une extension non enregistrée renvoie nil (pas une erreur), laissant la décision de repli à l’appelant.
6. Bonnes pratiques et mises en garde
Un point d’entrée unique — ne le réinventez pas. File-to-file utilise
Convert(FilePathSource, formats.Get(ext)/constructor, FilePathSink); ne changez les sinks que lorsque vous avez besoin d’octets ou d’un flux. Ne créez pas manuellementos.Open → ReadAll → … → os.WriteFile; la source/le sink gèrent les ressources et créent les répertoires parents pour vous.Concurrence et licence. Le moteur sous-jacent est natif : ne partagez pas un même objet
SaveOption/workbook entre des goroutines dans le même processus ; pour un travail en masse, traitez les fichiers séquentiellement ou parallélisez entre processus. La version d’évaluation limite les chargements (environ cent chargementsNewWorkbook_Streampar processus) — pour de gros benchmarks, redémarrez le processus afin de réinitialiser le compteur.Lisez l’entrée une fois, puis réutilisez‑la. Pour générer plusieurs formats à partir d’une même entrée, utilisez d’abord
os.ReadFilepour la placer dans un[]bytepuis convertissez à plusieurs reprises avecBytesSource, évitant ainsi des lectures disque et des rechargements répétés.Les flux sont mis en mémoire tampon.
NewReaderSourcemet en tampon lors du premier accès, il convient donc aux entrées ponctuelles comme le corps d’une requête HTTP, mais pas au streaming réel de fichiers très volumineux (utilisezFilePathSourcepointant directement sur le disque dans ce cas).Sachez qui décide de la mise en page de la sortie.
Convertest « une entrée → un fichier de sortie ». Si vous avez besoin d’un fichier par feuille de calcul ou d’un zip, utilisezmanipulator.Splitavec unFolderSink/ZipSink— ne le forcez pas viaConvert.
