Конвертер: один рядок у найпростіший спосіб, будь-яке середовище у найгнучкішій формі
Пакет converter Aspose.Cells for Go via C++ Toolkits зменшує кожну потребу «перетворити електронну таблицю в інший формат» до однієї функції входу:
converter.Convert(source, saveOption, sink) error
Він має лише три параметри, і кожен відповідає саме на одне запитання:
| Параметр | Тип | Питання, на яке відповідає | Типові значення |
|---|---|---|---|
source | datasource.DataSource | Звідки надходить вхід? | FilePathSource(path), BytesSource(data), NewReaderSource(r) |
saveOption | saveoptions.SaveOption | У який формат виводити, як налаштувати? | formats.Get("pdf") для типових значень за назвою, або pdf.New(pdf.WithOnePagePerSheet(true)) для тонкого налаштування |
sink | datasource.DataSink | Куди йде вихід? | FilePathSink(path), &BytesSink{}, NewWriterSink(w) |
Для найбільш стислого стилю використовуйте значення за замовчуванням на всіх трьох осях; для найбільш гнучкого — налаштовуйте кожен параметр окремо. Оскільки три осі незалежні, той самий Convert природно підходить для файлових, пам’яті, HTTP та пакетних середовищ. (Існує також застарілий однорядковий виклик ConvertSpreadsheetToFile для простого випадку файл→файл — порівняно в розділі 1 нижче.) Решта статті переходить від найбільш стислого до найбільш гнучкого, поступово розширюючи попередній фрагмент на кожному кроці, а не переключаючись на інший API.
1. Найпростіший: один виклик для одного формату
1.1 Вбудований однорядковий файл→файл: ConvertSpreadsheetToFile
Пакет також постачається зі старішим, ще коротшим записом для класичного “convert this file into that file” випадку. Все, що потрібно, — це два шляхи:
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)
}
}
Застаріло.
ConvertSpreadsheetToFile— це тонка обгортка, збережена для зворотної сумісності; новий код спрямовується доconverter.Convertнижче. У випадку file→file обидва є точно еквівалентними — це все, що робить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 і форма Convert, наведена вище, дають однакові результати; різниця полягає у сценарії, як показано далі.
1.2 Рекомендований однорядковий вираз: Convert за замовчуванням
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)
}
}
Усі три налаштування беруть свої значення за замовчуванням: input = файл, format = pdf.New() без жодної конфігурації, output = файл. Це «найбільш стислий» варіант — без ручного os.Open/os.Create, без виділення об’єктів, без закриття дескрипторів; джерело/приймач керують ресурсами за вас.
1.3 Порівняння двох форм file→file
ConvertSpreadsheetToFile(in, out) | converter.Convert(source, opt, sink) | |
|---|---|---|
| Вхід | тільки шлях до файлу | будь-який DataSource: шлях, []byte, або читач |
| Вихід | тільки шлях до файлу | будь-який DataSink: шлях, байти або io.Writer |
| Формат виводу | завжди визначається за розширенням, лише за замовчуванням | будь-який saveOption: за замовчуванням або налаштування, специфічне для формату |
| Додатковий імпорт | потрібно зареєструвати формат (_ "…/register", або відповідний підпакет saveoptions/* субпакет) | нічого, коли ви передаєте конструктор, наприклад pdf.New() |
| Статус | застарілий тонкий обгортка (стабільний, збережений для сумісності) | документована єдина точка входу для нового коду |
Той самий файл → результат файлу, два різних сценарії:
ConvertSpreadsheetToFile— ви буквально маєте два шляхи і задоволені налаштуваннями за замовчуванням движка для цільового формату. Ідеально підходить для одноразових скриптів конвертації, пакетів міграції та тестових допоміжних засобів. Його ціна: вхід, вихід і налаштування ніколи не можуть залишити форму «file path + defaults» — і він застарілий.converter.Convert— ви хочете той самий однорядковий виклик, але будь‑який з трьох аргументів може бути замінений: завтра вхід буде[]byteзавантаження, ціль потребуєpdf.WithOnePagePerSheet(true), або вихід має йти безпосередньо в HTTP‑відповідь. Це саме ті сценарії, що описані у розділах 3 і 4 — напишіть один раз за допомогоюConvert, і кожна зміна буде редагуванням одного аргументу.
2. Найпростіший × N: одна функція для всіх 32 форматів
Наступний рівень стислості — використання однієї функції незалежно від того, який формат ви обираєте. Оскільки saveOption можна обчислити за розширенням вихідного файлу, винесення цього висновку назовні дає “універсальний конвертер файлів”:
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")
}
Використання залишається ідентичним — лише змінюється розширення вихідного файлу:
$ 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
Що це за порожній імпорт _ "…/register"?
Існує два способи отримати saveOption; це єдина концепція, яку має розуміти стиль “most concise”.
- Шукайте в реєстрі за назвою формату (
formats.Get): розширення має бути присутнім у реєстріformats. Кожен підпакетsaveoptions/*реєструє себе у власнійinit(), але лише при імпорті. Імпортуйте потрібні підпакети по одному (наприклад, лишеpdf, якщо ви конвертуєте у PDF), або blank-import…/registerодин раз, що реєструє всі 32 формати одразу — «універсальний конвертер», згаданий вище, покладається на цей єдиний рядок. - Викликайте конструктор безпосередньо (
pdf.New(),markdown.New()): обходить реєстр, імпортregisterне потрібен; вартість — один рядок імпорту на кожний формат, який ви використовуєте.
Коротко: лише використовуйте _ "…/register" коли ви отримуєте через formats.Get + розширення вихідного файлу; передача конструктора безпосередньо не потребує нічого додаткового. Порожній імпорт безпечний і завжди присутній в офіційних прикладах.
3. Найбільш гнучкий: регулюйте кожен регулятор окремо
Коли потреба виходить за межі «файл у файл з налаштуваннями за замовчуванням», ви не змінюєте API — три параметри Convert можна незалежно міняти місцями.
1. Вхід (джерело): з файлу, у пам’ять, у будь‑який потік
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, …)
Примітка: базовий движок потребує випадкового доступу до всього вмісту, тому
ReaderSourceбуферизує потік повністю при першому доступі; кожен наступнийOpenнадає копію цього буфера. Використовуйте його впевнено для HTTP, лише майте на увазі, що це не справжнє “конвертувати під час потокової передачі”.
2. Формат (saveOption): за замовчуванням або налаштований
| Сценарій | Стиль написання | Чому |
|---|---|---|
| Деякий формат з налаштуваннями за замовчуванням | formats.Get("pdf") | шукається за розширенням; нечутливий до регістру; nil, якщо не зареєстровано |
| Формат зі специфічними для формату параметрами | pdf.New(pdf.WithOnePagePerSheet(true)) | функціональні опції |
| Налаштування за замовчуванням, явний формат | ooxml.New() / csv.New() / … | один конструктор без аргументів для кожного формату |
| Користувацький приватний формат | formats.Register("fmt", factory) | підключити до реєстру — див. docs/register.md |
Функціональні параметри з’являються лише у форматах, які їх підтримують: одна сторінка на лист у PDF — WithOnePagePerSheet; зображення вбудовані в HTML — WithExportImagesAsBase64; TSV — formats.Get("tsv"). Параметри мають семантику вказівника: пропуск = значення за замовчуванням движка; передача false явно також враховується.
3. Вихід (sink): файл, байти або 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 і WriterSink — це два ключі до “найбільш гнучкого”: вони дозволяють результату конвертації повністю обійти диск і напряму потрапляти у HTTP‑відповідь, об’єктне сховище, zip‑архів тощо. Усі три є різними реалізаціями одного параметра sink, тому будь‑що, що приймає []byte або io.Writer, можна підключити до конвертера.
4. Приклади у реальному середовищі: один Convert, багато форм
A. Конвертування в пам’яті; кінцева точка завантаження транслює PDF
Загальний сценарій на боці сервера — користувач завантажує xlsx, кінцева точка повертає PDF, без тимчасових файлів:
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())
}
Щоб замість цього видавати CSV / Excel / HTML, замініть лише saveOption (наприклад formats.Get("csv")); нічого іншого не змінюється.
B. Прочитати один раз, пакетно експортувати у багато форматів
Прочитайте вхідні дані лише один раз, а потім повторно використовуйте їх через BytesSource для будь‑якої кількості виходів — ідеально підходить для “експорту кожного звіту”:
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. “Зберегти як” у сім’ї електронних таблиць (мiграція / сумісність)
Міграція форматів у межах сімейства електронних таблиць, наприклад xlsx → xls, xlsx → xlsb, xlsx → ods, а також шаблони xltx/xltm — все ще один Convert, змінюється лише 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. Налаштувати параметри для кожного формату, лише за потреби
Функціональні параметри з’являються, коли потрібен тонкий контроль — зауважте, що кожний виклик нижче є реальним і правильно типізованим:
// 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" / …
Підказка: для однофайлових виводів, таких як CSV/HTML/image, движок за замовчуванням експортує лише лист, який він вважає “активним”. Щоб керувати областю, використовуйте власні параметри формату — напр.,
html.WithExportActiveWorksheetOnly(true)(тільки активний лист?),html.WithShowAllSheets(true), абоcsv.WithExportAllSheets(true). Якість зображень на рівні пікселів, точний вибір листів, які рендеряться, та інші глибокі налаштування все ще існують на рівні движка, проте поточний пакетimageвідкриває лише перемикачWithImageType— звертайтеся до нижчого рівня прив’язки, якщо потрібно більше; інструментарій буде поступово додавати нові параметри.
E. Пакетне перетворення каталогу
Повсякденне “convert this folder of Excels to PDF” завдання стає дуже коротким завдяки виведенню розширення:
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. Класифікація помилок
Помилки конвертера є класифікованими sentinel‑помилками; поєднуйте їх з errors.Is для точного оброблення:
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() повертає всі наразі зареєстровані розширення (відсортовані, безпечні для конкурентного доступу) — зручно для створення списку “підтримуваних форматів” або підказки про помилку.
5. Підтримувані формати на перший погляд (32 зареєстровано за замовчуванням)
| Сім’я | Вихідні розширення | Пакет налаштувань |
|---|---|---|
| Excel | xlsx xlsm xltx xltm xls xlsb | saveoptions/ooxml, xls, xlsb |
| OpenDocument | ods xml dif dbf | saveoptions/ods, xml, dif, dbf |
| Текст / дані | csv txt tsv json sql | saveoptions/csv, txt, json, sqlScript |
| Документи / макет | pdf docx pptx xps pcl epub | saveoptions/pdf, docx, pptx, xps, pcl, ebook |
| Веб | html md | saveoptions/html, markdown |
| Зображення | png jpg jpeg gif bmp svg emf tif tiff | saveoptions/image |
Щоб зберегти бінарний файл компактним, імпортуйте лише підпакети, які ви використовуєте (наприклад pdf); для зручності або загального диспетчеризації використовуйте порожній імпорт …/register. Імпорт підпакету ініціює його реєстрацію; пошуки в реєстрі нечутливі до регістру; незареєстроване розширення повертає nil (не помилку), залишаючи рішення про резервний варіант викликаючому.
6. Кращі практики та підводні камені
Один вхідний пункт — не винаходьте заново. File-to-file використовує
Convert(FilePathSource, formats.Get(ext)/constructor, FilePathSink); перемикайте sink лише коли потрібні байти або потік. Не робіть вручнуos.Open → ReadAll → … → os.WriteFile; source/sink керують ресурсами і створюють батьківські каталоги за вас.Конкурентність і ліцензування. Базовий движок є нативним: не діліться одним об’єктом
SaveOption/workbook між goroutine в одному процесі; для масової обробки обробляйте файли послідовно або паралельно в різних процесах. Оцінкова збірка обмежує кількість завантажень (близько стоNewWorkbook_Streamзавантажень на процес) — для великих тестів перезапустіть процес, щоб скинути лічильник.Прочитайте вхід один раз, а потім використовуйте його повторно. Щоб вивести кілька форматів з одного входу, спочатку
os.ReadFileйого у[]byteі конвертуйте повторно за допомогоюBytesSource, уникаючи повторних читань з диска та перезавантажень.Потоки буферизуються.
NewReaderSourceбуферизується при першому доступі, тому підходить для одноразових входів, таких як тіло HTTP‑запиту, а не для справжнього потокового оброблення дуже великих файлів (для цього використовуйтеFilePathSource, який вказує безпосередньо на диск).Знайте, хто визначає макет виходу.
Convert— це «один вхід → один вихідний файл». Якщо потрібен один файл на лист або zip, використовуйтеmanipulator.SplitзFolderSink/ZipSink— не примушуйте це черезConvert.
