Python编程快速上手 让繁琐工作自动化(三)

八、读写文件

1、文件与文件路径

  • 文件有两个关键属性:文件名和路径。在windows中,根文件夹名为C:\,也称为C:盘,在OS X和Linux中,根文件夹是/。
  • 在windows上路径书写使用倒斜杠\作为文件夹之间的分隔符,但在OS X和Linux上使用正斜杠/作为它们的路径分隔符。
  • 将单个文件和路径上的文件夹名称的字符串传递给os.path.join()函数,它会返回一个文件路径的字符串,包括正确的路径分隔符。
>>> import os
>>> os.path.join('user','bin','spam')   #os.path模块包含许多与文件名和文件路径相关的有用函数
'user\\bin\\spam'     #两个\是因为每个\需要由另一个\字符来转义

2、当前工作目录

每个运行程序都有一个当前工作目录(或cwd),所以没有从根文件夹开始的文件名或路径,都假定在当前工作目录下,利用os.getcwd()函数,可获得当前工作路径的字符串,并可以利用os.chdir()改变它。

>>> os.getcwd()
'C:\\Python34'
>>> os.chdir('C:\\Windows\\System32')
>>> os.getcwd()
'C:\\Windows\\System32'

3、绝对路径与相对路径

  • 绝对路径:总是从根文件夹开始。
  • 相对路径:它相对于程序的当前工作目录。
    单个句点.用作文件夹名称时,指“这个目录”,两个句点..意思是父文件夹。相对路径开始处的.\是可选的。

4、文件相关函数

  • os.makedirs()创建新文件夹(目录)。会创建所有必要的中间文件夹,目的是确保完整路径名存在。
>>> os.makedirs('C:\\delicious\\walnut\\waffles')
  • os.path.abspath(path)将返回参数的绝对路径的字符串,这是将相对路径转换为绝对路径的简便方法。
  • os.path.isabs(path),若参数是一个绝对路径则返回True,若是一个相对路径返回False。
  • os.path.relpath(path,start)将返回从start路径到path的相对路径的字符串,若没有提供start,就使用当前工作目录作为开始路径。
>>> os.path.abspath('.')
'C:\\Python34'
>>> os.path.abspath('.\\Scripts')
'C:\\Python34\\Scripts'
>>> os.path.isabs('.')
False
>>> os.path.isabs(os.path.abspath('.'))
True
>>> os.path.relpath('C:\\Windows', 'C:\\')
'Windows'
>>> os.path.relpath('C:\\Windows', 'C:\\spam\\eggs')
'..\\..\\Windows'
  • os.path.dirname(path)返回一个字符串,包含path参数中最后一个斜杠之前的所以内容。
  • os.path.basename(path)返回一个字符串,包含path参数中最后一个斜杠之后的所有内容。
>>> path = 'C:\\Windows\\System32\\calc.exe'
>>> os.path.basename(path)
'calc.exe'
>>> os.path.dirname(path)
'C:\\Windows\\System32'
  • 如果同时需要一个路径的目录名称和基本名称,使用os.path.split(),获得这个字符串的元组。也可调用前两个方法,将它们的返回值放在一个元组中,从而得到同样的元组。
>>> calcFilePath = 'C:\\Windows\\System32\\calc.exe'
>>> os.path.split(calcFilePath)
('C:\\Windows\\System32', 'calc.exe')
>>> (os.path.dirname(calcFilePath), os.path.basename(calcFilePath))
('C:\\Windows\\System32', 'calc.exe')
  • os.path.split()不接受一个文件路径并返回每个文件夹的字符串的列表,如果要这样需使用split()方法,并根据os.path.sep中的字符串进行分割。
>>> calcFilePath.split(os.path.sep)
['C:', 'Windows', 'System32', 'calc.exe']

OS X 和 Linux 系统上,返回的列表头上有一个空字符串.

  • os.path.getsize(path)将返回path参数中文件的字节数。
  • os.listdir(path)返回文件名字符串的列表,包含path参数中的每个文件。
