R Write CSV Files
After analyzing or cleaning data in R, you often need to save the results. Writing to CSV format preserves your data in a plain text file that anyone can open — in Excel, Google Sheets, Python, or another R session. R makes this as easy as reading: one function call does the job.
Basic: write.csv()
students <- data.frame(
name = c("Anita","Ravi","Seema","Kiran"),
age = c(22, 25, 21, 23),
score = c(88, 72, 45, 95),
grade = c("A","B","F","A")
)
write.csv(students, "students_output.csv")
This creates a file called students_output.csv in your working directory. Open it in any spreadsheet application.
The row.names Problem
By default, write.csv() adds a column of row numbers (1, 2, 3…) to the file. This is almost never what you want. Always suppress it:
write.csv(students, "students_output.csv", row.names = FALSE)
With row.names=TRUE (default): With row.names=FALSE: ──────────────────────────── ──────────────────────────── "","name","age","score" "name","age","score" "1","Anita",22,88 "Anita",22,88 "2","Ravi",25,72 "Ravi",25,72 ← extra column! ← clean
Key Arguments
Argument Default Description ────────────────────────────────────────────────────────────────── file (required) Output file path row.names TRUE Include row numbers? (use FALSE) col.names TRUE Include column names as first row? sep "," Column separator na "NA" How to write missing values append FALSE Append to existing file instead of overwrite quote TRUE Wrap strings in quotes? fileEncoding "" Output encoding (use "UTF-8" for non-ASCII)
write_csv() from readr (Recommended)
library(readr) write_csv(students, "students_output.csv")
- Never writes row names (no need for
row.names=FALSE) - Faster for large files
- Handles special characters and encoding better
- Consistent with read_csv() from the same package
Writing Multiple Data Frames to Separate Files
datasets <- list(
north = data.frame(region="North", sales=c(100,200)),
south = data.frame(region="South", sales=c(300,150))
)
for (region_name in names(datasets)) {
filename <- paste0(region_name, "_sales.csv")
write.csv(datasets[[region_name]], filename, row.names=FALSE)
cat("Saved:", filename, "\n")
}
Appending Rows to an Existing CSV
new_row <- data.frame(name="Dev", age=24, score=80, grade="B")
write.csv(new_row, "students_output.csv",
row.names=FALSE,
append=TRUE,
col.names=FALSE) # don't repeat headers when appending
Writing with a Different Separator
# Semicolon-separated (common in Europe)
write.csv2(students, "students_eu.csv", row.names=FALSE)
# Tab-separated
write.table(students, "students.tsv",
sep="\t",
row.names=FALSE,
quote=FALSE)
Complete Workflow: Clean and Save
# Load raw data
raw <- read.csv("raw_sales.csv")
# Clean
clean <- na.omit(raw)
clean$revenue <- as.numeric(clean$revenue)
clean <- clean[clean$revenue > 0, ]
# Add analysis column
clean$revenue_category <- ifelse(clean$revenue > 10000, "High", "Low")
# Save cleaned version
write.csv(clean, "clean_sales.csv", row.names=FALSE)
cat("Saved", nrow(clean), "rows to clean_sales.csv\n")
Always use row.names = FALSE with write.csv(). The extra row number column it adds by default confuses most downstream tools. For modern workflows, write_csv() from readr is the cleaner choice — no surprises, no extra arguments needed.
