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ètreTypeQuestion à laquelle il répondValeurs typiques
sourcedatasource.DataSourceD’où provient l’entrée ?FilePathSource(path), BytesSource(data), NewReaderSource(r)
saveOptionsaveoptions.SaveOptionQuel 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
sinkdatasource.DataSinkOù 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. ConvertSpreadsheetToFile est un petit wrapper conservé pour la compatibilité ascendante ; le nouveau code doit être dirigé vers converter.Convert ci‑dessous. Pour le cas fichier→fichier, les deux sont exactement équivalents — c’est tout ce que fait ConvertSpreadsheetToFile.

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éeun chemin de fichier uniquementtout DataSource : chemin, []byte, ou lecteur
Sortieun chemin de fichier uniquementtout DataSink : chemin, octets, ou io.Writer
Format de sortietoujours déduit de l’extension, uniquement les valeurs par défauttout saveOption : valeur par défaut ou réglage spécifique au format
Import supplémentairenécessite l’enregistrement du format (_ \"…/register\", ou le sous‑package correspondant saveoptions/*)aucun, lorsque vous passez un constructeur comme pdf.New()
Statutwrapper 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 []byte d’upload, la cible nécessite pdf.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 avec Convert, 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 registre formats. Chaque sous‑package saveoptions/* s’enregistre dans son propre init(), mais uniquement lorsqu’il est importé. Importez les sous‑packages dont vous avez besoin un par un (par exemple seulement pdf si vous convertissez en PDF), ou importez en blanc …/register une 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 import register n’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 ReaderSource met en mémoire tampon le flux entièrement lors du premier accès ; chaque Open ulté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

ScenarioWriting styleWhy
Un format avec les paramètres par défautformats.Get("pdf")recherché par extension ; insensible à la casse ; nil si non enregistré
Un format avec des options spécifiques au formatpdf.New(pdf.WithOnePagePerSheet(true))options fonctionnelles
Paramètres par défaut, format expliciteooxml.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), ou csv.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 package image actuel n’expose que le commutateur WithImageType — 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)

FamilleExtensions de sortiePackage d’optimisation
Excelxlsx xlsm xltx xltm xls xlsbsaveoptions/ooxml, xls, xlsb
OpenDocumentods xml dif dbfsaveoptions/ods, xml, dif, dbf
Texte / donnéescsv txt tsv json sqlsaveoptions/csv, txt, json, sqlScript
Documents / mise en pagepdf docx pptx xps pcl epubsaveoptions/pdf, docx, pptx, xps, pcl, ebook
Webhtml mdsaveoptions/html, markdown
Imagespng jpg jpeg gif bmp svg emf tif tiffsaveoptions/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

  1. 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 manuellement os.Open → ReadAll → … → os.WriteFile ; la source/le sink gèrent les ressources et créent les répertoires parents pour vous.

  2. 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 chargements NewWorkbook_Stream par processus) — pour de gros benchmarks, redémarrez le processus afin de réinitialiser le compteur.

  3. 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.ReadFile pour la placer dans un []byte puis convertissez à plusieurs reprises avec BytesSource, évitant ainsi des lectures disque et des rechargements répétés.

  4. Les flux sont mis en mémoire tampon. NewReaderSource met 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 (utilisez FilePathSource pointant directement sur le disque dans ce cas).

  5. Sachez qui décide de la mise en page de la sortie. Convert est « une entrée → un fichier de sortie ». Si vous avez besoin d’un fichier par feuille de calcul ou d’un zip, utilisez manipulator.Split avec un FolderSink/ZipSink — ne le forcez pas via Convert.