>>> os.path.getsize('C:\\Windows\\System32\\calc.exe')
776192
>>> os.listdir('C:\\Windows\\System32')
['0409', '12520437.cpx', '12520850.cpx', '5U877.ax', 'aaclient.dll',
--snip--
'xwtpdui.dll', 'xwtpw32.dll', 'zh-CN', 'zh-HK', 'zh-TW', 'zipfldr.dll']
  • os.path.exists(path)检查path参数所指的文件或文件夹是否存在,若是返回True,否则返回False。
  • os.path.isfile(path)检查path参数是否是一个文件,若是返回True,否则返回False。
  • os.path.isdir(path)检查path参数是否是一个文件夹,若是返回True,否则返回False。
>>> os.path.exists('C:\\Windows')
True
>>> os.path.exists('C:\\some_made_up_folder')
False
>>> os.path.isdir('C:\\Windows\\System32')
True
>>> os.path.isfile('C:\\Windows\\System32')
False
>>> os.path.isdir('C:\\Windows\\System32\\calc.exe')
False
>>> os.path.isfile('C:\\Windows\\System32\\calc.exe')
True

5、文件读写过程

  • 纯文本文件:只包含基本文本字符,不包含字体、大小和颜色信息。比如.txt扩展名和.py扩展名的都是纯文本。
  • 二进制文件:是所有其他文件类型,诸如字处理文档、PDF、图像、电子表格和可执行程序等。
    在python中读写文件有三个步骤:
    (1)、调用open()函数,返回一个File对象。
    (2)、调用File()对象的read()或write()方法。
    (3)、调用File对象的close()方法,关闭该文件。

6、open()函数

用此函数打开文件时,要传入一个字符串路径。

>>> testfile=open("D:\\zz\\pytest.txt")

这将默认文件以只读模式打开,不能写入或修改它。python默认以读模式打开文件,也可以向open()传入字符串'r',作为第二个参数(效果和上述一样)。

7、读取文件内容

如果希望将整个文件内容读取为一个字符串值,使用File对象的read()方法。

>>> content=testfile.read()
>>> content
'Hello Word!'

也可使用readlines()方法,返回一个字符串的列表,列表中的每个字符串就是文本中的每一行。

>>> testfile=open("D:\\zz\\pytest.txt")
>>> testfile.readlines()
["When, in disgrace with fortune and men's eyes,\n", 'I all alone beweep my outcast state,\n', 'And trouble deaf heaven with my bootless cries,\n', 'And look upon myself and curse my fate,']

每个字符串值都会以一个换行字符\n结束,除了最后一行。

8、写入文件

要写入文件,必须以写模式(覆写原有的文件)即将'w'作为第二个参数传递给open(),或添加模式(在已有文件的末尾添加文本)即将'a'作为第二个参数传递给open()打开文件。
如果传递给open()的文件名不存在,这两种模式都会创建一个新的空文件,在读取或写入文件后调用close()方法,然后才能再次打开该文件。

>>> testfile=open("D:\\zz\\pytest.txt",'w')
>>> testfile.write('hello world!\n')
13
>>> testfile.close()
>>> testfile=open("D:\\zz\\pytest.txt",'a')
>>> testfile.write('bacon is not a vegetable.')
25
>>> testfile.close()
>>> testfile=open("D:\\zz\\pytest.txt")
>>> content=testfile.read()
>>> content
'hello world!\nbacon is not a vegetable.'
>>> testfile.close()
>>> print(content)
hello world!
bacon is not a vegetable.

write()方法不会像print()函数一样在字符串的末尾自动天剑换行符,必须自己添加该字符。

9、用shelve模块保存变量

利用此模块可将python程序中的变量保存到二进制的shelf文件中。

>>> import shelve
>>> shelfile=shelve.open('pytest') #传入的是一个文件名,可以对返回的值的变量进行修改,类似字典
>>> cats=['zonhie','pookie','simon']
>>> shelfile['cats']=cats
>>> shelfile.close()

