R语言文本保存方法对比:writeLines()、cat()、sink()差异与适用场景
我们以生成包含以下内容的output.txt文件为测试场景,对比R中三种常见文本写入方法的差异:
Hello World
三种基础实现方式如下:
- 基于
writeLines()实现
fileConn<-file("output.txt") writeLines(c("Hello","World"), fileConn) close(fileConn)
- 基于
sink()实现
sink("outfile.txt") cat("hello") cat("\n") cat("world") sink()
- 基于
cat()实现
cat("Hello",file="outfile.txt",sep="\n") cat("World",file="outfile.txt",append=TRUE)
不少使用者反馈cat()的运行速度明显慢于另外两种方法,下面针对两个核心问题做具体说明:
不同方法的适用场景
三个函数的设计目标完全不同,没有绝对的优劣,各自有适配的使用场景:
- 当你已经把要写入的所有内容提前整理成了字符向量,需要一次性批量写入文件时,
writeLines()是最优选择。不需要手动处理换行符、反复调整写入参数,适合导出结构化文本结果、生成批量文本类输出的场景。 - 当你需要把原本打印到控制台的所有内容(包括函数运行的自动输出、警告信息、打印的中间变量)完整留存到文件时,
sink()的成本最低。不需要改写原有写好的打印逻辑,只要在代码块前后加上sink()的开关即可,最适合保存脚本全量运行日志、留存调试输出的场景。 - 当你需要在循环、条件判断等动态流程中零散追加内容片段时,
cat()的灵活度最高。不需要提前拼接完整的待写入内容,也不需要长期维护打开的文件连接,适合实时写入任务进度、逐段生成自定义格式文本的场景。
性能差异与R惯用法的底层逻辑
绝大多数常规写入场景下,writeLines()是最符合R语言惯用规范、运行效率最高的方法,核心原因有三点:
第一,函数功能更聚焦。writeLines()是专门为「按行写入字符向量到文本文件」设计的函数,没有冗余功能:不需要像sink()一样全局拦截控制台的所有输出流,也不需要像cat()一样兼容不同类型输入的转换、多输入对象拼接等复杂逻辑,底层C实现的执行路径更短,额外开销极低。
第二,IO操作次数更少。writeLines()的常规用法是单次打开文件连接、一次性写入全部内容、最后关闭连接,磁盘IO开销被压到最低。而大家平时感知到cat()速度慢,大多是因为反复调用追加模式的cat(),每次调用都会触发文件打开、写入、关闭的完整流程,IO开销会随着调用次数线性上涨——如果提前打开文件连接,再连续调用cat()写入,最后统一关闭连接,两者的速度差距会变得非常小。
第三,默认行为更合理。writeLines()会自动为字符向量的每个元素添加适配当前操作系统的换行符,不需要用户手动处理换行转义、跨平台换行符兼容的问题,默认参数就能覆盖绝大多数写文本文件的需求,代码可读性更强,也是R官方文档中推荐的常规文本写入方式。
小提示:如果要写入GB级别的超大文本文件,建议手动保持文件连接处于打开状态,分块调用
writeLines()写入内容,全部写完后再关闭连接,能最大程度降低磁盘IO带来的性能损耗;如果只是临时调试需要留存输出,直接用sink()不用改动原有代码的性价比最高。
内容的提问来源于stack exchange,提问作者Richard Erickson

