2015-07-09 3 views
2

Я столкнулся с любопытной проблемой при анализе объектов json в больших текстовых файлах, и решение, которое я нашел, на самом деле не имеет особого смысла. Я работал со следующим скриптом. Он копирует файлы bz2, распаковывает их, затем анализирует каждую строку как объект json.Python - пропущенные символы Readline

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

Попробуйте просто выполнить итерацию непосредственно в файле: 'для строки ввода: ...' – poke

+0

Не могу сказать, почему она не работает, но может предложить предложение. 'readlines()' is noteccesary, вы можете перебирать файл-объект непосредственно таким образом: 'для строки на входе:' – SiHa

+0

Да, я пробовал это. Это привело к тому же вопросу. –

ответ

2

Посмотрев исходный код файла .readlines и string.splitlines Я думаю, что вижу, что происходит. Примечание: это исходный код python 2.7, поэтому, если вы используете другую версию ... возможно, этот ответ относится, может быть, и нет.

readlines использует функцию Py_UniversalNewlineFread для тестирования для новой строки splitlines использует постоянный STRINGLIB_ISLINEBREAK, что только тесты для \ п или \ г. Я бы заподозрил, что Py_UniversalNewlineFread подбирает какой-то символ в потоке файлов в качестве строки, когда он не предназначен для разрыва строки, может быть из кодировки. Я не знаю ... но когда вы просто отправляете все эти же данные в строка, разделительные линии которой проверяют ее на \ r и \ n, нет совпадений, поэтому разделенные линии перемещаются до тех пор, пока не встретится реальный разрыв строки, и вы получите свою предполагаемую линию.

Смежные вопросы