---
disqus: ahb0222
GA : G-VF9ZT413CG
---
# R 快速合併多個檔案_以CSV為例
> [color=#40f1ef][name=LHB阿好伯, 2023/04/15][:earth_africa:](https://www.facebook.com/LHB0222/)
###### tags: `R`

[TOC]
# CSV
```r=
library(dplyr)
# 指定資料夾路徑
dir_path <- "C:\\R\\111Q3每日噪音監測資料(原始)"
```
## 方法一 for()
```r=
# 初始化空資料框
result_df <- data.frame()
# 循環讀取並合併CSV檔案
for (i in c(1:length(df_files))) {
temp_df <- read.csv(df_files[i], header = TRUE)
result_df <- rbind(result_df,temp_df)
# 合併進度
progress <- round(i/length(df_files), 2)*100
cat(sprintf("Processed file %d of %d (%.0f%%)\n", i, length(df_files), progress))
}
# 將合併後的資料保存到新的CSV檔案中
write.csv(result_df, "輸出檔案名稱.csv", row.names = FALSE)
```
## 方法二 map()
```r=
# 讀取目錄下的所有 CSV 檔案
csv_files <- list.files(dir_path, pattern = ".dbf", full.names = TRUE)
df_all <- map_df(csv_files, read.dbf)
str(df_all)
```
## 方法三 lapply()
```r=+
data <- lapply(csv_files, read.dbf)
final_data <- do.call(rbind, data) #bind_rows()
str(final_data)
```
## 方法三 SQLite
```r=
# 加載庫
library(RSQLite)
# 建立與數據庫的連接
con <- dbConnect(RSQLite::SQLite(), dbname = "20230404.db")
# 循環讀取並寫入CSV檔案
for (i in c(1:length(df_files))) {
# 讀取CSV文件
temp_df <- read.csv(df_files[i], header = TRUE)
# 將資料直接寫入SQLite
dbWriteTable(con, "my_table", temp_df, append = TRUE)
# 合併進度
progress <- round(i/length(df_files), 2)*100
cat(sprintf("Processed file %d of %d (%.0f%%)\n", i, length(df_files), progress))
}
# 關閉連接
dbDisconnect(con)
```
# 輸出執行進度
`sprintf`是一個用於格式化字串的函數。它的用法如下:
`sprintf(format, value1, value2, ...)`
其中,`format`是一個字串,其中包含要格式化的內容以及控制格式化的特殊符號,`value1`、`value2`等則是需要格式化的實際值。
在格式化字串中,透過 `%` 符號來控制具體的格式,例如:
- `%s` 使用字串方式輸出變數。
- `%d` 使用數值方式輸出變數。
- `%f` 使用浮點數方式輸出變數。
- `%e` 使用科學計數法方式輸出浮點數。
- `%x` 使用十六進位方式輸出變數。
例如,使用`sprintf`函數將數字和字串格式化為一個字串:
```r=
num <- 10
str <- "hello"
result <- sprintf("num=%d, str=%s", num, str)
print(result)
# 輸出:num=10, str=hello
```
`sprintf`函數可以幫助我們方便地格式化輸出結果,特別是在需要將變數輸出為特定格式時。
# 效能測試
## 測試基準_1000個CSV檔
```r=
# 生成1000個CSV檔案
set.seed(42)
csv_files <- sapply(1:1000, function(i) {
df <- data.frame(
A = rnorm(1000),
B = rnorm(1000),
C = rnorm(1000),
D = rnorm(1000)
)
file_name <- paste0("test_csv_", i, ".csv")
write.csv(df, file_name, row.names = FALSE)
return(file_name)
})
```
## 計算循環讀取並合併CSV檔案所需時間
### FOR_99s
```r=
profvis({
for (i in c(1:length(csv_files))) {
temp_df <- read.csv(csv_files[i], header = TRUE)
result_df <- rbind(result_df,temp_df)
}
})
```

### sqlite_23s

### lapply_7s
```r=
profvis({
result_df <- do.call(rbind, lapply(csv_files, read.csv, header = TRUE))
})
```

### purrr&dplyr_6.6s
```r=
# 計算使用purrr和dplyr讀取和合併CSV檔案所需時間
profvis({
result_df <- csv_files %>%
map(~ read.csv(.x, header = TRUE)) %>%
bind_rows()
})
```

### data.table套件_1.1s
```r=
# 讀取 CSV 檔案,並將所有檔案合併成一個資料表
profvis({
result_dt <- rbindlist(lapply(csv_files, fread))
})
```

來個暴力測試將資料提高到10000萬個檔案共四億筆數據的讀取
花費約40秒也比單純for迴圈來的快速

## 計算將合併後的資料保存所需時間
### for()_to_CSV_27s


### to_sqlite_23s


### fwrite()_to_csv_120ms


### to_feather_30ms


🌟全文可以至下方連結觀看或是補充
全文分享至
https://www.facebook.com/LHB0222/
https://www.instagram.com/ahb0222/
有疑問想討論的都歡迎於下方留言
喜歡的幫我分享給所有的朋友 \o/
有所錯誤歡迎指教
# [:page_with_curl: 全部文章列表](https://hackmd.io/@LHB-0222/AllWritings)
