我在解析大文本文件中的json对象时遇到了一个奇怪的问题,我找到的解决方案并没有多大意义。我正在使用以下脚本。它复制bz2文件,解压缩它们,然后将每一行解析为json对象。
import os, sys, json
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# USER INPUT
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
args = sys.argv
extractDir = outputDir = ""
if (len(args) >= 2):
extractDir = args[1]
else:
extractDir = raw_input('Directory to extract from: ')
if (len(args) >= 3):
outputDir = args[2]
else:
outputDir = raw_input('Directory to output to: ')
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# RETRIEVE FILE
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
tweetModel = [u'id', u'text', u'lang', u'created_at', u'retweeted', u'retweet_count', u'in_reply_to_user_id', u'coordinates', u'place', u'hashtags', u'in_reply_to_status_id']
filenames = next(os.walk(extractDir))[2]
for file in filenames:
if file[-4:] != ".bz2":
continue
os.system("cp " + extractDir + '/' + file + ' ' + outputDir)
os.system("bunzip2 " + outputDir + '/' + file)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# PARSE DATA
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
input = open (outputDir + '/' + file[:-4], 'r')
output = open (outputDir + '/p_' + file[:-4], 'w+')
for line in input.readlines():
try:
tweet = json.loads(line)
for field in enumerate(tweetModel):
if tweet.has_key(field[1]) and tweet[field[1]] != None:
if field[0] != 0:
output.write('\t')
fieldData = tweet[field[1]]
if not isinstance(fieldData, unicode):
fieldData = unicode(str(fieldData), "utf-8")
output.write(fieldData.encode('utf8'))
else:
output.write('\t')
except ValueError as e:
print ("Parse Error: " + str(e))
print line
line = input.readline()
quit()
continue
print "Success! " + str(len(line))
input.flush()
output.write('\n')
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# REMOVE OLD FILE
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
os.system("rm " + outputDir + '/' + file[:-4])
在读取for line in input.readlines():
循环中的某些行时,这些行偶尔会在不一致的位置被截断。由于换行符也被截断,因此它将继续读取,直到它在下一个json对象的末尾找到换行符。结果是一个不完整的json对象,后跟一个完整的json对象,解析器都将其视为一行。我找不到这个问题的原因,但我确实发现将循环更改为
filedata = input.read()
for line in filedata.splitlines():
的工作。有谁知道这里发生了什么?
答案 0 :(得分:2)
在查看file.readlines和string.splitlines的源代码后,我想我看到了什么。 注意:这是python 2.7源代码,所以如果你正在使用另一个版本...也许这个答案可能没有。
readlines使用函数Py_UniversalNewlineFread来测试换行符splitlines使用仅测试\ n或\ r \ n的常量STRINGLIB_ISLINEBREAK。我怀疑Py_UniversalNewlineFread在文件流中拾取一些字符作为换行符,当它不是真正意图作为换行符时,可能来自编码..我不知道......但当你只是转储所有相同的数据到一个字符串,splitlines检查它\ r和\ n theres没有匹配,所以splitlines继续前进,直到遇到真正的换行符并且你得到你想要的行。