Converter: satu baris dalam bentuk paling sederhana, lingkungan apa pun dalam bentuk paling fleksibel

Paket converter dari Aspose.Cells for Go via C++ Toolkits mengurangi setiap kebutuhan “turn a spreadsheet into another format” menjadi satu fungsi entri:

converter.Convert(source, saveOption, sink) error

Ia hanya memiliki tiga parameter, dan masing‑masing menjawab tepat satu pertanyaan:

ParameterTypePertanyaan yang dijawabNilai tipikal
sourcedatasource.DataSourceDari mana input berasal?FilePathSource(path), BytesSource(data), NewReaderSource(r)
saveOptionsaveoptions.SaveOptionOutput dalam format apa, dan bagaimana disesuaikan?formats.Get("pdf") untuk default berdasarkan nama, atau pdf.New(pdf.WithOnePagePerSheet(true)) untuk kontrol halus
sinkdatasource.DataSinkKe mana output pergi?FilePathSink(path), &BytesSink{}, NewWriterSink(w)

Untuk gaya paling ringkas, gunakan nilai default pada ketiga sumbu; untuk paling fleksibel, putar setiap kenop secara independen. Karena ketiga sumbu tersebut independen, Convert yang sama secara alami cocok untuk lingkungan file, memori, HTTP, dan batch. (Ada juga satu baris warisan, ConvertSpreadsheetToFile, untuk kasus file→file sederhana — dibandingkan di bagian 1 di bawah.) Sisanya artikel ini bergerak dari paling ringkas ke paling fleksibel, memperluas potongan kode sebelumnya pada setiap langkah alih‑alih beralih ke API yang berbeda.


1. Yang paling sederhana: satu panggilan untuk satu format

1.1 Satu baris built-in file→file: ConvertSpreadsheetToFile

Paket ini juga menyertakan entri yang lebih lama, bahkan lebih singkat untuk kasus klasik “convert this file into that file”. Yang dibutuhkan hanya dua jalur:

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

Usang. ConvertSpreadsheetToFile adalah pembungkus tipis yang dipertahankan untuk kompatibilitas mundur; kode baru diarahkan ke converter.Convert di bawah ini. Untuk kasus file→file, keduanya persis setara — inilah semua yang dilakukan 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 dan bentuk Convert di atas menghasilkan hasil yang identik; yang berbeda adalah skenario, seperti yang dibandingkan berikutnya.

1.2 One-liner yang direkomendasikan: Convert dengan nilai default

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

Ketiga knob mengambil nilai default mereka: input = sebuah file, format = pdf.New() dengan konfigurasi nol, output = sebuah file. Itu adalah bentuk yang “paling ringkas” — tidak ada os.Open/os.Create manual, tidak ada alokasi objek, tidak ada penutupan handle; source/sink mengelola sumber daya untuk Anda.

1.3 Dua bentuk file→file yang dibandingkan

