Konverterare: en rad på sitt enklaste, vilken miljö som helst på sitt mest flexibla

Paketet converter i Aspose.Cells for Go via C++ Toolkits minskar varje “turn a spreadsheet into another format”-behov till en enda ingångsfunktion:

converter.Convert(source, saveOption, sink) error

Den har bara tre parametrar, och varje svarar på exakt en fråga:

ParameterTypFråga den besvararTypiska värden
sourcedatasource.DataSourceVar kommer indata ifrån?FilePathSource(path), BytesSource(data), NewReaderSource(r)
saveOptionsaveoptions.SaveOptionVad ska utdata vara, och hur finjusteras det?formats.Get("pdf") för standardinställningar efter namn, eller pdf.New(pdf.WithOnePagePerSheet(true)) för finjustering
sinkdatasource.DataSinkVar går utdata?FilePathSink(path), &BytesSink{}, NewWriterSink(w)

För den mest koncisa stilen, använd standardinställningarna på alla tre axlar; för den mest flexibla, vrid varje ratt oberoende. Eftersom de tre axlarna är oberoende passar samma Convert naturligt för fil-, minnes-, HTTP- och batch-miljöer. (Det finns också en äldre enradare, ConvertSpreadsheetToFile, för det enkla fil→fil-fallet — jämfört i avsnitt 1 nedan.) Resten av den här artikeln går från mest koncis till mest flexibel, och bygger vidare på föregående kodsnutt i varje steg istället för att byta till ett annat API.

1. Det enklaste: ett anrop för ett format

1.1 En inbyggd fil→fil enradig kod: ConvertSpreadsheetToFile

Paketet levereras också med en äldre, ännu kortare ingång för det klassiska fallet “konvertera den här filen till den där filen”. Allt som krävs är två sökvägar:

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)
	}
}

Föråldrad. ConvertSpreadsheetToFile är ett tunt omslag som behålls för bakåtkompatibilitet; ny kod riktas till converter.Convert nedan. För fil→fil-fallet är de två exakt lika — detta är allt som ConvertSpreadsheetToFile gör:

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 och Convert‑formen ovan ger identiska resultat; vad som skiljer sig är scenariot, som jämförs härnäst.

1.2 Den rekommenderade enradskoden: Convert med standardinställningar

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)
	}
}

Alla tre reglage använder sina standardinställningar: input = en fil, format = pdf.New() utan någon konfiguration, output = en fil. Det är den “mest koncisa” formen — ingen manuell os.Open/os.Create, ingen objektallokering, ingen handtagsstängning; källan/målet hanterar resurser åt dig.

1.3 De två fil→fil-formerna jämförda

