100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Data Import and Export in R

Master reading and writing common file formats in R — CSV, Excel, and RDS — and know which function fits which situation.

Data StructuresBeginner9 min readJul 10, 2026
Analogies

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.

r
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

Was this page helpful?

Topics covered

#Programming#RProgrammingStudyNotes#DataImportAndExportInR#Data#Import#Export#Reading#StudyNotes#SkillVeris#ExamPrep