обрабатывать большой текстовый файл в Python - PullRequest
4 голосов
/ 27 июля 2011

У меня есть очень большой файл (3.8G), который является извлечением пользователей из системы в моей школе. Мне нужно обработать этот файл так, чтобы он просто содержал их идентификатор и адрес электронной почты, разделенные запятой.

У меня очень мало опыта с этим, и я хотел бы использовать его в качестве учебного упражнения для Python.

В файле есть записи, которые выглядят так:

dn: uid=123456789012345,ou=Students,o=system.edu,o=system
LoginId: 0099886
mail: fflintstone@system.edu

dn: uid=543210987654321,ou=Students,o=system.edu,o=system
LoginId: 0083156
mail: brubble@system.edu

Я пытаюсь получить файл, который выглядит так:

0099886,fflintstone@system.edu
0083156,brubble@system.edu

Любые советы или код?

Ответы [ 4 ]

10 голосов
/ 27 июля 2011

Для меня это выглядит как LDIF файл. Библиотека python-ldap имеет библиотеку обработки чистого LDIF-языка Python, которая может помочь, если в вашем файле есть некоторые неприятные ошибки, возможные в LDIF, например. Значения в кодировке Base64, сворачивание записей и т. Д.

Вы можете использовать это так:

import csv
import ldif

class ParseRecords(ldif.LDIFParser):
   def __init__(self, csv_writer):
       self.csv_writer = csv_writer
   def handle(self, dn, entry):
       self.csv_writer.writerow([entry['LoginId'], entry['mail']])

with open('/path/to/large_file') as input, with open('output_file', 'wb') as output:
    csv_writer = csv.writer(output)
    csv_writer.writerow(['LoginId', 'Mail'])
    ParseRecords(input, csv_writer).parse()

Редактировать

Таким образом, чтобы извлечь из действующего каталога LDAP, используя библиотеку python-ldap , вы захотите сделать что-то вроде этого:

import csv
import ldap

con = ldap.initialize('ldap://server.fqdn.system.edu')
# if you're LDAP directory requires authentication
# con.bind_s(username, password)

try:
    with open('output_file', 'wb') as output:
        csv_writer = csv.writer(output)
        csv_writer.writerow(['LoginId', 'Mail'])

        for dn, attrs in con.search_s('ou=Students,o=system.edu,o=system', ldap.SCOPE_SUBTREE, attrlist = ['LoginId','mail']:
            csv_writer.writerow([attrs['LoginId'], attrs['mail']])
finally:
    # even if you don't have credentials, it's usually good to unbind
    con.unbind_s()

Вероятно, стоит прочитать документацию для модуля ldap , особенно пример .

Обратите внимание, что в приведенном выше примере я полностью пропустил поставку фильтра, который вы, вероятно, захотите сделать в производстве. Фильтр в LDAP аналогичен предложению WHERE в выражении SQL; он ограничивает возвращаемые объекты. У Microsoft действительно есть хорошее руководство по фильтрам LDAP . Каноническая ссылка для фильтров LDAP: RFC 4515 .

Точно так же, если существует потенциально несколько тысяч записей даже после применения соответствующего фильтра, вам, возможно, придется взглянуть на элемент управления пейджингом LDAP , хотя его использование снова усложнит пример. Надеюсь, этого достаточно, чтобы вы начали, но если что-то появится, не стесняйтесь задавать или открывать новый вопрос.

Удачи.

5 голосов
/ 27 июля 2011

Предполагая, что структура каждой записи всегда будет одинаковой, просто сделайте что-то вроде этого:

import csv

# Open the file
f = open("/path/to/large.file", "r")
# Create an output file
output_file = open("/desired/path/to/final/file", "w")

# Use the CSV module to make use of existing functionality.
final_file = csv.writer(output_file)

# Write the header row - can be skipped if headers not needed.
final_file.writerow(["LoginID","EmailAddress"])

# Set up our temporary cache for a user
current_user = []

# Iterate over the large file
# Note that we are avoiding loading the entire file into memory
for line in f:
    if line.startswith("LoginID"):
        current_user.append(line[9:].strip())
    # If more information is desired, simply add it to the conditions here
    # (additional elif's should do)
    # and add it to the current user.

    elif line.startswith("mail"):
        current_user.append(line[6:].strip())
        # Once you know you have reached the end of a user entry
        # write the row to the final file
        # and clear your temporary list.
        final_file.writerow(current_user)
        current_user = []

    # Skip lines that aren't interesting.
    else:
        continue
1 голос
/ 27 июля 2011

Опять же, если ваш файл правильно сформирован:

with open(inputfilename) as inputfile, with open(outputfilename) as outputfile:
    mail = loginid = ''
    for line in inputfile:
        line = inputfile.split(':')
        if line[0] not in ('LoginId', 'mail'):
            continue
        if line[0] == 'LoginId':
            loginid = line[1].strip()
        if line[0] == 'mail':
            mail = line[1].strip()
        if mail and loginid:
            output.write(loginid + ',' + mail + '\n')
            mail = loginid = ''

По существу эквивалентен другим методам.

0 голосов
/ 27 июля 2011

Чтобы открыть файл, вам нужно использовать что-то вроде ключевого слова with, чтобы убедиться, что он правильно закрывается, даже если что-то идет не так:

with open(<your_file>, "r") as f:
   # Do stuff

Что касается фактического анализа этой информации, я 'Я рекомендую создать словарь идентификаторов пар электронной почты.Вам также понадобится переменная для идентификатора пользователя и адреса электронной почты.

data = {}
uid = 0
email = ""

Для фактического анализа файла (материал запускается, когда ваш файл открыт), вы можете сделать что-то вроде этого:

for line in f:
    if "uid=" in line:
        # Parse the user id out by grabbing the substring between the first = and ,
        uid = line[line.find("=")+1:line.find(",")]
    elif "mail:" in line:
        # Parse the email out by grabbing everything from the : to the end (removing the newline character)
        email = line[line.find(": ")+2:-1]
        # Given the formatting you've provided, this comes second so we can make an entry into the dict here
        data[uid] = email

Используя средство записи CSV (не забудьте импортировать CSV в начале файла), мы можем вывести следующее:

writer = csv.writer(<filename>)
writer.writerow("User, Email")
for id, mail in data.iteritems:
    writer.writerow(id + "," + mail)

Другой вариант - открыть средство записи перед файлом, написать заголовок, затем прочитайте строки из файла одновременно с записью в CSV.Это позволяет избежать сброса информации в память, что может быть очень желательно.Итак, сложив все вместе, мы получим

writer = csv.writer(<filename>)
writer.writerow("User, Email")
with open(<your_file>, "r") as f:
    for line in f:
        if "uid=" in line:
            # Parse the user id out by grabbing the substring between the first = and ,
            uid = line[line.find("=")+1:line.find(",")]
        elif "mail:" in line:
            # Parse the email out by grabbing everything from the : to the end (removing the newline character)
            email = line[line.find(": ")+2:-1]
            # Given the formatting you've provided, this comes second so we can make an entry into the dict here
            writer.writerow(iid + "," + email)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...