R Programming Quiz: Writing Csv Files
10 questions · exam conditions
0:00
Writing Csv FilesQuestion 1 of 10

R's working directory is /project, and the directory /project/exports already exists. The file /project/exports/run.csv also exists. An analyst runs write.csv(x, "exports/run.csv", row.names = FALSE).

What is the expected effect of this command?

It replaces /project/exports/run.csv with x, omitting row names
It appends x to /project/exports/run.csv, omitting row names
It replaces /exports/run.csv with x, using the filesystem root
It fails because write.csv() cannot use a relative subdirectory path
← Back to quizzes

R Programming Quiz

R Programming Quiz: Writing Csv Files

Practice Writing Csv Files in R Programming with focused quiz questions that help you check what you know, review explanations, and build confidence with test-style prompts.

What this quiz covers

This quiz focuses on Writing Csv Files, giving you a quick way to practice the rules, question types, and explanations that matter most for R Programming.

How to use this quiz

Try each quiz question before looking at the correct answer. Use the explanations to review missed ideas, then come back to similar questions until the pattern feels familiar.

All questions

Question 1

R's working directory is /project, and the directory /project/exports already exists. The file /project/exports/run.csv also exists. An analyst runs write.csv(x, "exports/run.csv", row.names = FALSE).

What is the expected effect of this command?

  1. It replaces /project/exports/run.csv with x, omitting row names (correct answer)
  2. It appends x to /project/exports/run.csv, omitting row names
  3. It replaces /exports/run.csv with x, using the filesystem root
  4. It fails because write.csv() cannot use a relative subdirectory path
Explanation: When working with file paths in R, the key concept to understand is how the working directory interacts with relative paths. R resolves relative paths by prepending the current working directory, so "exports/run.csv" becomes /project/exports/run.csv when your working directory is /project. Since that file already exists, write.csv() will simply overwrite it with the contents of x. The row.names = FALSE argument suppresses the automatic row index column that R would otherwise prepend to the output. This makes A the correct outcome — the existing file is replaced with x, and row names are omitted. B is wrong because write.csv() has no append functionality. Unlike write() or cat(), which accept an append argument, write.csv() always overwrites the target file. If you need to append CSV data, you'd use write.table() with append = TRUE. C describes what would happen if the path began with /, making it absolute from the filesystem root. Because "exports/run.csv" has no leading slash, it is a relative path anchored to the working directory, not the root. D is a common misconception — R handles relative paths with subdirectories just fine. The only requirement is that the subdirectory itself already exists; write.csv() will not create missing intermediate directories. A useful rule of thumb: in R, paths starting with / are absolute, everything else is relative to getwd(). When a question mentions the working directory, always mentally prepend it to any relative path before evaluating the answer choices.

Question 2

A programmer tries to create a semicolon-delimited file by running write.csv(d, "d.csv", sep = ";", row.names = FALSE).

What is the most likely result?

  1. A semicolon-delimited file is written because sep overrides the default comma separator
  2. A comma-delimited file is written, and a warning states that sep was ignored (correct answer)
  3. A comma-delimited file is written silently because sep is accepted but unused
  4. No file is written because sep is not a recognized argument for this function
Explanation: When working with R's file-writing functions, it's crucial to understand the difference between write.csv() and write.table() — they look similar but behave very differently regarding arguments. write.csv() is a convenience wrapper around write.table() that enforces comma-separated formatting by design. The R documentation explicitly states that certain arguments — including sep — are fixed within write.csv() and cannot be overridden by the user. However, rather than throwing an error or silently ignoring your input, R issues a warning telling you that sep was ignored, and then proceeds to write the file using the default comma delimiter. That makes B the correct answer: you do get a file, but it's comma-delimited, and R politely tells you something went wrong with your call. A is wrong because sep does not override the delimiter in write.csv() — the whole point of the function is that the separator is locked in as a comma. C is close but misses the key detail: R doesn't stay silent. It actively warns you, which is an important behavioral distinction. D is incorrect because sep is technically recognized as a parameter name by R's argument-matching system — it's just not permitted to change behavior here, which triggers a warning rather than an error. A practical study tip: if you need a custom delimiter like semicolons, use write.table(d, "d.csv", sep = ";", row.names = FALSE) instead. On R exams, questions about write.csv() often test whether you know which arguments are fixed — always check the documentation for "these arguments cannot be changed" language.

Question 3

A one-column data frame contains the character value He said "go, now". It is written using readr::write_csv(), whose default quoting behavior is used.

