Reading Delimited Text Files
Base R's read.csv() reads a comma-delimited text file into a data frame, with arguments like header = TRUE (first row as column names), sep = ',' (delimiter), and historically stringsAsFactors (now FALSE by default since R 4.0). The tidyverse's readr::read_csv() is a faster, more predictable alternative: it returns a tibble, never coerces strings to factors, prints a column specification showing the type it guessed for each column, and handles larger files noticeably faster than base R's implementation.
Cricket analogy: read.csv() parsing a ball-by-ball CSV into a data frame is like a scorer transcribing a paper scoresheet into a digital scorecard, row by row, column by column.
Writing Data Back Out
write.csv(df, 'file.csv', row.names = FALSE) writes a data frame back to disk as comma-separated text; omitting row.names = FALSE adds an unwanted extra column of row numbers to the output file, a very common beginner mistake. readr's write_csv(df, 'file.csv') is the tidyverse equivalent, never writes row names by default, and writes UTF-8 encoded output consistently across platforms, which base R's write.csv() does not guarantee.
Cricket analogy: Forgetting row.names=FALSE and getting an extra numbered column in an exported scorecard CSV is like a printed scoresheet accidentally including an extra unlabeled column of row numbers nobody asked for.
library(readr)
sales <- read_csv("sales_2026.csv") # tibble, types guessed & printed
write_csv(sales, "sales_clean.csv") # no row-name column added
# Preserve exact R object state
saveRDS(sales, "sales.rds")
sales2 <- readRDS("sales.rds") # factors, Dates restored exactly
# Multiple objects at once
save(sales, sales2, file = "session.RData")
load("session.RData")Working with Excel and Other Formats
Excel files need a dedicated package since they aren't plain text: readxl::read_excel('file.xlsx', sheet = 'Sheet2') reads a specific worksheet into a tibble, with excel_sheets('file.xlsx') letting you list available sheet names first. For statistical software formats, haven::read_sav()/read_dta()/read_sas() import SPSS, Stata, and SAS files respectively, preserving their variable labels as attributes; and jsonlite::fromJSON('file.json') parses JSON into nested lists or, for flat JSON, directly into a data frame.
Cricket analogy: excel_sheets('season.xlsx') listing sheet names before reading one is like checking a scorebook's table of contents (per-match tabs) before opening the specific match you want to analyze.
readr::read_csv() only scans the first 1000 rows by default to guess each column's type, which is fast but can misfire on files where a numeric column has stray text far down (e.g., a note in row 5000) — passing col_types explicitly or increasing guess_max avoids silent type-guessing errors on large files.
Saving R Objects Natively: RDS and RData
saveRDS(obj, 'model.rds') and readRDS('model.rds') save and restore a single R object exactly as it was — including factor levels, ordering, Date classes, and nested list structures — because RDS is R's native binary serialization format, unlike text formats that lose type information. save(obj1, obj2, file = 'workspace.RData') and load('workspace.RData') work similarly but can bundle multiple named objects into one file, restoring them directly into the environment under their original names, which is convenient for checkpointing an entire analysis session.
Cricket analogy: saveRDS() preserving a factor's exact level order (e.g., 'Loss'<'Draw'<'Win') when saving a match-result dataset is like archiving an original scorebook exactly as written, rather than retyping it and risking losing the recorded order.
Round-tripping data through CSV loses R-specific type information: factor levels and their order, Date/POSIXct classes, and integer vs. double distinctions are all flattened to plain text on write and must be re-inferred (often incorrectly) on the next read.csv() — use saveRDS() instead of CSV whenever you need to preserve an object exactly between R sessions.
- read.csv()/read_csv() import delimited text into a data frame/tibble; write.csv()/write_csv() write it back out.
- Always pass row.names = FALSE to write.csv() to avoid an unwanted index column in the output.
- readxl::read_excel(sheet=) reads a specific worksheet; excel_sheets() lists available sheets first.
- haven handles SPSS/Stata/SAS formats; jsonlite::fromJSON() parses JSON into lists or data frames.
- saveRDS()/readRDS() preserve a single R object exactly, including factor levels and Date classes.
- save()/load() checkpoint multiple named objects into one .RData file at once.
- CSV round-trips lose type metadata; use RDS when exact object fidelity matters.
Practice what you learned
1. What is a common mistake when using write.csv()?
2. Which package function reads a specific worksheet from an Excel file?
3. What does saveRDS()/readRDS() preserve that CSV round-tripping does not?
4. How many R objects can save()/load() handle in a single .RData file?
5. Why might readr::read_csv() misguess a column's type on a large file?
Was this page helpful?
You May Also Like
Data Frames in R
Understand R's core tabular data structure — how data.frame combines vectors of equal length into rows and columns for real-world datasets.
Factors in R
Learn how R represents categorical data with factors — encoding fixed levels efficiently and controlling ordinal comparisons.
Vectors in R
Learn how R's core data structure — the atomic vector — stores, indexes, and vectorizes operations over ordered collections of same-typed values.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics