R: R Excel 文件读写
最后更新:2026-08-26
上一课我们学了 CSV,但实际项目 60% 的数据存在 Excel 里——manager、销售、财务都喜欢发 Excel。这一课我们学 R 读写 Excel 的标准方案:
readxl+writexl,不依赖 Java(不像xlsx包要装 JDK)。
读完这一课你就能读取多 sheet 的财务报表、写出带格式的 Excel 报表。
1. 你将学到
- Excel 文件的 3 种格式(.xlsx / .xls / .xlsm)
- readxl 包的安装与 4 个核心函数
- 多 sheet 读取与批量处理
- read_excel 8 个常用参数(sheet、range、col_types、na)
- writexl 写出 Excel
- 与 openxlsx 的差异
- 实战:财务月报批量处理
2. 一个财务月报的故事
(1) 痛点:30 个 Excel 手要废了
Alice是财务,每月初要汇总 30 个分公司的"销售月报":
- 每个 Excel 3 个 sheet(销售明细、回款、库存)
- 每个 Excel 格式相同
- 总计 90 个表要读入 R 分析
如果用 Excel 自带的 Power Query 跨文件处理很复杂;用 Python openpyxl 慢;用 R xlsx 包要装 Java——
(2) R 的解法
# 1. 装包(不依赖 Java)
install.packages("readxl")
install.packages("writexl")
# 2. 列出所有 Excel 文件
files <- list.files("reports/", pattern = "\\.xlsx$", full.names = TRUE)
# 3. 批量读取所有 sheet
library(readxl)
all_data <- lapply(files, function(f) {
list(
sales = read_excel(f, sheet = "销售明细"),
payment = read_excel(f, sheet = "回款"),
stock = read_excel(f, sheet = "库存")
)
})
# 4. 合并分析
library(dplyr)
combined <- bind_rows(lapply(all_data, function(d) d$sales))
5 行代码搞定 30 个 Excel × 3 个 sheet = 90 张表。这就是 readxl 的威力。
graph TB
A[30 个分公司 Excel 文件] --> B[list.files 列出]
B --> C[lapply 批量读]
C --> D[excel_sheets 查 sheet]
D --> E[read_excel 每个 sheet]
E --> F[bind_rows 合并]
F --> G[group_by + summarise 汇总]
G --> H[write_xlsx 输出报表]
style A fill:#cce5ff
style B fill:#d4edda
style C fill:#fff3cd
style D fill:#f8d7da
style E fill:#e1d4ff
style F fill:#ffe1d4
style G fill:#cce5ff
style H fill:#d4edda
3. Excel 文件的 3 种格式
mindmap
root((Excel 文件<br/>3 种格式))
.xlsx
Excel 2007+
最大 @,000 rows of
现代标准
工具: readxl / openxlsx
.xls
Excel 97-2003
最大 65536 行
老格式
工具: readxl
.xlsm
启用宏
含 VBA
工具: readxl 不读宏
选择
新项目: .xlsx
老数据: .xls
含宏: .xlsm
(1) 格式对比
| 格式 | 后缀 | 最大行列 | 兼容性 | R 读取 |
|---|---|---|---|---|
| Excel 2007+ | .xlsx |
1048576 × 16384 | 现代标准 | readxl / openxlsx |
| Excel 97-2003 | .xls |
65536 × 256 | 老格式 | readxl |
| Excel 启用宏 | .xlsm |
同 xlsx | 含 VBA | readxl(不读宏) |
(2) R 读 Excel 的 3 个包对比
| 包 | 依赖 | 速度 | 功能 | 推荐度 |
|---|---|---|---|---|
| readxl | 纯 R(C++) | 快 | 仅读取 | ⭐⭐⭐ 读取首选 |
| writexl | 纯 R(C++) | 快 | 仅写入 | ⭐⭐⭐ 写入首选 |
| openxlsx | 纯 R | 中 | 读写+格式 | ⭐⭐ 需要格式时用 |
| xlsx | 要 Java | 慢 | 读写+公式 | ❌ 不推荐(依赖重) |
readxl + writexl(最简单);需要单元格格式/公式用 openxlsx;避免用 xlsx 包(要装 Java)。
4. readxl 4 个核心函数
(1) 函数速查表
| 函数 | 作用 |
|---|---|
read_excel() |
读 .xlsx 或 .xls(自动判断) |
read_xlsx() |
只读 .xlsx(更快) |
read_xls() |
只读 .xls(老格式) |
excel_sheets() |
列出所有 sheet 名 |
library(readxl)
# 1. 列出所有 sheet
sheets <- excel_sheets("report.xlsx")
print(sheets)
# [1] "销售明细" "回款" "库存"
# 2. 读指定 sheet
sales <- read_excel("report.xlsx", sheet = "销售明细")
# 或按 sheet 编号
sales <- read_excel("report.xlsx", sheet = 1)
# 3. 读所有 sheet(返回 list)
all_sheets <- lapply(excel_sheets("file.xlsx"), function(name) {
read_excel("file.xlsx", sheet = name)
})
names(all_sheets) <- excel_sheets("file.xlsx")
(2) read_excel 8 个常用参数
| 参数 | 作用 | 示例 |
|---|---|---|
path |
文件路径 | "data/sales.xlsx" |
sheet |
sheet 名或编号 | 1 或 "销售明细" |
range |
读取范围 | "A1:D100" 或 "A1:D100" |
col_names |
TRUE / 自定义向量 | TRUE |
col_types |
列类型 | "text", "numeric", "date" |
na |
NA 标记 | c("", "NA") |
skip |
跳过行数 | 2(跳过标题行) |
n_max |
最大读取行数 | 1000 |
(3) 实战:常用参数
# 1. 指定 sheet
df <- read_excel("data.xlsx", sheet = "销售明细")
# 2. 指定范围(避免读表头外的注释)
df <- read_excel("data.xlsx", range = "A1:D1000")
# 3. 跳过标题行
df <- read_excel("data.xlsx", skip = 2)
# 4. 只读 1000 行
df <- read_excel("data.xlsx", n_max = 1000)
# 5. 指定列类型
df <- read_excel("data.xlsx", col_types = c("text", "numeric", "date"))
# 6. 自定义 NA
df <- read_excel("data.xlsx", na = c("", "NA", "无"))
5. read_excel 参数详解
(1) sheet 参数
# 方式 1:sheet 名(推荐)
df <- read_excel("data.xlsx", sheet = "销售明细")
# 方式 2:sheet 编号(从 1 开始)
df <- read_excel("data.xlsx", sheet = 1)
# 方式 3:NULL(默认读第一个)
df <- read_excel("data.xlsx")
(2) range 参数(最实用)
Excel 里经常有标题、注释、空行,指定范围精准读取:
# 1. 字符串范围
df <- read_excel("data.xlsx", range = "A1:D100")
# 2. 锚定单元格(自动扩展到非空区域)
df <- read_excel("data.xlsx", range = "A1:D1") # 只读 1 行(自动扩展)
# 3. 完整 A1 引用
df <- read_excel("data.xlsx", range = "A1:Z1000")
# 4. 命名区域(Excel 里定义的 Named Range)
df <- read_excel("data.xlsx", range = "SalesTable")
(3) col_types 参数
# 方式 1:字符串简写
col_types = c("text", "numeric", "date", "guess", "skip")
# 方式 2:列表
col_types = list(
text, # 字符
numeric, # 数字
date, # 日期
guess, # 自动推断
skip # 跳过
)
# 全部跳过(不读数据)
col_types = c("skip", "skip", "skip")
# 全部字符
col_types = c("text")
可用类型:"guess"(默认推断)、"logical"、"numeric"、"date"、"text"、"skip"、"list"(嵌套表)
6. 写 Excel:writexl
(1) writexl 优势
- 纯 R 实现(不依赖 Java/LibreOffice)
- 速度快(C++ 后端)
- API 简单(只有
write_xlsx())
(2) 基本语法
library(writexl)
# 1. 单 sheet 输出
write_xlsx(df, "output.xlsx")
# 2. 多 sheet 输出(用 list)
write_xlsx(
list(
"销售明细" = sales_df,
"回款" = payment_df,
"库存" = stock_df
),
"output.xlsx"
)
# 3. 追加到现有文件
# writexl 不直接支持追加,需用 openxlsx
(3) 实战
# 把 R 里的数据框批量输出
list_of_dfs <- list(
销售 = sales_df,
回款 = payment_df,
库存 = stock_df
)
write_xlsx(list_of_dfs, "monthly_report.xlsx")
cat("=== 报表已生成:monthly_report.xlsx ===\n")
openxlsx:
library(openxlsx)
# 写带格式的 Excel
wb <- createWorkbook()
addWorksheet(wb, "销售")
writeData(wb, "销售", sales_df)
addStyle(wb, "销售", style = createStyle(fontColour = "red"),
rows = 2:10, cols = 5)
saveWorkbook(wb, "formatted_report.xlsx")
7. 实战:财务报表多 sheet 批量读取
下面是一个完整工作流示例,演示如何批量处理多文件多 sheet。
▶ 示例:30 个分公司财务月报汇总
# ============================================
# 30 个分公司财务月报汇总
# 功能:批量读取 30 个 Excel × 3 个 sheet
# ============================================
library(readxl)
library(dplyr)
library(purrr)
library(writexl)
# 1. 准备示例数据
set.seed(42)
make_sales <- function(city) {
tibble(
order_id = 1:5,
date = as.Date("2024-01-01") + 0:4,
product = sample(c("A", "B", "C"), 5, replace = TRUE),
amount = sample(1000:5000, 5)
)
}
make_payment <- function(city) {
tibble(
order_id = 1:5,
paid = sample(c(TRUE, FALSE), 5, replace = TRUE),
paid_date = as.Date("2024-01-15") + 0:4
)
}
make_stock <- function(city) {
tibble(
product = c("A", "B", "C"),
stock = sample(50:200, 3)
)
}
# 模拟 3 个分公司的 Excel(每个 3 sheet)
dir.create("temp_reports", showWarnings = FALSE)
for (city in c("北京", "上海", "广州")) {
write_xlsx(
list(
"销售明细" = make_sales(city),
"回款" = make_payment(city),
"库存" = make_stock(city)
),
file.path("temp_reports", paste0(city, ".xlsx"))
)
}
# 2. 列出所有 Excel 文件
files <- list.files("temp_reports", pattern = "\\.xlsx$", full.names = TRUE)
cat("找到", length(files), "个 Excel 文件:\n")
print(files)
# 3. 查看每个文件的 sheet 名
for (f in files) {
cat("\n文件:", basename(f), "\n")
cat(" Sheet:", paste(excel_sheets(f), collapse = ", "), "\n")
}
# 4. 批量读取所有 sheet
cat("\n=== 批量读取中 ===\n")
all_reports <- lapply(files, function(f) {
city <- tools::file_path_sans_ext(basename(f))
list(
sales = read_excel(f, sheet = "销售明细") |> mutate(city = !!city),
payment = read_excel(f, sheet = "回款") |> mutate(city = !!city),
stock = read_excel(f, sheet = "库存") |> mutate(city = !!city)
)
})
names(all_reports) <- tools::file_path_sans_ext(basename(files))
# 5. 合并所有销售数据
all_sales <- bind_rows(lapply(all_reports, function(d) d$sales))
cat("\n=== 销售汇总 ===\n")
print(all_sales)
# 6. 合并所有回款数据
all_payment <- bind_rows(lapply(all_reports, function(d) d$payment))
cat("\n=== 回款汇总 ===\n")
print(all_payment)
# 7. 合并所有库存数据
all_stock <- bind_rows(lapply(all_reports, function(d) d$stock))
cat("\n=== 库存汇总 ===\n")
print(all_stock)
# 8. 综合分析
cat("\n=== 各城市销售分析 ===\n")
city_stats <- all_sales |>
group_by(city) |>
summarise(
订单数 = n(),
总销售 = sum(amount),
平均订单 = round(mean(amount), 2)
) |>
arrange(desc(总销售))
print(city_stats)
# 9. 输出汇总报表
write_xlsx(
list(
"销售汇总" = all_sales,
"回款汇总" = all_payment,
"库存汇总" = all_stock,
"城市统计" = city_stats
),
"summary_report.xlsx"
)
cat("\n=== 汇总报表已输出:summary_report.xlsx ===\n")
# 10. 清理临时文件
unlink("temp_reports", recursive = TRUE)
预期输出(节选):
=== 各城市销售分析 ===
# A tibble: 3 × 4
city 订单数 总销售 平均订单
<chr> <int> <int> <dbl>
1 上海 5 14325 2865
2 北京 5 12289 2458.
3 广州 5 11234 2247.
❓ 常见问题
iconv 转换文件编码再读。read_excel("file.xlsx", sheet = "销售明细") 或 sheet = 1(按编号)。excel_sheets(file) 列出所有 sheet 名。range = "A1:D100" 指定单元格范围。或 range = "A1:D1" 锚定表头自动扩展。NA。需要处理时用 openxlsx 的 mergeCells 参数。library(openxlsx)
wb <- loadWorkbook("existing.xlsx")
addWorksheet(wb, "新sheet")
writeData(wb, "新sheet", new_df)
saveWorkbook(wb, "existing.xlsx")
📖 小节
- readxl 读取首选——纯 R 依赖、速度快、自动处理多 sheet
- Excel 3 种格式:
.xlsx(现代)、.xls(老)、.xlsm(含宏) - 4 个核心函数:
read_excel/read_xlsx/read_xls/excel_sheets - 8 个常用参数:
sheetrangecol_typescol_namesnaskipn_maxpath - writexl 写 Excel 首选——纯 R、快、不支持格式
- 需要格式/公式用 openxlsx——功能强但 API 复杂;避免 xlsx 包(要 Java)
- 批量多文件多 sheet:循环
lapply+bind_rows合并
📝 作业
-
基础题:创建一个含 3 个 sheet(销售/回款/库存)的 Excel 文件,用
write_xlsx()输出。用excel_sheets()验证 sheet 名正确,用read_excel()读取"销售" sheet 验证数据正确。 -
基础题:读取上题的 Excel,用
range = "A1:B5"只读 1-5 行的 A-B 列,验证只读了 2 列 5 行。 -
基础题:读取上题的"销售" sheet,用
col_types = c("numeric", "date", "text", "numeric")显式指定列类型,验证类型正确。 -
进阶题:模拟 3 个分公司 Excel(每个 3 sheet),用
lapply批量读取所有 sheet,用bind_rows合并同类型数据。统计各城市的总销售额。 -
挑战题:用
openxlsx写一个带格式的 Excel:① 标题行加粗红字 ② 数字列右对齐 ③ 数值列用千分位 ④ 列宽自适应。保存为formatted_report.xlsx,用 Excel 打开验证效果(截图保存)。