Which text represents that value correctly in the CSV data row?

  1. "He said ""go, now""" (correct answer)
  2. "He said \"go, now\""
  3. "He said "go, now""
  4. He said ""go, now""
Explanation: When working with CSV formatting in R, the key question is: how does the CSV standard handle special characters that appear inside a quoted field? The RFC 4180 CSV standard — which readr follows — uses quote doubling to escape embedded double quotes. That is, any literal " inside a quoted field is represented as "". So for the value He said "go, now", readr::write_csv() will wrap the entire field in double quotes (because it contains a comma and quotes), then escape each internal double quote by doubling it. The result is "He said ""go, now""" — the field opens with ", the two internal quotes each become "", and the field closes with ". That makes A the correct answer. B is wrong because it uses backslash escaping (\"), which is common in programming languages like Python or JavaScript but is not part of the CSV standard. readr does not produce backslash-escaped quotes. C is wrong because it only wraps the field in outer quotes without escaping the internal ones at all — "He said "go, now"" — leaving ambiguous, malformed CSV that a parser would misread. D is wrong because it applies quote doubling to the internal characters but forgets to wrap the entire field in enclosing double quotes, which are required whenever a field contains commas or quotes. As a study tip, remember: in CSV land, the escape character for a double quote is another double quote, not a backslash. When you see escape-sequence options on CSV questions, backslash choices are almost always traps.

Question 4

A data frame results contains some missing values. A downstream application requires a comma-separated file with column names, no row-name field, and an empty field for every missing value.

Which command meets all of these requirements?

  1. write.csv(results, "results.csv", row.names = FALSE, na = "") (correct answer)
  2. write.csv(results, "results.csv", row.names = TRUE, na = "")
  3. readr::write_csv(results, "results.csv", row.names = FALSE, na = "")
  4. write.csv(results, "results.csv", row.names = FALSE, na = "NA")
Explanation: When writing data frames to CSV files in R, you need to think carefully about three independent concerns: the function you use, how missing values are represented, and whether row names are included. Each of these is controlled by a separate argument, and exam questions like this one test whether you can identify all three simultaneously. The correct choice is A. write.csv() is the standard base R function for writing comma-separated files, and it automatically includes column headers. Setting row.names = FALSE suppresses the extra index column that R would otherwise prepend to every row — exactly what a downstream application expecting clean CSV typically needs. Setting na = "" ensures every NA value is written as a blank field rather than the literal string "NA", satisfying the "empty field for every missing value" requirement. B fails because row.names = TRUE is the default, meaning an unwanted index column (1, 2, 3, …) appears as the first field in the output — violating the "no row-name field" requirement. C is a trap for students familiar with the readr package. readr::write_csv() does not accept a row.names argument at all — passing it will throw an error or be silently ignored. The readr function handles row names differently by design, so mixing its syntax with base R arguments is incorrect. D uses na = "NA", which writes the literal text "NA" into missing fields rather than leaving them empty — directly violating the passage requirement. A useful pattern to remember: whenever a question lists multiple output requirements, mentally check each argument in your chosen function against every requirement before committing to an answer.

Question 5

An analyst runs d <- data.frame(id = c("A", "B"), score = c(8, 9)) followed by write.csv(d, "scores.csv"). No other arguments are supplied.

Which pair of lines appears first in scores.csv?

  1. "id","score" followed by "A",8
  2. "","id","score" followed by "1","A",8 (correct answer)
  3. "row.names","id","score" followed by 1,"A",8
  4. "1","id","score" followed by "2","A",8
Explanation: When working with write.csv() in R, the critical detail to understand is how R handles row names by default. Every data frame in R automatically carries row names — by default, these are just sequential integers (1, 2, 3, ...). Unless you explicitly suppress them with row.names = FALSE, write.csv() writes those row names as an extra first column in the output file. This is exactly what makes B correct. Since no extra arguments are supplied, R includes the row names column, but leaves its header blank — giving you "","id","score" on the first line. The first data row then becomes "1","A",8, where "1" is the quoted row name for the first observation. A is tempting because it looks like a "clean" CSV with just the column names you defined, but it omits the row names column entirely — that only happens when you pass row.names = FALSE. C is wrong because R doesn't label the row names column "row.names" in the header. The header for that column is literally an empty string "", not a descriptive label. D confuses row names with column values. It incorrectly implies the column headers themselves get numbered, which is not how write.csv() behaves under any default setting. A practical tip: whenever you see write.csv() without row.names = FALSE, immediately expect an extra unnamed first column in the output. In real workflows, analysts almost always add row.names = FALSE to avoid this "phantom column" that can trip up downstream data imports.

Question 6

A data frame measurements has meaningful row names such as S01 and S02. A CSV consumer requires these labels in an ordinary first column named sample, but it must not receive an additional unnamed row-number column.

Which approach produces the required file?

  1. readr::write_csv(measurements, "m.csv"), because row names are automatically promoted to the first data column
  2. write.csv(measurements, "m.csv", row.names = FALSE), because suppressing row names still preserves them as data values
  3. out <- data.frame(sample = rownames(measurements), measurements, row.names = NULL); readr::write_csv(out, "m.csv") (correct answer)
  4. measurements$sample <- rownames(measurements); write.csv(measurements, "m.csv", row.names = TRUE), because the explicit column replaces the row-name field
Explanation: When working with CSV export in R, you need to track two separate things: where the row names live (as metadata on the data frame) and where they appear (as a printed column in the file). These are not the same thing, and conflating them is exactly what the distractors exploit. Option C is correct because it explicitly moves the row names into a real data column before writing. rownames(measurements) extracts the labels, data.frame(sample = ..., measurements, row.names = NULL) stitches them in as an ordinary first column while dropping the row-name metadata, and then readr::write_csv() writes cleanly — no index column, no unnamed prefix. Option A is wrong because readr::write_csv() silently drops row names entirely rather than promoting them into a column. Your S01, S02 labels simply disappear. Option B is wrong on two counts. row.names = FALSE suppresses printing the row names but does not preserve them as data values — they are just omitted. The resulting file has no sample column at all. Option D gets the column created correctly, but then passes row.names = TRUE to write.csv(), which writes the row names again as an additional unnamed first column. The consumer would receive a redundant, unlabeled index column alongside your sample column — the opposite of what's required. A reliable mental model: treat row names as invisible metadata. If you need them in the file, always pull them out with rownames() and bind them as a real column before writing, then write with a method that suppresses the metadata index.

Question 7

An analyst wants to write d as a gzip-compressed CSV with a header and no row-name field. The desired path is archive.csv.gz.

Which command accomplishes this directly based on the filename extension?

  1. write.csv(d, "archive.csv.gz", row.names = FALSE)
  2. write.csv(d, "archive.csv", gzip = TRUE, row.names = FALSE)
  3. readr::write_csv(d, "archive.csv", compress = "gzip")
  4. readr::write_csv(d, "archive.csv.gz") (correct answer)
Explanation: When working with file I/O in R, it's worth knowing the difference between base R and the readr package — particularly how each handles compression. The readr package is designed to be "smart" about file extensions: if you give write_csv() a path ending in .gz, it automatically applies gzip compression without any extra arguments. That's exactly what D does — readr::write_csv(d, "archive.csv.gz") writes a gzip-compressed CSV with a header by default and no row names (since readr never writes row names). Clean, direct, and extension-aware. A is tempting because base R's write.csv() does actually support .gz extensions — but the question asks what works directly based on the filename extension, and the phrasing hints toward readr's automatic behavior. More importantly, the other distractors reveal the trap: B uses write.csv() with a gzip = TRUE argument, which doesn't exist in base R's write.csv(). That argument will either be silently ignored or throw an error. C calls readr::write_csv() with a compress = "gzip" argument — but write_csv() has no such parameter; compression is handled purely through the file extension, not an explicit argument. A useful rule of thumb: in readr, compression is implicit via extension (.gz, .bz2, .xz), not explicit via arguments. When you see options offering extra compression parameters for readr functions, that's usually a distractor. Memorize that readr::write_csv() never writes row names and auto-compresses based on the file path — two behaviors that distinguish it cleanly from base R.

Question 8

The file daily.csv already contains yesterday's data. An analyst runs readr::write_csv(today, "daily.csv"), where today has three columns and five rows.

Assuming the command completes successfully, what is the resulting file expected to contain?

  1. Yesterday's rows followed by five new rows, with one shared header
  2. Only today's five rows, preceded by the three column names (correct answer)
  3. Only today's five rows, with no column-name header included
  4. Yesterday's data unchanged because existing files are not overwritten
Explanation: When working with file I/O functions in R, the critical question to ask is: does this function overwrite or append? readr::write_csv() is a write function, meaning it creates a fresh file from scratch every time it runs — it does not check for existing content. When write_csv(today, "daily.csv") executes successfully, it replaces whatever was in daily.csv with the contents of the today data frame. By default, write_csv() includes the column names as a header row, followed by the data rows. Since today has five rows and three columns, the resulting file contains exactly six lines: one header row with the three column names, plus five data rows. That makes B the correct answer. A is wrong because write_csv() does not append — it overwrites. To add rows to an existing file, you would need write_csv(today, "daily.csv", append = TRUE). Without that argument, yesterday's data is gone. C is wrong because write_csv() writes column names by default. To suppress the header, you would explicitly pass col_names = FALSE, which was not done here. D is wrong because R does not protect existing files from overwriting. Unlike some systems that warn you or raise an error, write_csv() silently replaces the file — a common source of accidental data loss. A useful rule of thumb: in R, "write" means overwrite unless you specifically say otherwise. Always double-check whether you need append = TRUE before saving to an existing file.

Question 9

A file was initially created with readr::write_csv(old, "log.csv"), so it already contains one header line and several data rows. A compatible one-row data frame new is then written with readr::write_csv(new, "log.csv", append = TRUE).

How does the second command normally modify log.csv?

  1. It inserts the new row immediately after the existing header line in the file
  2. It appends another header line followed by the new row at the end of the file
  3. It replaces all existing content with only the new row and a fresh header
  4. It appends the new row at the end of the file without writing another header line (correct answer)
Explanation: When working with file I/O in R, the key distinction to understand is how the append parameter controls whether new content replaces or extends a file. This question specifically tests your knowledge of readr::write_csv() behavior when append = TRUE. By default, write_csv() writes a header line followed by data rows, overwriting whatever was in the file. When you pass append = TRUE, the function changes its behavior in two important ways: it opens the file in append mode (adding content at the end rather than overwriting), and it suppresses the header line. This means the new row lands cleanly at the bottom of the existing file, perfectly extending the dataset without duplicating column names. That makes D the correct answer. A is wrong because write_csv() has no mechanism to insert rows at a specific position within a file — file streams don't work that way in R or most languages. Writing always happens at the beginning (overwrite) or the end (append). B describes what would happen if append = TRUE did not suppress the header — writing a header plus the row at the end. This is the most tempting distractor, and it reflects what some other tools do. However, readr specifically omits the header when appending, which is exactly why append = TRUE exists as a safe logging pattern. C describes the default behavior of write_csv() without append = TRUE — it would overwrite the file entirely. As a study tip, remember the pattern: append = TRUE in readr means data only, no header. This is by design, so appending to a CSV never corrupts the column structure.

Question 10

Consider d <- data.frame(code = c("A1", "B,2"), n = c(3, 4)). The object is written once with write.csv(d, "base.csv", row.names = FALSE) and once with readr::write_csv(d, "readr.csv"), using all other defaults.

Which statement correctly compares the quoting in the two files?

  1. Both files quote every character value, including A1 and the column names
  2. Neither file quotes B,2, because commas inside character values are preserved
  3. base.csv generally quotes character fields, while readr.csv quotes B,2 only as needed (correct answer)
  4. readr.csv generally quotes character fields, while base.csv quotes B,2 only as needed
Explanation: When comparing R's base and readr CSV writers, the key concept is default quoting strategy — specifically, whether a function quotes all character fields or only those that require quoting to be parsed correctly. Base R's write.csv() applies a conservative, quote-everything approach: by default (quote = TRUE), it wraps all character and factor values — as well as column names — in double quotes. So in base.csv, both "A1" and "B,2" appear quoted, along with the header "code". The readr package takes a minimal quoting approach: write_csv() only quotes values when necessary to avoid ambiguity — specifically when a value contains a comma, quote character, or newline. So in readr.csv, A1 appears unquoted, while B,2 gets quoted because the embedded comma would otherwise break CSV parsing. This makes C correct: base quotes broadly, readr quotes only as needed. A is wrong because it claims both files quote every character value, including A1. That's true for base but not for readr, which leaves A1 unquoted. B is wrong in a dangerous way — it claims neither file quotes B,2, but any correct CSV writer must quote a value containing a comma; otherwise the file becomes unparseable. D reverses the two functions entirely, attributing readr's behavior to base and vice versa — a classic swap trap. A useful memory hook: base = broad quoting, readr = restrained quoting. When exam questions contrast these two writers, always ask yourself which one quotes only when structurally necessary — that's readr.