{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 5.8 遍历文本文件"
]
},
{
"cell_type": "raw",
"metadata": {},
"source": [
"作者:赵广辉,vasp@qq.com\n",
"本教程版权归属于武汉理工大学赵广辉所有,仅限用于学校教学用途,未经许可,严禁用于培训、出版等除学校教学以外的任何用途。\n",
"教学应用以及任何基于本教程的修改均应保留此段文字。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[Who Moved My Cheese.txt](images/ch5/Who Moved My Cheese.txt) \n",
"\n",
"[8.1 静夜思.txt](images/ch5/8.1 静夜思.txt)"
]
},
{
"cell_type": "raw",
"metadata": {},
"source": [
"静夜思\n",
"床前明月光,疑是地上霜。\n",
"举头望明月,低头思故乡。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"文本文件的内容除了我们看到的文本信息外,还有一些不可见字符,例如,在每行末会有一个换行和回车符。 \n",
"行末常见的符号有CR/LF \n",
"LF是Line Feed的缩写,符号是\\n,ASCII值是10; \n",
"CR是Carriage Return的缩写,符号是\\r,ASCII值是13; \n",
"Unix/Linux/Mac系统下面,一般只用LF \n",
"Windows系统下面经常同时使用两个符号,CRLF,有时也只用LF。\n",
"\n",
"这两种符号在python中都可以用字符串的str.strip()方法去除,下面统称为换行符。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/ch5/4.png\" width=\"400\"><br />\n",
"<img src=\"images/ch5/5.png\" width=\"400\">"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"知识扩展:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"LF:换行\n",
"LF(Line Feed)代表“换行”,换行符(转义序列 \\n) \n",
"这个字符代表一行文本的结束,在 Linux 和 Mac 上,这相当于新文本行的开始。 \n",
"\n",
"CR:回车\n",
"CR(Carriage Return)代表回车(转义序列\\r) \n",
"将光标移动到当前行的开头。\n",
"\n",
"打字机和回车(CR)\n",
"将一张纸固定在称为托架的机械卷上,为设备送入一张纸。每次击键时,打字机都会使用墨水在您的纸张上打印字母,将笔架向左移动以确保键入的下一个字母会出现在前一个字母的右侧。\n",
"\n",
"当然,一旦当前行的空间用完,打字员就需要向下移动到纸张上的下一行。这是通过旋转滑架将纸张相对于打字机的“笔”向上移动一定距离来完成的。但是还需要重置托架(carriage),以便键入的下一个字符将与纸张的左侧边距对齐。换句话说,打字员需要某种方式将托架返回到其起始位置。而这正是回车的工作:一个金属杆连接到托架的左侧,当推动时,将托架返回到其起始位置。\n",
"\n",
"电传打字机和回车换行(CRLF)\n",
"进入 20 世纪初,出现了电传打字机。基本上,它的工作方式与手动打字机相同,除了不是打印到物理纸上,而是通过传输器通过物理电线或无线电波将消息发送给接收方。\n",
"\n",
"虽然打印方式不同,但是同样需要使用换行符 (LF) 和回车符 (CR),而且这些设备需要同时使用换行符 (LF) 和回车符 (CR) 以允许打字员从下一行文本的开头输入。毕竟手动打字机就是这样工作的,只是它没有任何“字符”的概念,因为它是一种机械操作的设备。\n",
"\n",
"我们可以将 LF 和 CR 视为代表水平或垂直方向上的独立运动,而不是同时代表两者,这样更容易将其形象化。为了实现这个功能,电传打字机在一些最早的操作系统中设定了 CRLF 行尾的标准,比如流行的 MS-DOS。将CR 代表“回车”——CR 控制字符将打印头(“回车”)返回到第 0 列,而无需推进纸张。 LF 代表“换行”——LF 控制字符在不移动打印头的情况下将纸张前进一行。因此,如果您想将打印头返回到第 0 列(准备打印下一行)并推进纸张(以便在新纸上打印),则需要 CR 和 LF。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. 遍历输出文件"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"open()函数可以打开文件并创建一个可遍历的文件对象,可用赋值方式命名:\n",
"f = open() \n",
"也可用内容管理器with...as为之命别名: \n",
"with open() as f: \n",
"两个方法都可以打开文件创建文件对象。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"f = open('images/ch5/8.1 静夜思.txt') # f 只是为创建的文件对象起的名字,无特殊意义\n",
"for a in f: # 遍历文件对象,每次循环获得文件的一行,包括行末的符号\n",
" print(a) # 逐行输出"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# with ...as 语句需要以冒号结尾\n",
"\n",
"with open('images/ch5/8.1 静夜思.txt') as fr: # fr 只是为创建的文件对象起的名字,可理解为可读文件对象\n",
" for line in fr: # 遍历文件对象,每次循环获得文件的一行,包括行末的符号\n",
" print(line) # 逐行输出"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"两种方法都可以逐行输出文件内容,但注意到文件末尾有一个换行符:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print('静夜思') # 输出静夜思后换行"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print() # 输出一个换行"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print('\\n') # 输出两个换行 "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print('静夜思\\n') # '静夜思\\n'相当于'静夜思'+'\\n',输出静夜思后换行再换行,即多输出一个空行"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. 读文件时去除换行符"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2.1 字符串的str.strip()方法"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"f = open('images/ch5/Who Moved My Cheese.txt') # f 只是为创建的文件对象起的名字,无特殊意义\n",
"for line in f: # 遍历文件对象,每次循环获得文件的一行,包括行末的符号\n",
" print(line.strip()) # 逐行输出"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# with ...as 语句需要以冒号结尾\n",
"\n",
"with open('/data/bigfiles/8704a285-deaf-40f3-8694-f2036f0604de.txt') as fr: # fr 只是为创建的文件对象起的名字,可理解为可读文件对象\n",
" for line in fr: # 遍历文件对象,每次循环获得文件的一行,包括行末的符号\n",
" print(line.strip()) # 逐行输出"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2.2 用字符串的str.replace()方法替换 "
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"静夜思\n",
"床前明月光,疑是地上霜。\n",
"举头望明月,低头思故乡。\n"
]
}
],
"source": [
"f = open('images/ch5/8.1 静夜思.txt') # f 只是为创建的文件对象起的名字,无特殊意义\n",
"for line in f: # 遍历文件对象,每次循环获得文件的一行,包括行末的符号\n",
" print(line.replace('\\n','')) # 将字符串中的换行符替换为空字符串"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"with open('/data/bigfiles/8704a285-deaf-40f3-8694-f2036f0604de.txt') as fr: # fr 只是为创建的文件对象起的名字,可理解为可读文件对象\n",
" for line in fr: # 遍历文件对象,每次循环获得文件的一行,包括行末的符号\n",
" print(line.replace(',','-')) # 逐行输出"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2.3 定义函数"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def read_txt(filename): # 传入的带路径文件名\n",
" \"\"\"接收一个文件名为参数,读取文件中的数据并逐行输出。\"\"\"\n",
" with open(filename, 'r', encoding='utf-8') as poem: # poem为创建的文件对象名\n",
" for line in poem:\n",
" print(line.strip())\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" file = '/data/bigfiles/8704a285-deaf-40f3-8694-f2036f0604de.txt' # 文件名定义变量,使函数具有通用性,传不同的文件名就可以读不同的文件\n",
" read_txt(file)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3 读文件为一个字符串"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def read_txt(filename): # 传入的带路径文件名\n",
" \"\"\"接收一个文件名为参数,读取文件中的数据为一个字符串,返回这个字符串。\"\"\"\n",
" with open(filename, 'r', encoding='utf-8') as poem: # poem为创建的文件对象名\n",
" text = '' # 空字符串\n",
" for line in poem:\n",
" text = text + line # 当前行拼接到字符串上,保留原来的换行符\n",
" return text\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" file = 'images/ch5/8.1 静夜思.txt' # 文件名定义变量,使函数具有通用性,传不同的文件名就可以读不同的文件\n",
" print(read_txt(file))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<font face='楷体' color='red' size=5> 练一练1 </font>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"修改3的程序,拼接为字符串时去掉每个行末的换行符,观察输出的结果为分析换行符的作用。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 补充你的代码\n",
"\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<font face='楷体' color='red' size=5> 练一练2 </font>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"模仿3的程序,编程读取文件“Who Moved My Cheese.txt”,逐行输出。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def read_txt(filename): # 传入的带路径文件名\n",
" \"\"\"接收一个文件名为参数,读取文件中的数据为一个字符串,返回这个字符串。\"\"\"\n",
" # 补充你的代码\n",
" \n",
" \n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" file = 'images/ch5/Who Moved My Cheese.txt' # 文件名定义变量,使函数具有通用性,传不同的文件名就可以读不同的文件\n",
" print(read_txt(file))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<font face='楷体' color='red' size=5> 练一练3 </font>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"观察练一练2的输出,发现若每行要么全是中文,要么该行全是英文或数字; \n",
"根据这个特点,将中文和英文分别输出\n",
"提示: \n",
"非中文字符x的ord(x)值均不小于 256\n",
"一般来说每行只判断第1个字符就可以知道是中文还是英文\n",
"但本文档中,有些中文的行是英文符号开头,这些行也会被输出,思考一下如何解决这个问题?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def read_txt(filename): # 传入的带路径文件名\n",
" \"\"\"接收一个文件名为参数,读取文件中的英文为一个字符串,返回这个字符串。\"\"\"\n",
" # 补充你的代码\n",
" \n",
" \n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" file = 'images/ch5/Who Moved My Cheese.txt' # 文件名定义变量,使函数具有通用性,传不同的文件名就可以读不同的文件\n",
" print(read_txt(file))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def read_txt(filename): # 传入的带路径文件名\n",
" \"\"\"接收一个文件名为参数,读取文件中的中文为一个字符串,返回这个字符串。\"\"\"\n",
" # 补充你的代码\n",
" \n",
" \n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" file = '/data/bigfiles/863798db-6d6b-4bfa-842d-d6294266be31.txt' # 文件名定义变量,使函数具有通用性,传不同的文件名就可以读不同的文件\n",
" print(read_txt(file))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}