R: R Excel 文件读写

最后更新:2026-08-26

上一课我们学了 CSV,但实际项目 60% 的数据存在 Excel 里——manager、销售、财务都喜欢发 Excel。这一课我们学 R 读写 Excel 的标准方案:readxl + writexl不依赖 Java(不像 xlsx 包要装 JDK)。

读完这一课你就能读取多 sheet 的财务报表、写出带格式的 Excel 报表。

1. 你将学到



2. 一个财务月报的故事

(1) 痛点:30 个 Excel 手要废了

Alice是财务,每月初要汇总 30 个分公司的"销售月报":

如果用 Excel 自带的 Power Query 跨文件处理很复杂;用 Python openpyxl 慢;用 R xlsx 包要装 Java——

(2) R 的解法

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 的威力。

100%
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 种格式

100%
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 名
R
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) 实战:常用参数

R
# 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 参数

R
# 方式 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 里经常有标题、注释、空行,指定范围精准读取

R
# 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 参数

R
# 方式 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 优势

(2) 基本语法

R
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
# 把 R 里的数据框批量输出
list_of_dfs <- list(
  销售 = sales_df,
  回款 = payment_df,
  库存 = stock_df
)
write_xlsx(list_of_dfs, "monthly_report.xlsx")
cat("=== 报表已生成:monthly_report.xlsx ===\n")
⚠️ 注意:writexl 不支持单元格格式(颜色、字体、公式)。要格式用 openxlsx

R
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 个分公司财务月报汇总

R 📖 仅展示
# ============================================
# 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)
逻辑代码 84 行(超过 40 行限制,仅展示)

预期输出(节选):

TEXT 📖 仅展示
=== 各城市销售分析 ===
# A tibble: 3 × 4
  city  订单数 总销售 平均订单
  <chr>  <int>   <int>     <dbl>
1 上海      5   14325    2865  
2 北京      5   12289    2458. 
3 广州      5   11234    2247. 

❓ 常见问题

Q readxl 读取乱码怎么办?
A readxl 自动处理 UTF-8 和 GBK 编码。如真乱码,先用 iconv 转换文件编码再读。
Q 怎么读指定 sheet?
A read_excel("file.xlsx", sheet = "销售明细")sheet = 1(按编号)。excel_sheets(file) 列出所有 sheet 名。
Q 怎么只读部分范围?
Arange = "A1:D100" 指定单元格范围。或 range = "A1:D1" 锚定表头自动扩展。
Q 怎么读带合并单元格的 Excel?
A 合并单元格里只有左上角有值,其他位置是空。readxl 按"未合并"读,合并区域的"非左上"位置是 NA。需要处理时用 openxlsxmergeCells 参数。
R
library(openxlsx)
wb <- loadWorkbook("existing.xlsx")
addWorksheet(wb, "新sheet")
writeData(wb, "新sheet", new_df)
saveWorkbook(wb, "existing.xlsx")

📖 小节


📝 作业

  1. 基础题:创建一个含 3 个 sheet(销售/回款/库存)的 Excel 文件,用 write_xlsx() 输出。用 excel_sheets() 验证 sheet 名正确,用 read_excel() 读取"销售" sheet 验证数据正确。

  2. 基础题:读取上题的 Excel,用 range = "A1:B5" 只读 1-5 行的 A-B 列,验证只读了 2 列 5 行。

  3. 基础题:读取上题的"销售" sheet,用 col_types = c("numeric", "date", "text", "numeric") 显式指定列类型,验证类型正确。

  4. 进阶题:模拟 3 个分公司 Excel(每个 3 sheet),用 lapply 批量读取所有 sheet,用 bind_rows 合并同类型数据。统计各城市的总销售额。

  5. 挑战题:用 openxlsx 写一个带格式的 Excel:① 标题行加粗红字 ② 数字列右对齐 ③ 数值列用千分位 ④ 列宽自适应。保存为 formatted_report.xlsx,用 Excel 打开验证效果(截图保存)。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