在windows上运行上述程序,会在当前工作目录下生成3个二进制文件pytest.bak、pytest.dat 和 pytest.dir:


微信图片_20210409150401.png

shelf值不必用读/写模式打开,因为它们在打开后,既能读又能写。shelf值也有keys()和values()方法,返回类似列表的值,所以应该将它们传给list()函数,取得列表的形式。

>>> shelfile=shelve.open('pytest')
>>> type(shelfile)
<class 'shelve.DbfilenameShelf'>
>>> shelfile['cats']
['zonhie', 'pookie', 'simon']
>>> list(shelfile.keys())
['cats']
>>> list(shelfile.values())
[['zonhie', 'pookie', 'simon']]
>>> shelfile.close()

创建文件时,如果需要在 Notepad 或 TextEdit 这样的文本编辑器中读取它们,纯文本就非常有用。但是,如果想保存 Python 程序中的数据,就使用 shelve 模块。

10、用pprint.format()函数保存变量

此函数返回的字符串不仅易于阅读,也是语法正确的python代码。假定有一个字典,保存在一个变量中,若希望保存这个变量和它的内容,以便将来使用,此函数将提供一个字符串,可以将它写入.py 文件。该文件成为自己的模块,如果需要使用存储在其中的变量,就可以导入它。

>>> import pprint
>>> cats = [{'name': 'Zophie', 'desc': 'chubby'}, {'name': 'Pooka', 'desc': 'fluffy'}]
>>> pprint.pformat(cats)
"[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]"
>>> fileobj=open('mydata.py','w')
>>> fileobj.write('cats='+pprint.pformat(cats)+'\n')
81
>>> fileobj.close()
>>> 
>>> import mydata
>>> mydata.cats
[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]
>>> mydata.cats[0]
{'desc': 'chubby', 'name': 'Zophie'}
>>> mydata.cats[0]['name']
'Zophie'

mydata.py中的内容为:


微信图片_20210409152510.png

九、组织文件

1、shutil模块

shutil(或称为shell工具)模块中包含一些函数,用于复制、移动、改名和删除文件。

  • 复制文件和文件夹
    shutil.copy(source,destination)将路径source处的文件复制到路径destination处的文件夹,若destination是一个文件名,将作为被复制文件的新名字。此函数返回一个字符串,表示被复制文件的路径。
>>> import shutil, os
>>> os.chdir('C:\\')
>>> shutil.copy('C:\\spam.txt', 'C:\\delicious')
'C:\\delicious\\spam.txt'
>>> shutil.copy('eggs.txt', 'C:\\delicious\\eggs2.txt')
'C:\\delicious\\eggs2.txt'

shutil.copy()复制一个文件,shutil.copytree()复制整个文件夹,以及它包含的文件夹和文件。

>>> os.chdir('C:\\')
>>> shutil.copytree('C:\\bacon', 'C:\\bacon_backup')
'C:\\bacon_backup'
  • 文件和文件夹的移动与改名
    shutil.move(source,destination)将路径source处的文件夹移动到路径destination。并返回新位置的绝对路径的字符串。destination也可以指向一个文件名。(很容易覆写文件)
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs')
'C:\\eggs\\bacon.txt'
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs\\new_bacon.txt')
'C:\\eggs\\new_bacon.txt'

以上假定文件夹eggs存在,若C目录下没有此文件夹,则move()会将bacon.txt改名为eggs的文件(没有.txt扩展名的文本文件)。所以构成目的地的文件夹必须已存在。

>>> shutil.move('C:\\bacon.txt', 'C:\\eggs')
'C:\\eggs'
  • 永久删除文件和文件夹
    (1)os.unlink(path)将删除path处的文件。
    (2)os.rmdir(path)将删除path处的文件夹,该文件夹必须为空,其中没有任何文件和文件夹。
    (3)shutil.rmtree(path)删除path处的文件夹,包括它包含的所有文件和文件夹。
