yao/excel/sheet.go
Max c357c72934 refactor: Simplify sheet dimension retrieval in Excel processing
- Replaced the previous method of calculating sheet dimensions with a more efficient approach using the `Cols` method.
- Removed commented-out code related to dimension handling, streamlining the function for better readability and maintainability.
2025-05-15 13:02:13 +08:00

255 lines
5.7 KiB
Go

package excel
import (
"fmt"
"strings"
"github.com/xuri/excelize/v2"
)
// New creates a new Excel workbook
func New() (*Excel, error) {
f := excelize.NewFile()
return &Excel{
File: f,
id: "",
path: "",
create: 0,
abs: "",
}, nil
}
// validateSheetName checks if the sheet name contains invalid characters
func (excel *Excel) validateSheetName(name string) error {
invalidChars := []string{":", "\\", "/", "?", "*", "[", "]"}
for _, char := range invalidChars {
if strings.Contains(name, char) {
return fmt.Errorf("sheet name cannot contain any of these characters: :/?*[\\]")
}
}
if len(name) == 0 {
return fmt.Errorf("sheet name cannot be empty")
}
if len(name) > 31 {
return fmt.Errorf("sheet name cannot be longer than 31 characters")
}
return nil
}
// CreateSheet creates a new sheet with the given name
// Returns the index of the new sheet and any error encountered
func (excel *Excel) CreateSheet(name string) (int, error) {
// Validate sheet name
if err := excel.validateSheetName(name); err != nil {
return 0, err
}
// Check if sheet already exists
if idx, _ := excel.GetSheetIndex(name); idx != -1 {
return 0, fmt.Errorf("sheet %s already exists", name)
}
return excel.NewSheet(name)
}
// ReadSheet reads all data from a sheet
// Returns the data as a 2D array of interfaces and any error encountered
func (excel *Excel) ReadSheet(name string) ([][]interface{}, error) {
// Check if sheet exists
if idx, _ := excel.GetSheetIndex(name); idx == -1 {
return nil, fmt.Errorf("sheet %s does not exist", name)
}
rows, err := excel.GetRows(name)
if err != nil {
return nil, err
}
// Convert [][]string to [][]interface{}
result := make([][]interface{}, len(rows))
for i, row := range rows {
result[i] = make([]interface{}, len(row))
for j, cell := range row {
result[i][j] = cell
}
}
return result, nil
}
// GetSheetDimension returns the number of rows and columns in a sheet
func (excel *Excel) GetSheetDimension(name string) (rows int, cols int, err error) {
// Check if sheet exists
if idx, _ := excel.GetSheetIndex(name); idx == -1 {
return 0, 0, fmt.Errorf("sheet %s does not exist", name)
}
rows = 0
cols = 0
ri, err := excel.File.Rows(name)
if err != nil {
return 0, 0, err
}
defer ri.Close()
for ri.Next() {
rows++
}
// Get column count
ci, err := excel.File.Cols(name)
if err != nil {
return 0, 0, err
}
for ci.Next() {
cols++
}
return rows, cols, nil
}
// ReadSheetRows reads all data from a sheet by rows
func (excel *Excel) ReadSheetRows(name string, start int, size int) ([][]string, error) {
// Validate parameters
if start < 0 {
return nil, fmt.Errorf("start position cannot be negative")
}
if size < 0 {
return nil, fmt.Errorf("size cannot be negative")
}
// Check if sheet exists
if idx, _ := excel.GetSheetIndex(name); idx == -1 {
return nil, fmt.Errorf("sheet %s does not exist", name)
}
// If size is 0, return empty slice
if size == 0 {
return [][]string{}, nil
}
// Get rows iterator
rows, err := excel.File.Rows(name)
if err != nil {
return nil, err
}
defer rows.Close()
// Skip to start position
currentRow := -1
for rows.Next() {
currentRow++
if currentRow >= start {
break
}
}
// Read requested number of rows
result := make([][]string, 0, size)
if currentRow == start {
row, err := rows.Columns()
if err != nil {
return nil, err
}
result = append(result, row)
}
for i := 1; i < size && rows.Next(); i++ {
row, err := rows.Columns()
if err != nil {
return nil, err
}
result = append(result, row)
}
return result, nil
}
// UpdateSheet updates an existing sheet with new data
// If the sheet doesn't exist, it will be created
func (excel *Excel) UpdateSheet(name string, data [][]interface{}) error {
// Validate sheet name
if err := excel.validateSheetName(name); err != nil {
return err
}
// Ensure sheet exists
_, err := excel.SetSheet(name)
if err != nil {
return err
}
// Clear existing content by deleting the sheet
err = excel.DeleteSheet(name)
if err != nil {
return err
}
// Create new sheet with same name
_, err = excel.NewSheet(name)
if err != nil {
return err
}
// Write new data
return excel.WriteAll(name, "A1", data)
}
// DeleteSheet removes a sheet by name
func (excel *Excel) DeleteSheet(name string) error {
// Check if sheet exists
if idx, _ := excel.GetSheetIndex(name); idx == -1 {
return fmt.Errorf("sheet %s does not exist", name)
}
return excel.File.DeleteSheet(name)
}
// ListSheets returns a list of all sheet names in the workbook
func (excel *Excel) ListSheets() []string {
return excel.GetSheetList()
}
// SheetExists checks if a sheet exists in the workbook
func (excel *Excel) SheetExists(name string) bool {
idx, _ := excel.GetSheetIndex(name)
return idx != -1
}
// CopySheet copies a sheet to a new name
func (excel *Excel) CopySheet(source, destination string) error {
// Validate destination sheet name
if err := excel.validateSheetName(destination); err != nil {
return err
}
// Check if source exists
if idx, _ := excel.GetSheetIndex(source); idx == -1 {
return fmt.Errorf("source sheet %s does not exist", source)
}
// Check if destination already exists
if idx, _ := excel.GetSheetIndex(destination); idx != -1 {
return fmt.Errorf("destination sheet %s already exists", destination)
}
// Create new sheet
_, err := excel.NewSheet(destination)
if err != nil {
return err
}
// Copy content
rows, err := excel.GetRows(source)
if err != nil {
return err
}
// Convert [][]string to [][]interface{}
data := make([][]interface{}, len(rows))
for i, row := range rows {
data[i] = make([]interface{}, len(row))
for j, cell := range row {
data[i][j] = cell
}
}
return excel.WriteAll(destination, "A1", data)
}