Reads a delimited text file into a base R data frame, using the bundled
zsv C parser. The file is read twice: once to establish the shape and
validate it, once to fill columns that were allocated at their exact
final length.
Usage
read_csv(
file = NULL,
header = TRUE,
delimiter = ",",
na = c("", "NA"),
col_types = NULL,
text = NULL
)Arguments
- file
Path to a local file, as a single string.
~is expanded. Supply this ortext, not both.- header
If
TRUE(the default), the first record supplies the column names. IfFALSE, every record is data and columns are namedV1,V2, ... IfNA, detect: the first record is treated as names unless one of its unquoted fields looks like a number or a logical, in which case it is data. A quoted field is always text, and so always counts as a name:"2024"and"TRUE"are column names where bare2024andTRUEare data. Header values are always text: they are never matched againstnaand never type-inferred.- delimiter
The field delimiter, as a single ASCII character. Defaults to
",". A newline, carriage return, form feed or double quote is not allowed.- na
Character vector of cell values to read as missing, or
NULLto disable missing-value matching. Matching happens after unquoting and is exact: no whitespace is trimmed, soNAand"NA"are both missing under the default but" NA"is not.- col_types
NULLto infer each column's type, or a character vector of"logical","integer","double"or"character". A single value applies to every column; otherwise give one per column. A cell that cannot be converted to a forced type is an error, not a missing value.- text
The CSV itself, as a character vector, instead of a path. A vector of several elements is joined with newlines, so each element is one line —
readLines()output reads back unchanged. The string's declared encoding is honoured and converted to UTF-8, so a latin1 string reads correctly where a latin1 file is still an error.
Value
A data.frame with one column per field. Names come from the
first record when header = TRUE, or when header = NA and that record
is detected as names; otherwise they are V1, V2, ... An empty file,
or one of nothing but blank lines, gives a data frame with zero rows and
zero columns; a header-only file gives zero rows but one column per
header field.
Details
Some behavior worth knowing before you rely on it:
Blank lines are skipped, wherever they appear, and do not count as rows. A line holding only whitespace or only delimiters is not blank: it is a record of empty cells and must match the table's width. In a single-column file, write an intentional empty cell as
""— a bare empty line is skipped.Every record must have the same width. A mismatch is an error; short rows are not padded.
Column names are kept exactly as they appear, including duplicates and empty strings. No name repair is performed.
Text must be valid UTF-8. A byte sequence that is not, or an embedded NUL, is an error rather than something passed through to fail later. A UTF-8 BOM is ignored.
A CR LF pair inside a quoted field is normalised to a single LF.
header = NAlooks at the first record only, and at nothing else: not the rest of the file, notcol_types, and notna. It therefore reaches a different verdict fromdata.table::fread()and DuckDB, which compare the first record against the types of the rest, on three shapes — and the row count moves in both directions:an unquoted header of numeric-looking names over numeric columns, such as
id,2024,2025above1,5,6, reads as data, so the name record becomes a row and you get one row more;a first record that is entirely missing values,
NA,NA,NAabove1,2,3, reads as a header, costing one row;a headerless first record of entirely quoted numbers,
"1","2"above"3","4", reads as a header, costing one row.
Detection is a convenience for files whose shape you do not know. When you do know, pass
header = TRUEorheader = FALSEand none of this applies.
See also
sniff_csv(), to see the header verdict and inferred types
before committing to them — and to pin them down so nothing is
inferred on the next run.
Examples
# A small CSV given directly, rather than from a file
read_csv(text = "a,b\n1,2")
#> a b
#> 1 1 2
# A character vector is one line per element
read_csv(text = c("id,name", "1,Ada", "2,Linus"))
#> id name
#> 1 1 Ada
#> 2 2 Linus
path <- tempfile(fileext = ".csv")
write.csv(
data.frame(id = 1:3, name = c("Ada", "Linus", "Grace")),
path,
row.names = FALSE
)
read_csv(path)
#> id name
#> 1 1 Ada
#> 2 2 Linus
#> 3 3 Grace
# Force a column's type rather than inferring it
read_csv(path, col_types = c("character", "character"))
#> id name
#> 1 1 Ada
#> 2 2 Linus
#> 3 3 Grace
# Detect whether the first record is a header
read_csv(path, header = NA)
#> id name
#> 1 1 Ada
#> 2 2 Linus
#> 3 3 Grace
unlink(path)