ConvertSpreadsheetToFile(in, out)converter.Convert(source, opt, sink)
Inputhanya jalur fileapa pun DataSource: jalur, []byte, atau pembaca
Outputhanya jalur fileapa pun DataSink: jalur, byte, atau io.Writer
Output formatselalu diinferrensikan dari ekstensi, hanya defaultapa pun saveOption: default atau penyesuaian khusus format
Extra importmemerlukan format terdaftar (_ "…/register", atau subpaket saveoptions/* yang cocok)tidak ada, ketika Anda memberikan konstruktor seperti pdf.New()
Statuswrapper tipis yang usang (stabil, dipertahankan untuk kompatibilitas)titik masuk tunggal yang didokumentasikan untuk kode baru

File yang sama→hasil file, dua skenario berbeda:

  • ConvertSpreadsheetToFile — Anda secara harfiah memiliki dua jalur dan puas dengan pengaturan default mesin untuk format target. Ideal untuk skrip konversi satu kali, batch migrasi, dan pembantu pengujian. Harganya: input, output, dan pengaturan tidak pernah keluar dari bentuk “file path + defaults” — dan ini sudah usang.
  • converter.Convert — Anda menginginkan satu baris kode yang sama, tetapi salah satu dari tiga argumen dapat diganti: besok inputnya adalah []byte hasil unggahan, target membutuhkan pdf.WithOnePagePerSheet(true), atau output harus langsung masuk ke respons HTTP. Itulah tepatnya skenario pada bagian 3 dan 4 — tulis sekali dengan Convert, dan setiap perubahan adalah edit satu argumen.

2. Yang paling sederhana × N: satu fungsi untuk semua 32 format

Tingkat berikutnya dalam keefisienan adalah menggunakan same function tidak peduli format apa yang Anda targetkan. Karena saveOption dapat dihitung dari ekstensi file output, mengeluarkan inferensi itu menghasilkan “konverter file universal”:

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

Penggunaan tetap sama — hanya ekstensi output yang berubah:

$ 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

Apa itu impor kosong _ "…/register"?

Ada dua cara untuk memperoleh saveOption; ini satu‑satunya konsep yang perlu dipahami oleh gaya “most concise”.

  • Cari di registry berdasarkan nama format (formats.Get): ekstensi harus ada di registry formats. Setiap subpaket saveoptions/* mendaftarkan dirinya sendiri di init() masing‑masing, tetapi hanya ketika diimpor. Impor subpaket yang Anda butuhkan satu per satu (misalnya hanya pdf, jika Anda mengonversi ke PDF), atau blank-import …/register sekali, yang mendaftarkan semua 32 format sekaligus — “universal converter” di atas bergantung pada satu baris itu.
  • Panggil konstruktor secara langsung (pdf.New(), markdown.New()): melewati registry, tidak perlu impor register; biayanya satu baris impor per format yang Anda gunakan.

Singkatnya: hanya gunakan _ "…/register" ketika Anda menyelesaikannya melalui formats.Get + ekstensi output; melewatkan konstruktor secara langsung tidak memerlukan apa pun tambahan. Impor kosong tidak berbahaya dan selalu ada dalam contoh resmi.

3. Yang paling fleksibel: putar setiap kenop secara terpisah

Ketika kebutuhan melampaui “file to file with default settings”, Anda tidak mengubah API — tiga parameter Convert dapat ditukar secara independen.

1. Input (sumber): dari file, ke memori, ke aliran apa pun

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

Catatan: mesin dasar memerlukan akses acak ke seluruh konten, sehingga ReaderSource menampung aliran sepenuhnya pada akses pertama; setiap Open berikutnya menyajikan salinan buffer tersebut. Gunakan dengan percaya diri untuk HTTP, hanya ketahuilah bahwa ini bukan “konversi sambil streaming” yang sebenarnya.

2. Format (saveOption): default, atau disesuaikan

ScenarioWriting styleWhy
Beberapa format dengan pengaturan defaultformats.Get("pdf")dicari berdasarkan ekstensi; tidak sensitif huruf besar/kecil; nil jika tidak terdaftar
Sebuah format dengan opsi khusus formatpdf.New(pdf.WithOnePagePerSheet(true))opsi fungsional
Pengaturan default, format eksplisitooxml.New() / csv.New() / …satu konstruktor tanpa argumen per format
Format pribadi khususformats.Register("fmt", factory)masukkan ke dalam registry — lihat docs/register.md

Opsi fungsional hanya muncul pada format yang memilikinya: satu halaman per lembar kerja dalam PDF adalah WithOnePagePerSheet; gambar inline dalam HTML adalah WithExportImagesAsBase64; TSV adalah formats.Get("tsv"). Opsi bersifat pointer‑semantic: menghilangkan = nilai default mesin; memberikan false secara eksplisit juga dihitung.

3. Output (sink): sebuah file, byte, atau 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 dan WriterSink adalah dua kunci untuk “paling fleksibel”: mereka memungkinkan hasil konversi melewati penyimpanan ke disk sepenuhnya dan mengalir langsung ke respons HTTP, penyimpanan objek, file zip, dan sebagainya. Ketiga‑nya merupakan implementasi berbeda dari parameter sink yang sama, sehingga apa pun yang menerima []byte atau io.Writer dapat dipasang ke konverter.

4. Contoh lingkungan nyata: satu Convert, banyak bentuk

A. Konversi dalam memori; endpoint unduhan mengalirkan PDF

Skenario umum di sisi server — pengguna mengunggah xlsx, endpoint mengembalikan PDF, tanpa file sementara:

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

Untuk mengeluarkan CSV / Excel / HTML sebagai gantinya, tukar hanya saveOption (misalnya formats.Get("csv")); tidak ada yang lain yang berubah.

B. Baca sekali, ekspor batch ke banyak format

Baca input hanya sekali, lalu gunakan kembali melalui BytesSource untuk sejumlah output — ideal untuk “ekspor setiap laporan”:

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. “Simpan sebagai” dalam keluarga spreadsheet (migrasi / kompatibilitas)

Migrasi format di dalam keluarga spreadsheet, misalnya xlsx → xls, xlsx → xlsb, xlsx → ods, dan templat xltx/xltm — masih satu Convert, hanya saveOption yang berubah:

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. Sesuaikan opsi per format, hanya bila diperlukan

Opsi fungsional muncul ketika Anda membutuhkan kontrol yang halus — catat setiap panggilan di bawah ini nyata dan diketik dengan benar:

// 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: untuk output satu file seperti CSV/HTML/image, mesin secara default mengekspor hanya lembar kerja yang dianggap “aktif”. Untuk mengontrol ruang lingkup, gunakan opsi khusus format — misalnya html.WithExportActiveWorksheetOnly(true) (hanya lembar aktif?), html.WithShowAllSheets(true), atau csv.WithExportAllSheets(true). Kualitas gambar tingkat piksel, memilih tepat lembar mana yang dirender, dan kontrol mendalam lainnya masih ada di lapisan mesin, tetapi paket image saat ini hanya mengekspos saklar WithImageType — gunakan binding yang mendasarinya jika Anda memerlukan lebih banyak; toolkit akan terus menambahkan opsi seiring waktu.

E. Konversi batch pada direktori

Tugas harian “convert this folder of Excels to PDF” menjadi sangat singkat dengan inferensi ekstensi:

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. Mengklasifikasikan kesalahan

error konverter adalah sentinel error yang dapat diklasifikasikan; padukan dengan errors.Is untuk penanganan yang tepat:

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() mengembalikan setiap ekstensi yang saat ini terdaftar (diurutkan, aman terhadap konkurensi) — berguna untuk menghasilkan daftar “format yang didukung” atau petunjuk kesalahan.

5. Format yang didukung secara sekilas (32 terdaftar secara default)

KeluargaEkstensi outputPaket penyesuaian
Excelxlsx xlsm xltx xltm xls xlsbsaveoptions/ooxml, xls, xlsb
OpenDocumentods xml dif dbfsaveoptions/ods, xml, dif, dbf
Teks / datacsv txt tsv json sqlsaveoptions/csv, txt, json, sqlScript
Dokumen / tata letakpdf docx pptx xps pcl epubsaveoptions/pdf, docx, pptx, xps, pcl, ebook
Webhtml mdsaveoptions/html, markdown
Gambarpng jpg jpeg gif bmp svg emf tif tiffsaveoptions/image

Untuk menjaga binary tetap ringan, impor hanya subpaket yang Anda gunakan (seperti pdf); untuk kenyamanan atau pengiriman generik, lakukan blank-import …/register. Mengimpor subpaket memicu pendaftarannya; pencarian di registry tidak sensitif huruf besar/kecil; ekstensi yang tidak terdaftar mengembalikan nil (bukan error), meninggalkan keputusan fallback kepada pemanggil.

6. Praktik terbaik dan peringatan

  1. Satu titik masuk — jangan menciptakan ulang. File-to-file menggunakan Convert(FilePathSource, formats.Get(ext)/constructor, FilePathSink); hanya ganti sink ketika Anda membutuhkan byte atau aliran. Jangan membuat secara manual os.Open → ReadAll → … → os.WriteFile; source/sink mengelola sumber daya dan membuat direktori induk untuk Anda.
  2. Konkruensi dan lisensi. Mesin dasar bersifat native: jangan berbagi satu objek SaveOption/workbook di antara goroutine dalam proses yang sama; untuk pekerjaan massal, proses file secara berurutan atau paralelkan antar proses. Build evaluasi membatasi pemuatan (sekitar seratus pemuatan NewWorkbook_Stream per proses) — untuk benchmark besar, restart proses untuk mengatur ulang penghitung.
  3. Baca masukan sekali, lalu gunakan kembali. Untuk menghasilkan beberapa format dari satu masukan, os.ReadFile ke dalam []byte terlebih dahulu dan konversi berulang kali dengan BytesSource, menghindari pembacaan disk berulang dan pemuatan ulang.
  4. Aliran menjadi terbuffer. NewReaderSource melakukan buffering pada akses pertama, sehingga cocok untuk masukan satu kali seperti body permintaan HTTP, bukan streaming sebenarnya dari file yang sangat besar (gunakan FilePathSource yang langsung mengarah ke disk untuk itu).
  5. Ketahui siapa yang menentukan tata letak output. Convert adalah “satu masukan → satu file output”. Jika Anda membutuhkan satu file per lembar kerja atau sebuah zip, gunakan manipulator.Split dengan FolderSink/ZipSink — jangan memaksanya melalui Convert.