Převodník: jeden řádek v jeho nejjednodušší podobě, jakékoli prostředí v jeho nejflexibilnější podobě

Balíček converter z Aspose.Cells for Go via C++ Toolkits snižuje každou potřebu „převést tabulku do jiného formátu“ na jednu vstupní funkci:

converter.Convert(source, saveOption, sink) error

Má jen tři parametry a každý odpovídá přesně na jednu otázku:

ParametrTypOtázka, na kterou odpovídáTypické hodnoty
sourcedatasource.DataSourceOdkud vstup pochází?FilePathSource(path), BytesSource(data), NewReaderSource(r)
saveOptionsaveoptions.SaveOptionJaký je výstup a jak je nastaven?formats.Get("pdf") pro výchozí hodnoty podle názvu, nebo pdf.New(pdf.WithOnePagePerSheet(true)) pro jemné nastavení
sinkdatasource.DataSinkKam výstup směřuje?FilePathSink(path), &BytesSink{}, NewWriterSink(w)

Pro nejstručnější styl použijte výchozí nastavení na všech třech osách; pro nejflexibilnější otočte každý ovladač nezávisle. Protože jsou tři osy nezávislé, stejná Convert přirozeně vyhovuje souborovým, paměťovým, HTTP a dávkovým prostředím. (Existuje také starší jednorázová metoda ConvertSpreadsheetToFile pro jednoduchý případ soubor→soubor — porovnáno v sekci 1 níže.) Zbytek tohoto článku přechází od nejstručnějšího k nejflexibilnějšímu, přičemž postupně rozšiřuje předchozí úryvek místo přepnutí na jiné API.


1. Nejjednodušší: jedno volání pro jeden formát

1.1 Vestavěný file→file jednorázový příkaz: ConvertSpreadsheetToFile

Balíček také obsahuje starší, ještě kratší vstup pro klasický případ „převést tento soubor na ten soubor“. Stačí jen dvě cesty:

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

Zastaralé. ConvertSpreadsheetToFile je tenký obal zachovaný pro zpětnou kompatibilitu; nový kód je nasměrován na converter.Convert níže. Pro případ soubor→soubor jsou oba přesně ekvivalentní — to je vše, co ConvertSpreadsheetToFile dělá:

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 a výše uvedená forma Convert produkují identické výsledky; liší se scénář, jak je uvedeno níže.

1.2 Doporučený jednorázový příkaz: Convert s výchozími hodnotami

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

Všechny tři ovládací prvky používají výchozí hodnoty: input = soubor, format = pdf.New() s nulovou konfigurací, output = soubor. To je “nejstručnější” podoba — žádné ruční os.Open/os.Create, žádná alokace objektů, žádné uzavírání handle; source/sink spravují prostředky za vás.

1.3 Porovnání dvou tvarů soubor→soubor