for filename in os.listdir():
if filename.endswith('.txt'):
os.unlink(filename)
  • 用send2trash模块安全删除
    此模块是第三方模块,需自行安装然后用import导入。用os和shutil是永久删除,不可恢复,会释放磁盘空间,而send2trash模块会将文件或文件夹发送到计算机的垃圾箱或回收站,不会释放磁盘空间。
>>> import send2trash
>>> baconFile = open('bacon.txt', 'a')
>>> baconFile.write('Bacon is not a vegetable.')
25
>>> baconFile.close()
>>> send2trash.send2trash('bacon.txt')

2、遍历目录树

希望遍历目录树,处理遇到的每个文件用os.walk()函数。此函数传入一个文件夹的路径。在循环的每次迭代中,返回三个值:
(1)当前文件夹名称的字符串。
(2)当前文件夹中子文件夹的字符串的列表。
(3)当前文件夹中文件的字符串的列表。

for folderName, subfolders, filenames in os.walk('C:\\delicious'):
    print('The current folder is ' + folderName)
    for subfolder in subfolders:
         print('SUBFOLDER OF ' + folderName + ': ' + subfolder)
    for filename in filenames:
         print('FILE INSIDE ' + folderName + ': '+ filename)
    print('')

3、用zipfile模块压缩文件

利用zipfile模块中的函数,python程序可以创建和打开(解压)ZIP文件。

  • 读取ZIP文件
    要读取,首先必须创建一个ZipFile对象(概念上和File对象相似),需调用zipfile.ZipFile()函数,向它传入一个字符串,表示.zip文件的文件名。
>>> import zipfile, os
>>> os.chdir('C:\\') # move to the folder with example.zip
>>> exampleZip = zipfile.ZipFile('example.zip')#此压缩包已存在
>>> exampleZip.namelist()
['spam.txt', 'cats/', 'cats/catnames.txt', 'cats/zophie.jpg']
>>> spamInfo = exampleZip.getinfo('spam.txt')
>>> spamInfo.file_size  #原来文件大小
13908
>>> spamInfo.compress_size  #压缩后文件大小
3828
>>> exampleZip.close()

ZipFile对象有一个namelist()方法,返回ZIP文件中包含的所有文件和文件夹的字符串的列表,这些字符串可以传递给ZipFile对象的getinfo()方法,返回一个关于特定文件的ZipInfo对象。此对象有file_size和compress_size等属性。

  • 从ZIP文件中解压缩
    ZipFile对象的extractall()方法从ZIP文件中解压所有文件及文件夹,放到当前工作目录中,也可以传入一个文件夹名称,将文件解压到这个文件夹,若传递的文件夹不存在则会被创建。
>>> os.chdir('C:\\') # move to the folder with example.zip
>>> exampleZip = zipfile.ZipFile('example.zip')
>>> exampleZip.extractall()
>>> exampleZip.close()

extract()方法从ZIP文件中解压单个文件,传递给它的字符串必须匹配namelist()返回的字符串列表中的一个,也可通过传入第二个参数将文件解压到指定文件夹。此方法的返回值是被压缩后文件的绝对路径。

>>> exampleZip.extract('spam.txt')
'C:\\spam.txt'
>>> exampleZip.extract('spam.txt', 'C:\\some\\new\\folders')
'C:\\some\\new\\folders\\spam.txt'
>>> exampleZip.close()
  • 创建和添加到ZIP文件
    创建压缩ZIP文件,必须以写模式打开ZipFile对象,即传入‘w’作为第二个参数。向ZipFile对象的write()方法传入一个路径,就会压缩该路径所指的文件,将它加到ZIP文件中。
>>> newZip = zipfile.ZipFile('new.zip', 'w')
>>> newZip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED)  #第一个参数代表要添加的文件名,第二个参数是压缩类型参数,可以总是设置成这样
>>> newZip.close()

以上写模式会覆盖ZIP文件中原有的内容,如果希望将文件添加到原有的ZIP文件中,就以添加模式打开ZIP文件。(第二个参数改成‘a’)

