rxlconnect

XLConnect sheet names too long


The code below asks the user for a path to .csv files, makes a list of the .csv filenames, then writes the contents of each .csv file to a sheet, in one .xlsx file. Each sheet is named after the original name of the .csv file.

My problem is that some of my .csv filenames are over 31 characters long, which is the limit for sheet names in Excel.

I want to put the sheet name in cell A1, write the contents of the file below that and give the sheets a name (1, 2, 3..., for instance), but I can't wrap my head around how I would accomplish this. Any suggestions would be greatly appreciated.

library(data.table)  ## for fast fread() function
library(XLConnect)
library(svDialogs)

# Ask user for path to csv files
folder <- dlgInput(title = "Merge csv", "Enter path to csv files (use '/' instead of '\\': ", Sys.info()["user"])$res

setwd(folder)

# Create and load Excel file
wb <- loadWorkbook("Output.xlsx", create=TRUE)

# Get list of csv files
pattern.ext <- "\\.csv$"
files <- dir(folder, full=TRUE, pattern=pattern.ext)

# Use file names for sheet names
files.nms <- basename(files)
files.nms <- gsub(pattern.ext, "", files.nms)

# Set the names to make them easier to grab
names(files) <- files.nms

# Iterate over each csv and output to sheet in Excel with its name
for (nm in files.nms) {

  # Ingest csv file
  temp_DT <- fread(files[[nm]])

  # Create the sheet with the name  
  createSheet(wb, name=nm)

  # Output the contents of the csv 
  writeWorksheet(object=wb, data=temp_DT, sheet=nm, header=TRUE, rownames=NULL)
}

# Remove default sheets
removeSheet(wb, sheet = "Sheet1")
removeSheet(wb, sheet = "Sheet2")
removeSheet(wb, sheet = "Sheet3")

saveWorkbook(wb)

# Check to see if file exists
if (file.exists("Output.xlsx")) {
  dlg_message("Your Excel file has been created.")$res
} else {
  dlg_message("Error: Your file was not created. Please try again.")$res
}

EDIT - ALTERNATE SOLUTION:

Modified code to initially take substring of the file names...

# Use substring of file names for sheet names (Excel sheet name limit is 31)
files.nms <- substr(basename(files),1,31)
files.nms <- gsub(pattern.ext, "", files.nms)

FINAL EDIT: Added welcome message and function ask user for path, which checks if the path exists. If it does not, it will continually ask user until they cancel or enter an existing directory.

library(data.table)  # fread() function
library(XLConnect)   # Excel and csv files
library(svDialogs)   # Dialog boxes

# Welcome message
dlg_message("This program will merge one or more .csv files into one Excel file. When prompted, enter the path 
            where the .csv files are located. Sheet names in the Excel file will consist of a substring of the original filename.")$res

# Function to get user path
getPath <- function() { 
  # Ask for path
  path <- dlgInput("Enter path to .csv files: ", Sys.info()["user"])$res
  if (dir.exists(path)) {
    # If it is, set the path as the working directory
    setwd(path)
  } else {
    # If not, issue an error and recall the getPath function
    dlg_message("Error: The path you entered is not a valid directory. Please try again.")$res
    getPath()
  }
}

# Call getPath function
folder <- getPath()

# Create and load Excel file
wb <- loadWorkbook("Combined.xlsx", create=TRUE)

# Get list of csv files in directory
pattern.ext <- "\\.csv$"
files <- dir(folder, full=TRUE, pattern=pattern.ext)

# Use substring of file names for sheet names (Excel limit) and remove extension 
files.nms <- substr(basename(files),9,39)
files.nms <- gsub(pattern.ext, "", files.nms)

# Set the names 
names(files) <- files.nms

# Iterate over each .csv and output to Excel sheet
for (nm in files.nms) {

  # Read in .csv files 
  df <- fread(files[nm])

  # Create the sheet and name as substr of file name  
  createSheet(object = wb, name = nm)

  # Writes contents of the .csv To Excel
  writeWorksheet(object = wb, data = df, sheet = nm, header = TRUE, rownames = NULL)

  # Create a custom anonymous cell style
  cs <- createCellStyle(wb)

  # Wrap text
  setWrapText(object = cs, wrap = TRUE)

  # Set column width
  setColumnWidth(object = wb, sheet = nm, column = 1:50, width = -1)
}

saveWorkbook(wb)

# Check to see if Excel file exists and is greater than default file size
if (file.exists("Combined.xlsx") & file.size("Combined.xlsx") > 8731) {
  dlg_message("Your Excel file has been created.")$res
} else {
  dlg_message("Error: Your file may not have been created or compelted properly. Please verify and try again if necessary.")$res
}

Solution

  • Have you considered using openxlsx?

    It's not java dependent and it's pretty feature full.

    # Load package
    library(openxlsx)
    
    # Create workbook
    wb <- createWorkbook()
    
    # Define data.frames you want to write (adapt to your scenario)    
    df <- c("mtcars", "iris")
    
    # Loop over the length of the dataframes defined above
    for(i in 1:length(df)){
        # Create a work sheet and call it the numeric value
        addWorksheet(wb, as.character(i))
        # In the first row, first column, specify the df name
        writeData(wb, i, df[i], startRow = 1, startCol = 1)
        # Write the data.frame to the second row, first column
        writeData(wb, i, eval(parse(text=df[i])), startRow = 2, startCol = 1)
    }
    
    # Save workbook
    saveWorkbook(wb, "eg.xlsx", overwrite = TRUE)