I have 100 excel files in one folder and I would like to change the name of the fourth column of each file to corresponding file name in R.
filenames <- list.files(pattern = '\\.xlsx', full.names = TRUE)
lapply(filenames, function(x) {
#Read the data
data <- readxl::read_excel(x)
#Change the 4th column with filename
names(data)[4] <- tools::file_path_sans_ext(basename(x))
#Write the data back
writexl::write_xlsx(data, x)
})
So, I have many excel files in a folder, and each file has multiple sheets. If the name of the excel file is 'xyz', I want each sheet of each excel file to contain a 'new_column' such that each row of the new column will contain the excel file name (in this example, 'xyz').
Is there any direct way to do that? I would prefer to directly alter the files in the folder without creating new dataframes within rstudio.
Thanks.
You can use double lapply -
library(readxl)
library(writexl)
#Get a vector of xlsx filenames
filenames <- list.files(pattern = '.xlsx', full.names = TRUE)
lapply(filenames, function(x) {
#Read the sheet names
sheetname <- excel_sheets(x)
#For each sheet read the data and create list of dataframe
lapply(sheetname, function(y) {
cbind(read_xlsx(x, y), filename = x)
}) -> res
#Assign names to the list
names(res) <- sheetname
#Write the data back
write_xlsx(res, x)
})
Given this data frame as:
a <- 1:5
b <- 6:10
df <- data.frame(a,b)
df
Can I write to .csv file automatically without pre-creating such .csv file
write(df)
without specifying the file path (because I have no pre-created file) and r will create one automatically to save my data frame in my working directory?
If I got your question! you just use:
write.csv(df, "df.csv")
Write a custom function that converts object name into a filename and saves as ".csv":
myWrite <- function(x){
write.csv(x, file = paste0(deparse(substitute(x)), ".csv"))
}
myWrite(mtcars)
list.files(pattern = "mtcars")
# [1] "mtcars.csv"
My R code currently involves looping through a list of .xlsm files, transforming the data within each sheet through function and then output the files as a set of .xlsx files. Suppose my Filelist consists of only 2 files i.e. Filelist = c("aaa.xlsm", "bbb.xlsm"), my current code, stated below, will output the .xlsx files with file names "aaa.xlsm.xlsx" and "bbb.xlsm.xlsx" respectively.
Filelist <- list.files(pattern = ".xlsm$") #extract list of files from folder that end with xlsm
lapply(Filelist, function(i) {
df1 <- read_excel(i, sheet = "Trial1")
df2 <- read_excel(i, sheet = "Trial2")
df3 <- read_excel(i, sheet = "Trial3")
df4 <- read_excel(i, sheet = "Trial4")
write.xlsx(list(df1, df2, df3, df4), file = paste0('Out', i, '.xlsx'),
sheetName = c("df1", "df2", "df3", "df4"))})
How can I output the files as "aaa.xlsx" and "bbb.xlsx" instead? I understand that I can use the function file.rename after the .xlsx files have been output with the wrong names but I cannot seem to get the right syntax for this.
Filename <- list.files(pattern = ".xlsm.xlsx$")
Newname <- sub("^xlsm.xlsx$", "xlsx", Filename)
file.rename(Filename, Newname)
You could use tools::file_path_sans_ext and add the extension to generate the name directly:
paste0(tools::file_path_sans_ext("aaa.xlm"), ".xlsx")
#> [1] "aaa.xlsx"
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
}
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)