ConvertSpreadsheetToFile(in, out)converter.Convert(source, opt, sink)
Inputenbart en filsökvägvalfri DataSource: sökväg, []byte, eller läsare
Outputenbart en filsökvägvalfri DataSink: sökväg, byte eller io.Writer
Output formatalltid härledd från filändelsen, endast standardvärdenvalfri saveOption: standard eller format‑specifik justering
Extra importkräver att formatet registreras (_ "…/register", eller motsvarande saveoptions/*‑undepaket)ingen, när du skickar en konstruktor som pdf.New()
Statusföråldrad tunn wrapper (stabil, behållen för kompatibilitet)det dokumenterade enda inträdespunkten för ny kod

Samma fil→filresultat, två olika scenarier:

  • ConvertSpreadsheetToFile — du har bokstavligen två vägar och är nöjd med motorns standardinställningar för målformatet. Perfekt för engångskonverteringsskript, migrationsbatchar och testhjälpmedel. Dess pris: indata, utdata och inställningarna kan aldrig lämna formen “file path + defaults” — och den är föråldrad.
  • converter.Convert — du vill ha samma enradare, men något av de tre argumenten ska kunna ersättas: imorgon är indata en uppladdnings []byte, målet behöver pdf.WithOnePagePerSheet(true), eller så ska utdata gå direkt in i ett HTTP‑svar. Det är exakt scenarierna i avsnitt 3 och 4 — skriv det en gång med Convert, och varje förändring är en en‑argument‑ändring.

2. Den enklaste × N: en funktion för alla 32 format

Den nästa nivån av korthet är att använda samma funktion oavsett vilket format du riktar dig mot. Eftersom saveOption kan beräknas från utdatafilens filändelse, ger det att ta bort den slutsatsen en “universell filkonverterare”:

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")
}

Användningen förblir identisk — endast filändelsen för utdata ändras:

$ 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

Vad är den där tomma _ "…/register"-importen?

Det finns två sätt att erhålla ett saveOption; detta är det enda konceptet som den “mest koncisa” stilen behöver förstå:

  • Hämta det från registret med formatnamn (formats.Get): tillägget måste finnas i formats‑registret. Varje saveoptions/*‑undermodul registrerar sig själv i sin egen init(), men endast när den importeras. Importera de undermoduler du behöver en och en (endast pdf, säg, om du konverterar till PDF), eller blank‑importera …/register en gång, vilket registrerar alla 32 format på en gång — den “universella konverteraren” ovan förlitar sig på den enda raden.
  • Anropa en konstruktor direkt (pdf.New(), markdown.New()): kringgår registret, ingen register‑import behövs; kostnaden är en importrad per format du använder.

Kort sagt: använd bara _ "…/register" när du löser via formats.Get + utdatafilens filändelse; att skicka en konstruktor direkt kräver inget extra. Den tomma importen är ofarlig och finns alltid med i de officiella exemplen.

3. Den mest flexibla: vrid varje ratt oberoende

När behovet går bortom “fil till fil med standardinställningar” ändrar du inte API‑et — de tre Convert‑parametrarna är oberoende utbytbara.

1. Inmatning (källa): från en fil, till minne, till någon ström

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, …)

Obs: den underliggande motorn kräver slumpmässig åtkomst till hela innehållet, så ReaderSource buffrar strömmen helt vid första åtkomst; varje senare Open levererar en kopia av den bufferten. Använd den med förtroende för HTTP, men var medveten om att det inte är en sann “konvertera medan du strömmar”.

2. Format (saveOption): standardvärden, eller justerade

ScenarioWriting styleWhy
Ett format med standardinställningarformats.Get("pdf")sökt upp via filändelse; skiftlägesokänslig; nil om oregistrerad
Ett format med format-specifika alternativpdf.New(pdf.WithOnePagePerSheet(true))funktionella alternativ
Standardinställningar, explicit formatooxml.New() / csv.New() / …en konstruktor utan argument per format
Ett anpassat privat formatformats.Register("fmt", factory)koppla in i registret — se docs/register.md

Funktionella alternativ visas bara för de format som har dem: en sida per kalkylblad i PDF är WithOnePagePerSheet; bilder inbäddade i HTML är WithExportImagesAsBase64; TSV är formats.Get("tsv"). Alternativen är pekar‑semantiska: utelämna = motorstandard; att explicit skicka false räknas också.

3. Utdata (sink): en fil, bytes eller en 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 och WriterSink är de två nycklarna till “mest flexibla”: de låter konverteringsresultatet hoppa över disken helt och flöda rakt in i ett HTTP‑svar, objektlagring, en zip, och så vidare. Alla tre är olika implementationer av samma sink‑parameter, så allt som accepterar []byte eller en io.Writer kan anslutas till konverteraren.


4. Exempel i verklig miljö: en Convert, många former

A. Konvertera i minnet; nedladdningsändpunkten strömmar PDF

Det vanliga server‑sidscenario‑et — en användare laddar upp xlsx, endpointen returnerar PDF, inga temporära filer:

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())
}

För att leverera CSV / Excel / HTML istället, byt bara ut saveOption (till exempel formats.Get("csv")); inget annat förändras.

B. Läs en gång, batchexportera till många format

Läs indata en enda gång och återanvänd den via BytesSource för valfritt antal utdata — idealiskt för “exportera varje 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. “Spara som” inom kalkylbladsfamiljen (migration / kompatibilitet)

Formatmigration inom kalkylbladsfamiljen, t.ex. xlsx → xls, xlsx → xlsb, xlsx → ods, och mallarna xltx/xltm — fortfarande en Convert, endast saveOption ändras:

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. Justera alternativ per format, endast vid behov

Funktionella alternativ visas när du behöver fin kontroll — observera att varje anrop nedan är verkligt och korrekt typat:

// 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" / …

Tips: för enkelutdata som CSV/HTML/image, exporterar motorn endast det kalkylblad som den anser vara “aktivt” som standard. För att kontrollera omfattningen, använd formatets egna alternativ — t.ex. html.WithExportActiveWorksheetOnly(true) (endast det aktiva bladet?), html.WithShowAllSheets(true), eller csv.WithExportAllSheets(true). Pixelnivå bildkvalitet, att exakt välja vilka blad som renderas, och andra djupa kontroller finns fortfarande på motornivå, men det aktuella image-paketet exponerar endast WithImageType‑växeln — gå till det underliggande bindningen om du behöver mer; verktygssatsen kommer fortsätta införa fler alternativ med tiden.

E. Batchkonvertering över en katalog

Det vardagliga jobbet ”konvertera den här mappen med Excelfiler till PDF” blir mycket kortare med filändelseinferens:

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. Klassificering av fel

konverteringsfel är klassificerbara sentinelfel; kombinera dem med errors.Is för exakt hantering:

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() returnerar alla för närvarande registrerade tillägg (sorterade, trådsäkra) — praktiskt för att generera en lista över “stödda format” eller en felhint.


5. Stödda format i översikt (32 registrerade som standard)

FamiljUtdatafiländelserInställningspaket
Excelxlsx xlsm xltx xltm xls xlsbsaveoptions/ooxml, xls, xlsb
OpenDocumentods xml dif dbfsaveoptions/ods, xml, dif, dbf
Text / datacsv txt tsv json sqlsaveoptions/csv, txt, json, sqlScript
Dokument / layoutpdf docx pptx xps pcl epubsaveoptions/pdf, docx, pptx, xps, pcl, ebook
Webhtml mdsaveoptions/html, markdown
Bilderpng jpg jpeg gif bmp svg emf tif tiffsaveoptions/image

För att hålla den binära filen slank, importera endast de underpaket du använder (t.ex. pdf); för bekvämlighet eller generisk dispatch, blank‑import …/register. Att importera ett underpaket triggar dess registrering; registeruppslag är skiftlägesokänsliga; en oregistrerad filändelse returnerar nil (inte ett fel), vilket lämnar återfallsbeslutet till anroparen.

6. Bästa praxis och förbehåll

  1. En enda ingångspunkt — återuppfinna den inte. File-to-file använder Convert(FilePathSource, formats.Get(ext)/constructor, FilePathSink); byt bara sink när du behöver bytes eller en ström. Undvik att manuellt kedja os.Open → ReadAll → … → os.WriteFile; källan/sänkan hanterar resurser och skapar föräldramappar åt dig.
  2. Samtidighet och licensiering. Den underliggande motorn är native: dela inte ett SaveOption/arbetsbok-objekt över goroutines i samma process; för massarbete, behandla filer sekventiellt eller parallellisera över processer. Utvärderingsbyggnaden begränsar laddningar (ungefär hundra NewWorkbook_Stream‑laddningar per process) — för stora benchmarker, starta om processen för att återställa räknaren.
  3. Läs indata en gång, återanvänd sedan. För att generera flera format från en indata, os.ReadFile den till en []byte först och konvertera upprepade gånger med BytesSource, vilket undviker upprepade diskavläsningar och omladdningar.
  4. Strömmar buffras. NewReaderSource buffrar vid första åtkomst, så den passar engångsindata som en HTTP‑förfrågningskropp, men inte riktig streaming av mycket stora filer (använd FilePathSource som pekar direkt på disken för sådana).
  5. Vet vem som bestämmer utdata‑layouten. Convert är “en indata → en utdatafil”. Om du behöver en fil per kalkylblad eller en zip, är det manipulator.Split med en FolderSink/ZipSink — tvinga inte det genom Convert.