appendtxt:Stata 中高效合并 txt 文件的命令

今天给大家分享一个 Stata 中高效合并 txt 文件的命令:appendtxt,是根据会员的问题编写好代码再使用 GPT 模型封装成 ado 命令的,可以用于快速合并某个文件夹里面所有的 txt 文件生成一个 dta 文件。得到的文件包含两个变量,filename 和 content,分别表示各个文件的名称和内容。


目录

  1. 命令简介
  2. 安装方法
  3. 语法说明
  4. 创建示例数据
  5. 基本用法
  6. 进阶用法
  7. 常见问题

1. 命令简介

appendtxt 用于将指定文件夹中所有 .txt 文件批量读入 Stata,每个文件对应数据集中的一行观测值,并将文件路径与文件内容分别存入两个变量:

变量名 类型 内容
filename strL TXT 文件的完整路径(文件夹 + 文件名)
content strL TXT 文件的全部文本内容

主要特性:

  • 支持相对路径与绝对路径
  • 支持多文件夹追加合并(多次调用自动累积)
  • 可正确处理文件内容中含有反引号(`)的情形,不触发宏展开错误
  • 可选择将结果直接保存为 .dta 文件

2. 安装方法

方式一:放入当前工作目录(临时使用)

将以下两个文件复制到你的 Stata 当前工作目录(cd 所指向的目录):

appendtxt.ado
appendtxt.sthlp

无需任何额外操作,即可在该工作目录下使用 appendtxt 命令。

查看当前工作目录:pwd


方式二:安装到个人 ado 目录(永久使用,推荐)

将 appendtxt.ado 和 appendtxt.sthlp 复制到 Stata 个人 ado 目录下按首字母分类的子文件夹中。

第一步:查看个人 ado 目录路径

sysdir

输出示例:

   STATA:  C:\Program Files\Stata18\
BASE: C:\Program Files\Stata18\ado\base\
SITE: C:\Program Files\Stata18\ado\site\
PLUS: C:\Users\用户名\ado\plus\
PERSONAL: C:\Users\用户名\ado\personal\

第二步:将文件放入 PERSONAL 目录下的 a 子文件夹

Windows:  C:\Users\用户名\ado\personal\a\
Mac/Linux: ~/ado/personal/a/

若 a 文件夹不存在,手动创建即可。

第三步:验证安装

which appendtxt
help appendtxt

方式三:通过 net install 从本地安装(包方式)

将以下四个文件放在同一个文件夹(如 C:/mypkg/appendtxt/):

appendtxt.ado
appendtxt.sthlp
appendtxt.pkg
stata.toc

然后执行:

*- Windows
net install appendtxt.pkg, from("C:/mypkg/appendtxt")

*- Mac / Linux
net install appendtxt.pkg, from("/Users/用户名/mypkg/appendtxt")

3. 语法说明

appendtxt [, folder(路径) saving(文件名) replace]
选项 简写 说明
folder(路径) fol() 指定 TXT 文件所在文件夹,默认为当前工作目录
saving(文件名) sav() 保存结果为 .dta 文件,无需写后缀
replace — 配合 saving() 使用,允许覆盖已有文件

4. 创建示例数据

在正式演示各种用法之前,先用 Stata 代码在当前工作目录下创建一批示例 TXT 文件,以便复现所有示例。

4.1 创建目录结构

*- 创建示例文件夹
mkdir "示例文本"
mkdir "示例文本/第一批"
mkdir "示例文本/第二批"
mkdir "示例文本/含特殊字符"

4.2 创建第一批 TXT 文件(普通文本)

*- 文件 1:某公司 2024 年一季度报告
local f1 = "示例文本/第一批/report_2024q1.txt"
local content1 = "公司名称:宏远科技有限公司" + char(10) + ///
"报告期间:2024年第一季度" + char(10) + ///
"营业收入:1,250万元" + char(10) + ///
"净利润:320万元" + char(10) + ///
"同比增长:15.3%"
file open fh using `"`f1'"', write replace
file write fh `"`content1'"'
file close fh

*- 文件 2:某公司 2024 年二季度报告
local f2 = "示例文本/第一批/report_2024q2.txt"
local content2 = "公司名称:宏远科技有限公司" + char(10) + ///
"报告期间:2024年第二季度" + char(10) + ///
"营业收入:1,480万元" + char(10) + ///
"净利润:401万元" + char(10) + ///
"同比增长:18.7%"
file open fh using `"`f2'"', write replace
file write fh `"`content2'"'
file close fh

*- 文件 3:某公司 2024 年三季度报告
local f3 = "示例文本/第一批/report_2024q3.txt"
local content3 = "公司名称:宏远科技有限公司" + char(10) + ///
"报告期间:2024年第三季度" + char(10) + ///
"营业收入:1,620万元" + char(10) + ///
"净利润:445万元" + char(10) + ///
"同比增长:21.2%"
file open fh using `"`f3'"', write replace
file write fh `"`content3'"'
file close fh

4.3 创建第二批 TXT 文件(访谈记录)

*- 访谈记录 1
local f4 = "示例文本/第二批/interview_001.txt"
local content4 = "受访者:张三" + char(10) + ///
"日期:2024-03-15" + char(10) + ///
"地点:北京" + char(10) + char(10) + ///
"问:您如何看待当前的市场形势?" + char(10) + ///
"答:整体来看,市场需求在逐步回暖,但竞争压力依然较大。"
file open fh using `"`f4'"', write replace
file write fh `"`content4'"'
file close fh

*- 访谈记录 2
local f5 = "示例文本/第二批/interview_002.txt"
local content5 = "受访者:李四" + char(10) + ///
"日期:2024-03-16" + char(10) + ///
"地点:上海" + char(10) + char(10) + ///
"问:您认为未来一年的发展重点是什么?" + char(10) + ///
"答:数字化转型是重中之重,需要加大技术研发投入。"
file open fh using `"`f5'"', write replace
file write fh `"`content5'"'
file close fh

4.4 创建含特殊字符的 TXT 文件

*- 含引号与百分号的文件
local f6 = "示例文本/含特殊字符/special_chars.txt"
local content6 = "产品说明:本产品采用\"高强度合金\"材料" + char(10) + ///
"折扣率:8.5折(即85%)" + char(10) + ///
"备注:价格含税,不含运费"
file open fh using `"`f6'"', write replace
file write fh `"`content6'"'
file close fh

4.5 验证文件创建结果

*- 查看各文件夹中的 txt 文件列表
local list1 : dir "示例文本/第一批" files "*.txt"
local list2 : dir "示例文本/第二批" files "*.txt"
local list3 : dir "示例文本/含特殊字符" files "*.txt"

di "第一批:`list1'"
di "第二批:`list2'"
di "含特殊字符:`list3'"

5. 基本用法

5.1 读取当前工作目录下的所有 TXT 文件

最简调用,不加任何选项,默认读取当前目录(pwd)下所有 .txt 文件:

clear
appendtxt
list

5.2 使用相对路径指定文件夹

clear
appendtxt, folder("示例文本/第一批")
list filename

输出示意:

*>     +----------------------------------------------+
*> | filename |
*> |----------------------------------------------|
*> 1. | 示例文本/第一批/report_2024q1.txt |
*> 2. | 示例文本/第一批/report_2024q2.txt |
*> 3. | 示例文本/第一批/report_2024q3.txt |
*> +----------------------------------------------+

5.3 使用绝对路径指定文件夹

clear
*- Windows 示例
appendtxt, folder("C:/Users/用户名/Desktop/示例文本/第一批")

*- Mac / Linux 示例
appendtxt, folder("/Users/用户名/Desktop/示例文本/第一批")

list filename

5.4 读取后直接保存为 .dta 文件

clear
appendtxt, folder("示例文本/第一批") saving(quarterly_reports) replace

执行后 Stata 输出:

*> 文件夹:示例文本/第一批
*> 共发现 3 个 txt 文件,开始读取...
*>
*> [1/3] 正在读取:report_2024q1.txt
*> [2/3] 正在读取:report_2024q2.txt
*> [3/3] 正在读取:report_2024q3.txt
*>
*> 读取完成!共 3 个文件已合并。
*> 数据已保存至:quarterly_reports.dta
*>
*> ═══════════════════════════════════════
*> appendtxt 执行摘要
*> ═══════════════════════════════════════
*> 来源文件夹:示例文本/第一批
*> 本次读取: 3 个文件
*> 数据集总行:3 行
*> 保存路径: quarterly_reports.dta
*> ═══════════════════════════════════════

5.5 查看读取结果

clear
appendtxt, folder("示例文本/第一批")

*- 查看变量基本信息
describe

*- 查看文件名列表
list filename

*- 查看第一行文件内容
di content[1]

*- 查看所有内容(适合内容较短时)
list content

6. 进阶用法

6.1 合并多个文件夹(追加模式)

appendtxt 支持多次调用,后续调用会自动追加到已有数据集末尾:

clear

*- 先读取第一批
appendtxt, folder("示例文本/第一批")
di "第一批读取后观测数:" _N

*- 再追加第二批
appendtxt, folder("示例文本/第二批")
di "追加第二批后观测数:" _N

*- 查看完整结果
list filename

*- 保存合并结果
save all_texts, replace

6.2 合并多文件夹并一次性保存

clear
appendtxt, folder("示例文本/第一批")
appendtxt, folder("示例文本/第二批")
appendtxt, folder("示例文本/含特殊字符") saving(all_merged) replace

注意:saving() 选项只需在最后一次调用时指定,Stata 会将内存中完整的数据集保存。


6.3 读取后提取文件名(去除路径前缀)

有时只需要文件名本身,可用字符串函数处理 filename 变量:

clear
appendtxt, folder("示例文本/第一批")

*- 提取纯文件名(去除文件夹路径)
gen basename = regexs(0) if regexm(filename, "[^/\\]+\.txt$")

list filename basename

6.4 从文件名中提取结构化信息

若文件名有规律(如 report_2024q1.txt),可进一步拆解为结构化变量:

clear
appendtxt, folder("示例文本/第一批")

*- 提取年份
gen year = real(regexs(1)) if regexm(filename, "(\d{4})q\d")

*- 提取季度
gen quarter = real(regexs(1)) if regexm(filename, "\d{4}q(\d)")

list filename year quarter

输出示意:

*>      +-----------------------------------------------+
*> | filename year quarter |
*> |-----------------------------------------------|
*> 1. | 示例文本/第一批/report_2024q1.txt 2024 1 |
*> 2. | 示例文本/第一批/report_2024q2.txt 2024 2 |
*> 3. | 示例文本/第一批/report_2024q3.txt 2024 3 |
*> +-----------------------------------------------+

6.5 按关键词筛选文件内容

读取后可对 content 变量进行字符串匹配,筛选包含特定关键词的文件:

clear
appendtxt, folder("示例文本/第一批")

*- 筛选内容中包含"净利润"的文件
keep if strpos(content, "净利润") > 0

di "包含净利润字段的文件数:" _N
list filename

6.6 统计各文件的字符数与行数

clear
appendtxt, folder("示例文本/第一批")

*- 统计每个文件的字符数
gen char_count = length(content)

*- 统计每个文件的行数(以换行符数量 +1 估算)
gen line_count = length(content) - length(subinstr(content, char(10), "", .)) + 1

list filename char_count line_count

6.7 将文件内容分行展开(长格式转换)

若需要对文本逐行分析,可将每行内容拆分为独立观测值:

clear
appendtxt, folder("示例文本/第一批")

*- 保留原始文件标识
gen file_id = _n

*- 展开为长格式:每行文本一条观测值
*- (需要 splitvallabels 或手动循环,以下为简化示意)
*- 先将换行符替换为分隔符
gen content2 = subinstr(content, char(10), "|", .)

*- 使用 split 命令按 | 拆分(生成 content2_1, content2_2, ...)
split content2, parse("|") gen(line_)

*- 转换为长格式
reshape long line_, i(file_id) j(line_no)
drop if missing(line_) | line_ == ""
rename line_ text_line

list file_id line_no text_line

6.8 读取后立即排序

文件读取顺序由操作系统决定(通常为文件名字母升序),如需明确控制顺序,读取后手动排序:

clear
appendtxt, folder("示例文本/第一批")

*- 按文件名升序排列
sort filename

*- 按文件名降序排列
gsort -filename

list filename

6.9 与现有数据集合并

若已有一个包含文件名信息的元数据表,可在读取后与之合并:

*- 第一步:创建元数据(文件名 → 附加属性)
clear
input str50 basename str10 category
"report_2024q1.txt" "财务"
"report_2024q2.txt" "财务"
"report_2024q3.txt" "财务"
end
save metadata, replace

*- 第二步:读取 TXT 文件
clear
appendtxt, folder("示例文本/第一批")

*- 提取纯文件名用于匹配
gen basename = regexs(0) if regexm(filename, "[^/\\]+\.txt$")

*- 第三步:与元数据合并
merge 1:1 basename using metadata
list filename category

7. 常见问题

Q1:文件夹路径中含有中文或空格,会报错吗?

不会。appendtxt 内部使用复合引号(``”…”‘`)处理路径,可兼容中文路径和含空格的路径。


Q2:文件内容含有反引号(```),会报错吗?

不会。这正是 appendtxt 相比手动脚本的核心改进之处。命令内部直接调用 fileread() 函数将结果写入 strL 变量,完全绕过本地宏的解析过程,因此反引号不会触发宏展开错误。


Q3:追加时报错”当前数据集中不含 filename 或 content 变量”?

这意味着内存中已有数据集,但不含 appendtxt 所需的两个变量。解决方法:

*- 方法一:清空内存重新开始
clear
appendtxt, folder("你的文件夹")

*- 方法二:先保存现有数据,再清空
save backup, replace
clear
appendtxt, folder("你的文件夹")

Q4:命令只读取了当前文件夹,不读取子文件夹?

是的,appendtxt 仅扫描指定文件夹的根目录,不递归进入子文件夹。若需处理多层目录,请对每个子文件夹分别调用:

clear
appendtxt, folder("示例文本/第一批")
appendtxt, folder("示例文本/第二批")
appendtxt, folder("示例文本/含特殊字符")
save all, replace

Q5:如何只保存部分列?

读取后用 keep 命令保留所需变量,再保存:

clear
appendtxt, folder("示例文本/第一批")
keep filename content // 只保留这两列(默认即只有这两列)
save result, replace

Q6:文件数量很多时,命令会很慢吗?

速度主要取决于文件总大小而非文件数量。fileread() 函数为 Stata 内置函数,效率较高。若文件单个体积很大(数十 MB 以上),读取速度会相应变慢,这是正常现象。

点击这里跳转到 RStata 短书平台获取附件:appendtxt:Stata 中高效合并 txt 文件的命令

评论