LINUX.ORG.RU

Python прочитать фаил от начала до конца


0

2

Добрый день.

Задача, есть фаил логов статитики от биллинга, его надо разобрать по байтно и запихнуть в базу. Читать побайтно я научился, но не могу понять как правильно написать цикл для того что бы он прочитал фаил целиком, подскажите пожалуйста!

функцию чтения и разбора написал

f = open(«test_raw.raw», «rb»)

def fReadRawLine(f):

udef = f.read(4); # 1-4
src_ip = f.read(4); # 5-8
dst_ip = f.read(4); # 9-12
undef = f.read(8); # 13-20
packets = f.read(4); # 21-24
bytes = f.read(4); # 25-28
undef = f.read(4); # 29-32
undef = f.read(4); # 33-36
src_p = f.read(2); # 37-38
dst_p = f.read(2); # 39-40
undef = f.read(16); # 41-56
acc_id = f.read(4); # 57-60
undef = f.read(4); # 61-64
tclass = f.read(4); # 65-68
tstamp = f.read(4); # 69-72
undef = f.read(4); # 73-76

src_ip = struct.unpack(«i», src_ip)
dst_ip = struct.unpack(«i», dst_ip)
packets = struct.unpack(«i», packets)
bytes = struct.unpack(«i», bytes)
src_p = struct.unpack(«h», src_p)
dst_p = struct.unpack(«h», dst_p)
acc_id = struct.unpack(«i», acc_id)
tclass = struct.unpack(«i», tclass)
tstamp = struct.unpack(«i», tstamp)

С питоном только начинаю дружить, поэтому буду рад любому совету, может в целом подход и реализация не правильная?


А там эти логи друг за другом лежат пачкой? Тогда в бесконечном цикле чиать лог за логом, пока не вылетит исключение

AIv ★★★★★
()

Лучше так:

def ReadRawLines(f):
    data = f.read(76)
    if len(data) == 76:
        yield struct.unpack("iii...")

for src_ip, dst_ip, ... in ReadRawLines(f):
    # Process next record

rymis ★★
()

Для начала, не надо использовать много реадов по 4 байта. Прочитай одну структуру целиком (76 байт) и используй структ унпак сразу с несколькими (16) буквами. Он тебе даст всю какбы строку целиком.

Ну а далее используй цикл, который читает файл кусками по 76 байт пока не получит пустую строку. Не забудь организовать дочитывание до полных 76 байт. Реад может вернуть и меньше. Но если вернул пусто то это точно конец файла.

Исправленный варинт клади сюда.

mmarkk
()

фаил

FAIL?

anonymous
()
Ответ на: комментарий от mmarkk

Ну вообщем получилось что-то типа такого:

import struct
import socket

f = open("test_raw.raw", "rb")
EndFileFlag = 1
StrCount = 0

def ReadRawLines(f):
    global flag,StrCount
    data = f.read(76)
    if len(data) == 76:
        yield struct.unpack("iiiqiiiiHHqqiiiii", data);
        StrCount = StrCount + 1
    else:
        EndFileFlag = 0

while (EndFileFlag == 1):
    for udef, src_ip, dst_ip, undef, packets, bytes, undef, undef, src_p, dst_p, undef, undef, acc_id, undef, tclass, tstamp, undef in ReadRawLines(f):
        src_ip = socket.inet_ntoa(struct.pack('!L',src_ip))
        dst_ip = socket.inet_ntoa(struct.pack('!L',dst_ip))
        print src_ip,dst_ip,packets,bytes,src_p,dst_p,acc_id,tclass,tstamp
f.close()

В целом работает как надо. разбирает файл, но иногда проскакивает вот такая ошибка:

DeprecationWarning: struct integer overflow masking is deprecated (ругаеться на строчку где использую преобразование inet_ntoa.) причем не сомтря на предупреждение, все же все строки совподают с оригнальной утилиткой, и рассхождения по данным нет, не подскажете из-за чего это может быть?

Morbid
() автор топика
Ответ на: комментарий от Morbid

Не проверял, но должно работать:

#!/usr/bin/python
# coding: utf-8

import struct
import socket

def readall(f, length):
    res = ''
    while length:
        chunk = f.read(length)
        if not chunk:
            break
        length -= len(chunk)
        res += chunk

    if length and res:
        raise Exception('Short read near the end of file')
    return res

def generate_line(filename):
    unpacker = struct.Struct("!iLLqiiiiHHqqiiiii")
    # TODO: remake more fast implementation, using:
    # unpacker.unpack_from(infile, offset); offset+=unpacker.size
    with open(filename, "rb") as infile:
        while 1:
            line = readall(infile, unpacker.size)
            if not line:
                break
            yield unpacker.unpack(line)

def main():
    lines_count = 0
    for i in generate_line("test_raw.raw"):
        (
        _udef,
        src_ip,
        dst_ip,
        _undef,
        packets,
        mybytes,
        _undef,
        _undef,
        src_p,
        dst_p,
        _undef,
        _undef,
        acc_id,
        _undef,
        tclass,
        tstamp,
        _undef,
        ) = i
        src_ip = socket.inet_ntoa (src_ip)
        dst_ip = socket.inet_ntoa (dst_ip)
        lines_count += 1
        print src_ip, dst_ip, packets, mybytes, src_p, dst_p, acc_id, tclass, tstamp
    print '{0} Line(s) total'.format(lines_count)

if __name__ == '__main__':
    main()

mmarkk
()
Ответ на: комментарий от Morbid

но иногда проскакивает ошибка

import warnings
warnings.filterwarnings("ignore", category = DeprecationWarning)

:)

nitz ★★
()
Ответ на: комментарий от mmarkk

УПС. L в формате надо заменить на 4s. тогда должно быть норм.

И ещё, ты не сказал с какой эндианностью записаны другие интеджеры...

mmarkk
()
Ответ на: комментарий от mmarkk

Есть ещё одна улучшалка по грамотному разделению функицонала: сделать

with open("test_raw.raw", "rb") as infile:
    for i in generate_line(infile):

mmarkk
()
Ответ на: комментарий от mmarkk

то что написано в TODO работать не будет. для этого нужен mmap. будет быстрее. точно. но не намного (для питона).

mmarkk
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.