ConvertSpreadsheetToFile(in, out)converter.Convert(source, opt, sink)
Vstuppouze cesta k souborulibovolný DataSource: cesta, []byte, nebo čtečka
Výstuppouze cesta k souborulibovolný DataSink: cesta, bajty, nebo io.Writer
Formát výstupuvždy odvozeno z přípony, pouze výchozí hodnotylibovolná saveOption: výchozí nebo ladění specifické pro formát
Další importvyžaduje registraci formátu (_ \"…/register\", nebo odpovídající podbalíček saveoptions/*)žádný, pokud předáte konstruktor jako pdf.New()
Stavzastaralý tenký obal (stabilní, zachován pro kompatibilitu)dokumentovaný jediný vstupní bod pro nový kód

Stejný soubor → výsledek souboru, dva různé scénáře:

  • ConvertSpreadsheetToFile — doslova máte dvě cesty a jste spokojeni s výchozími nastaveními enginu pro cílový formát. Ideální pro jednorázové konverzní skripty, migrační dávky a testovací pomocníky. Jeho cena: vstup, výstup a nastavení nikdy nemohou opustit tvar „file path + defaults“ — a je zastaralý.
  • converter.Convert — chcete stejný jednorázový řádek, ale kterýkoliv ze tří argumentů zůstane zaměnitelný: zítra bude vstup []byte nahraný, cíl bude potřebovat pdf.WithOnePagePerSheet(true), nebo výstup by měl jít přímo do HTTP odpovědi. To jsou přesně scénáře sekcí 3 a 4 — napište to jednou pomocí Convert a každá změna bude úprava jednoho argumentu.

2. Nejjednodušší × N: jedna funkce pro všech 32 formátů

Dalším stupněm stručnosti je použití téže funkce bez ohledu na to, který formát cílíte. Protože saveOption lze vypočítat z přípony výstupního souboru, vytažení tohoto odvození ven poskytuje „univerzální převodník souborů“:

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

Použití zůstává stejné — mění se pouze výstupní přípona:

$ 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

Co je to za prázdný import _ "…/register"?

Existují dva způsoby, jak získat saveOption; to je jediný koncept, který musí styl “most concise” pochopit:

  • Vyhledejte v registru podle názvu formátu (formats.Get): rozšíření musí být přítomno v registru formats. Každý podbalíček saveoptions/* se zaregistruje ve své vlastní funkci init(), ale pouze při importu. Importujte podbalíčky, které potřebujete, jeden po druhém (např. jen pdf, pokud převádíte do PDF), nebo prázdný import …/register jednou, který zaregistruje všech 32 formátů najednou — „universal converter“ výše se spoléhal na tento jediný řádek.
  • Volání konstruktoru přímo (pdf.New(), markdown.New()): obejde registr, není potřeba import register; náklady jsou jeden řádek importu na každý formát, který používáte.

Stručně řečeno: použijte _ "…/register" pouze tehdy, když řešíte pomocí formats.Get + výstupní přípona; předání konstruktoru přímo nevyžaduje nic dalšího. Prázdný import je neškodný a je vždy přítomen v oficiálních příkladech.

3. Nejvíce flexibilní: otáčejte každý knoflík samostatně

Když potřeba přesahuje „soubor na soubor s výchozími nastaveními“, neměníte API — tři parametry Convert jsou nezávisle zaměnitelné.

1. Vstup (zdroj): ze souboru, do paměti, do libovolného streamu

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

Poznámka: podkladový engine vyžaduje náhodný přístup k celému obsahu, takže ReaderSource při prvním přístupu plně načte stream do vyrovnávací paměti; každé další volání Open poskytne kopii této vyrovnávací paměti. Používejte jej s důvěrou pro HTTP, jen vězte, že to není pravé „převádění během streamování“.

2. Formát (saveOption): výchozí, nebo vyladěné

ScenarioWriting styleWhy
Formát s výchozím nastavenímformats.Get("pdf")vyhledáno podle přípony; nerozlišuje velká a malá písmena; nil pokud není registrováno
Formát s možnostmi specifickými pro formátpdf.New(pdf.WithOnePagePerSheet(true))funkční volby
Výchozí nastavení, explicitní formátooxml.New() / csv.New() / …jeden konstruktor bez argumentů pro každý formát
Vlastní soukromý formátformats.Register("fmt", factory)připojit do registru — viz docs/register.md

Funkční možnosti se objevují pouze u formátů, které je mají: jedna stránka na list v PDF je WithOnePagePerSheet; obrázky vložené do HTML jsou WithExportImagesAsBase64; TSV je formats.Get("tsv"). Možnosti mají semantiku ukazatele: vynechat = výchozí nastavení enginu; předání false explicitně také počítá.

3. Výstup (sink): soubor, bajty nebo 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 a WriterSink jsou dva klíče k „největší flexibilitě“: umožňují, aby výsledek konverze úplně obešel disk a proudil přímo do HTTP odpovědi, úložiště objektů, zipu a podobně. Všechny tři jsou různé implementace stejného parametru sink, takže cokoliv, co přijímá []byte nebo io.Writer, může být zapojeno do konvertoru.

4. Příklady v reálném prostředí: jeden Convert, mnoho tvarů

A. Převod v paměti; koncový bod pro stahování streamuje PDF

Běžný scénář na straně serveru — uživatel nahrává xlsx, endpoint vrací PDF, žádné dočasné soubory:

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

Chcete-li místo toho poskytovat CSV / Excel / HTML, vyměňte pouze saveOption (například formats.Get("csv")); nic jiného se nezmění.

B. Načtěte jednou, hromadně exportujte do mnoha formátů

Přečtěte vstup jen jednou a poté jej znovu použijte prostřednictvím BytesSource pro libovolný počet výstupů — ideální pro “export každé zprávy”.

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. “Uložit jako” v rámci rodiny tabulek (migrace / kompatibilita)

Migrace formátu v rámci rodiny tabulkových souborů, např. xlsx → xls, xlsx → xlsb, xlsx → ods, a šablony xltx/xltm — stále jeden Convert, pouze se mění saveOption:

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. Ladit možnosti podle formátu, pouze když je to potřeba

Funkční možnosti se objevují, když potřebujete jemnou kontrolu — všimněte si, že každý níže uvedený volání je skutečné a správně typované:

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

Tip: pro výstupy do jediného souboru, jako jsou CSV/HTML/image, engine exportuje pouze list, který považuje za „aktivní“ ve výchozím nastavení. Pro řízení rozsahu použijte vlastní možnosti formátu — např. html.WithExportActiveWorksheetOnly(true) (pouze aktivní list?), html.WithShowAllSheets(true) nebo csv.WithExportAllSheets(true). Kvalita obrazu na úrovni pixelů, výběr přesně toho, které listy jsou vykresleny, a další pokročilé ovládací prvky stále existují na úrovni engine, ale aktuální balíček image vystavuje pouze přepínač WithImageType — pokud potřebujete více, sáhněte po podkladovém bindingu; sady nástrojů budou postupně přidávat další možnosti.

E. Dávková konverze v adresáři

Každodenní “převést tuto složku Excel souborů do PDF” úkol se stává velmi krátkým díky odvození přípony:

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. Klasifikace chyb

chyby konvertoru jsou klasifikovatelné sentinelní chyby; spárujte je s errors.Is pro přesné zpracování:

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() vrací každé aktuálně registrované rozšíření (seřazené, souběžně bezpečné) — praktické pro vytvoření seznamu „podporovaných formátů“ nebo nápovědy k chybě.


5. Podporované formáty na první pohled (32 registrovaných ve výchozím nastavení)

RodinaVýstupní příponyLadící balíček
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
Dokumenty / rozvrženípdf docx pptx xps pcl epubsaveoptions/pdf, docx, pptx, xps, pcl, ebook
Webhtml mdsaveoptions/html, markdown
Obrázkypng jpg jpeg gif bmp svg emf tif tiffsaveoptions/image

Aby byl binární soubor úsporný, importujte pouze podbalíky, které používáte (např. pdf); pro pohodlí nebo obecné směrování použijte prázdný import …/register. Import podbalíku spustí jeho registraci; vyhledávání v registru není citlivé na velikost písmen; neregistrovaná přípona vrátí nil (ne chybu), což ponechává rozhodnutí o záložním řešení na volajícím.

6. Nejlepší postupy a úskalí

  1. Jedno vstupní místo — nepřepisujte jej. File-to-file používá Convert(FilePathSource, formats.Get(ext)/constructor, FilePathSink); přepínejte sinky jen když potřebujete bajty nebo stream. Nepište ručně os.Open → ReadAll → … → os.WriteFile; source/sink spravují prostředky a vytvoří nadřazené adresáře za vás.

  2. Souběžnost a licencování. Podkladový engine je nativní: nedílejte jeden objekt SaveOption/workbook mezi goroutine v rámci stejného procesu; pro hromadnou práci zpracovávejte soubory sekvenčně nebo paralelně napříč procesy. Vyhodnocovací sestavení omezuje načítání (přibližně sto načtení NewWorkbook_Stream na proces) — pro velké benchmarky restartujte proces, aby se čítač vynuloval.

  3. Přečtěte vstup jednou a poté jej znovu použijte. Pro vytvoření několika formátů z jednoho vstupu jej nejprve os.ReadFile načtěte do []byte a opakovaně převádějte pomocí BytesSource, čímž se vyhnete opakovaným čtením z disku a opětovnému načítání.

  4. Streamy jsou bufferovány. NewReaderSource bufferuje při prvním přístupu, takže je vhodný pro jednorázové vstupy jako tělo HTTP požadavku, nikoli pro skutečný streaming velmi velkých souborů (pro ty použijte FilePathSource, který ukazuje přímo na disk).

  5. Vězte, kdo rozhoduje o rozložení výstupu. Convert je „jeden vstup → jeden výstupní soubor“. Pokud potřebujete jeden soubor na list nebo zip, použijte manipulator.Split s FolderSink/ZipSink — nepřetlačujte to přes Convert.