十、调试

1、抛出异常

在代码中可以抛出自己的异常,使用raise语句,此语句包含以下部分:

  • raise关键字
  • 对Exception函数的调用
  • 传递给Exception函数的字符串,包含有用的出错信息
>>> raise Exception('This is the error message')
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    raise Exception('This is the error message')
Exception: This is the error message

通常是调用该函数的代码知道如何处理异常,而不是该函数本身。所以一般raise语句在一个函数中,try和except语句在调用该函数的代码中。

def boxprint(symbol,width,height):
    if len(symbol)!=1:
        raise Exception('symbol msut be a single charater string.')
    if width<=2:
        raise Exception('width must be greater than 2.')
    if height<=2:
        raise Exception('height must be greater than 2.')
    print(symbol*width)
    for i in range(height-2):
        print(symbol+(' '*(width-2))+symbol)
    print(symbol*width)
for sym,w,h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)):
    try:
        boxprint(sym,w,h)
    except Exception as err:  #若boxprint()返回一个Exception对象,这条语句就会将它保存在名为err的变量中。
        print('an exception happened:'+str(err))  #Exception对象可以传递给str(),将它转换为一个字符串。
#运行结果:
****
*  *
*  *
****
OOOOOOOOOOOOOOOOOOOO
O                  O
O                  O
O                  O
OOOOOOOOOOOOOOOOOOOO
an exception happened:width must be greater than 2.
an exception happened:symbol msut be a single charater string.

2、取得反向跟踪的字符串

若python遇到错误,会产生一些错误信息,称为反向跟踪。反向跟踪包含了出错消息、导致该错误的代码行号,以及导致该错误的函数调用的序列。这个序列称为调用栈。
只要抛出的异常没有被处理,python就会显示反向跟踪,也可以调用traceback.format_exc(),得到它的字符串形式。

>>> import traceback
>>> try:
    raise Exception('This is the error message.')
except:
    errorFile = open('errorInfo.txt', 'w')
    errorFile.write(traceback.format_exc())
    errorFile.close()
    print('The traceback info was written to errorInfo.txt.')
    
116
The traceback info was written to errorInfo.txt.

反向跟踪文本被写入errorInfo.txt:


微信图片_20210414145547.png

3、断言

断言由assert语句执行,若检查失败,就会抛出异常,在代码中,assert语句包含以下部分:

  • assert关键字
  • 条件(即求值为True或False的表达式)
  • 逗号
  • 当条件为False时显示的字符串
>>> podBayDoorStatus = 'open'
>>> assert podBayDoorStatus == 'open', 'The pod bay doors need to be "open".'
>>> podBayDoorStatus = 'I\'m sorry, Dave. I\'m afraid I can\'t do that.'
>>> assert podBayDoorStatus == 'open', 'The pod bay doors need to be "open".'
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    assert podBayDoorStatus == 'open', 'The pod bay doors need to be "open".'
AssertionError: The pod bay doors need to be "open".

断言针对的是程序员的错误,而不是用户的错误。对于那些可以恢复的错误(文件没有找到或用户输了无效数据等),应抛出异常,而不是用assert语句检测。在运行python时传入-O选项可以禁用断言。

4、日志

Python的logging模块很容易创建自定义的消息记录。要启用logging模块,在程序运行时将日志信息显示在屏幕上,需将以下代码复制到程序顶部:

import logging
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s
- %(message)s')

当python记录一个事件的日志时,它会创建一个LogRecord对象,保存关于该事件的信息。logging模块的函数让你指定想看到的LogRecord对象的细节以及希望的细节展示方式。

import logging
logging.basicConfig(level=logging.DEBUG,format=' %(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of program')

def factorial(n):
    logging.debug('Start of factorial(%s%%)' % (n))
    total=1
    for i in range(n+1):
        total*=i
        logging.debug('i is '+str(i)+',total is '+str(total))
    logging.debug('End of factorial(%s%%)' % (n))
    return total
print(factorial(5))
logging.debug('End of program')

以上函数计算一个数的阶乘。想打印日志信息时,使用logging.debug()函数,此函数将调用basicConfig(),打印一行信息,这行信息的格式在basicConfig()函数中指定的,并且包括我们传递给debug()的消息。程序输出如下:

 2021-04-27 14:41:20,668 - DEBUG - Start of program
 2021-04-27 14:41:20,678 - DEBUG - Start of factorial(5%)
 2021-04-27 14:41:20,680 - DEBUG - i is 0,total is 0
 2021-04-27 14:41:20,681 - DEBUG - i is 1,total is 0
 2021-04-27 14:41:20,684 - DEBUG - i is 2,total is 0
 2021-04-27 14:41:20,686 - DEBUG - i is 3,total is 0
 2021-04-27 14:41:20,687 - DEBUG - i is 4,total is 0
 2021-04-27 14:41:20,689 - DEBUG - i is 5,total is 0
 2021-04-27 14:41:20,691 - DEBUG - End of factorial(5%)
0
 2021-04-27 14:41:20,696 - DEBUG - End of program

factorial() 函数返回 0 作为 5 的阶乘,这是不对的。for 循环应该用从 1 到 5的数,乘以 total 的值。但 logging.debug() 显示的日志信息表明,i 变量从 0 开始,而不是 1。因为 0 乘任何数都是 0,所以接下来的迭代中,total 的值都是错的。将代码行 for i in range(n +1)改为 for i in range(1,n + 1),再次运行程序。输出结果为:

 2021-04-27 14:48:09,754 - DEBUG - Start of program
 2021-04-27 14:48:09,760 - DEBUG - Start of factorial(5%)
 2021-04-27 14:48:09,761 - DEBUG - i is 1,total is 1
 2021-04-27 14:48:09,762 - DEBUG - i is 2,total is 2
 2021-04-27 14:48:09,763 - DEBUG - i is 3,total is 6
 2021-04-27 14:48:09,763 - DEBUG - i is 4,total is 24
 2021-04-27 14:48:09,764 - DEBUG - i is 5,total is 120
 2021-04-27 14:48:09,765 - DEBUG - End of factorial(5%)
120
 2021-04-27 14:48:09,766 - DEBUG - End of program

日志消息的好处在于可以在程序中想加多少加多少,之后只要加入一次logging.disable(logging.CRITICAL)调用,就可以禁用日志,不像print(),需要手动删除。

5、日志级别

日志级别提供了一种方式,按重要性对日志消息进行分类。

级别 日志函数 描述
DEBUG logging.debug() 最低级别
INFO logging.info() 记录程序中一般事件的信息或确保一切工作正常
WARNING logging.warning() 用于表示可能得问题
ERROR logging.error() 记录错误,它导致程序做某事失败
CRITICAL logging.critical() 最高级别,表示致命的错误

日志消息作为一个字符串,传递给这些函数。向basicConfig()函数传入 logging.DEBUG 作为 level 关键字参数,这将显示所有日志级别的消息。如果只对错误感兴趣。可将 basicConfig() 的 level 参数设置为 logging.ERROR,这将只显示 ERROR和 CRITICAL 消息,跳过 DEBUG、INFO 和 WARNING 消息。

6、禁用日志

logging.disable() 函数可以禁用日志消息,这样就不必进入到程序中,手工删除所有的日志调用。只要向 logging.disable() 传入一个日志级别,它就会禁止该级别和更低级别的所有日志消息。所以,如果想要禁用所有日志,只要在程序中添加 logging. disable(logging.CRITICAL)。

7、将日志记录到文件

除了将日志消息显示到屏幕上,还可以将它们写入文本文件。logging.basicConfig()函数接受filename关键字参数。

import logging
logging.basicConfig(filename='myProgramLog.txt', level=logging.DEBUG, format='
%(asctime)s - %(levelname)s - %(message)s')

日志信息将被保存到 myProgramLog.txt 文件中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容