none
Помогите организовать обработку лога Visual Basic RRS feed

  • Вопрос

  • Доброго времени суток)))

    Есть сквид лог,размер 8Гб))) его нужно обработать и вытыщить инфу по 10ти наиболее загружаемым сайтам.

    Проблема в том, что не могу организовать процесс так, чтобы читались первые 20000 строк,затем обрабатывались,результаты обработки сохранялись,а далее снова считывались следующие 20к строк и так до конца.

    28 сентября 2011 г. 6:39

Ответы

  • > Но в тоже время последующие вызовы Skip(offset) будут приводить к пустому чтению файла до offset?

    да.

    вместо Skip(..).Take(..) можно определить свой метод Chunk:

    foreach (var chunk in File.ReadLines(@"c:\temp\log.txt").Chunk(20000)) 
    {
        foreach (var lines in chunk) 
        { 
            // обработать строки в lines
        }
    };
    ...
    
    public static class LinqEx
    {
        public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> seq, int size)
        {
            var ret = new List<T>(size);
            foreach (var itm in seq)
            {
                ret.Add(itm);
                if (ret.Count == size)
                {
                    yield return ret;
                    ret.Clear();
                }
            }
            if (ret.Count > 0)
                yield return ret;
        }
    }
    

     

    • Помечено в качестве ответа AndrisRA 4 октября 2011 г. 4:44
    28 сентября 2011 г. 18:28

Все ответы

  • Можете локализовать проблемы? Например: "не знаю как читать из файла", "не знаю как сохранить", "как разделить чтение файла на блоки", "где хранить обработаную информацию" и т.д. Пока что непонятно как можно вам помочь, задача слишком общая.
    28 сентября 2011 г. 9:25
    Отвечающий
  • > организовать процесс так, чтобы читались первые 20000 строк,затем обрабатывались,результаты обработки сохранялись,а далее снова считывались следующие 20к строк и так до конца.

    примерно так:

     

    var offset = 0;
    while (true)
    {
        var lines = System.IO.File.ReadLines(@"c:\temp\log.txt").Skip(offset).Take(20000).Select(s => s);
        var count = 0;
        foreach (var line in lines)
        {
            count++;
            System.Diagnostics.Trace.WriteLine(line);
        }
        if (count == 0)
            break;
        offset += count;
    }
    

     


    • Изменено Malobukv 28 сентября 2011 г. 10:20
    • Предложено в качестве ответа Malobukv 28 сентября 2011 г. 10:21
    • Отменено предложение в качестве ответа Malobukv 28 сентября 2011 г. 13:19
    28 сентября 2011 г. 10:19
  • Можете локализовать проблемы? Например: "не знаю как читать из файла", "не знаю как сохранить", "как разделить чтение файла на блоки", "где хранить обработаную информацию" и т.д. Пока что непонятно как можно вам помочь, задача слишком общая.

    как разделить чтение файла на блоки)))
    или может быть проще будет разрезать исходный файл на части,а потом организовать уже их обработку?)
    • Изменено AndrisRA 28 сентября 2011 г. 10:38
    28 сентября 2011 г. 10:36
  • > организовать процесс так, чтобы читались первые 20000 строк,затем обрабатывались,результаты обработки сохранялись,а далее снова считывались следующие 20к строк и так до конца.

    примерно так:

     

    var offset = 0;
    while (true)
    {
        var lines = System.IO.File.ReadLines(@"c:\temp\log.txt").Skip(offset).Take(20000).Select(s => s);
        var count = 0;
        foreach (var line in lines)
        {
            count++;
            System.Diagnostics.Trace.WriteLine(line);
        }
        if (count == 0)
            break;
        offset += count;
    }
    

     



    а можно пример на Basic'e )))
    28 сентября 2011 г. 10:36
  • > организовать процесс так, чтобы читались первые 20000 строк,затем обрабатывались,результаты обработки сохранялись,а далее снова считывались следующие 20к строк и так до конца.

    примерно так:

     

    var offset = 0;
    while (true)
    {
        var lines = System.IO.File.ReadLines(@"c:\temp\log.txt").Skip(offset).Take(20000).Select(s => s);
        var count = 0;
        foreach (var line in lines)
        {
            count++;
            System.Diagnostics.Trace.WriteLine(line);
        }
        if (count == 0)
            break;
        offset += count;
    }
    

     



    Разве в этом случае не будет сначала считан весь файл в память? При этим памяти не хватит, т.к. размер файла 8 Гб.
    Для связи [mail]
    28 сентября 2011 г. 10:48
  • А нет, я ошибся, все должно быть хорошо =)

    AndrisRA, вы можете воспользоваться сервисом Convert C# to VB.NET для конвертации кода, если возникнут вопросы - задавайте.


    Для связи [mail]
    28 сентября 2011 г. 11:01
  • > Разве в этом случае не будет сначала считан весь файл в память?

    нет. в оcнове File.ReadLines используется итератор, вызывающий StreamReader.ReadLine(); у StreamReader по-умолчанию byteBuffer = new byte[0x400];

    28 сентября 2011 г. 11:07
  • Но в тоже время последующие вызовы Skip(offset) будут приводить к пустому чтению файла до offset? Т.е. на каждой итерации цикла while файл будет читаться с начала и до offset + 20000.

    Может проще просто читать последовательно файл один раз, записывая и очищая буффер по достижении 20000 строк?

                using (StreamReader sr = new StreamReader("log.txt"))
                {
                    string line;
                    int count = 0;
                    List<string> lines = new List<string>(20000);
    
                    while ((line = sr.ReadLine()) != null)
                    {
                        lines.Add(line);
                        if (++count == 20000)
                        {                       
                            // обработка 20000 строк
    
                            // после обработки
                            count = 0;
                            lines.Clear();
                        }
                    }
    
                    if (lines.Count > 0)
                    {
                        // обработка оставшихся данных
                    }
                }


    Для связи [mail]
    • Изменено Abolmasov Dmitry 28 сентября 2011 г. 11:16
    • Предложено в качестве ответа Malobukv 28 сентября 2011 г. 13:20
    28 сентября 2011 г. 11:15
  • > Но в тоже время последующие вызовы Skip(offset) будут приводить к пустому чтению файла до offset?

    да.

    вместо Skip(..).Take(..) можно определить свой метод Chunk:

    foreach (var chunk in File.ReadLines(@"c:\temp\log.txt").Chunk(20000)) 
    {
        foreach (var lines in chunk) 
        { 
            // обработать строки в lines
        }
    };
    ...
    
    public static class LinqEx
    {
        public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> seq, int size)
        {
            var ret = new List<T>(size);
            foreach (var itm in seq)
            {
                ret.Add(itm);
                if (ret.Count == size)
                {
                    yield return ret;
                    ret.Clear();
                }
            }
            if (ret.Count > 0)
                yield return ret;
        }
    }
    

     

    • Помечено в качестве ответа AndrisRA 4 октября 2011 г. 4:44
    28 сентября 2011 г. 18:28
  • Private Sub ButtonSchitat_Click(sender As System.Object, e As System.EventArgs) Handles ButtonSchitat.Click
            Dim filePath = filesListBox.SelectedItem.ToString
            Dim URLsVisited As New Collection()
            Dim IPsVisited As New Collection()
            Dim SizeVisited As New Collection()
            Dim q As Integer
            ' Читаем файл построчно и делим на слова
            Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(filePath)
                MyReader.TextFieldType = FileIO.FieldType.Delimited
                MyReader.SetDelimiters(" ")
                Dim Words As String()
                Dim Word As String
                Dim k, non As Integer
                q = 0
                Dim URL As String
                Dim regexp As New System.Text.RegularExpressions.Regex("/(?:http:\/\/)?[-0-9a-z._]*.\w{2,4}[:0-9]*/")
                Dim regexp1 As New System.Text.RegularExpressions.Regex("CONNECT")
                Dim regexpIP As New System.Text.RegularExpressions.Regex("^(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])){3}$")
                Dim regexpSize As New System.Text.RegularExpressions.Regex("TCP")
                Dim regexpGET As New System.Text.RegularExpressions.Regex("GET")
                Dim regexpPOST As New System.Text.RegularExpressions.Regex("POST")
                Dim fined As Boolean
                ' c помощью регулярных выражений отбираем только URL, IP-адрес пользователя и трафик
                While Not MyReader.EndOfData
                    Words = MyReader.ReadFields()
                    q = q + 1
                    For Each Word In Words
                        If fined = True Then
                            If regexpGET.IsMatch(Word).ToString() = True  Or regexpPOST.IsMatch(Word).ToString() = True Then
                                SizeVisited.Add("0")
                            Else
                                SizeVisited.Add(Word)
                            End If
                            fined = False
                        End If
                        If regexpIP.IsMatch(Word).ToString() = True Then
                            IPsVisited.Add(Word)
                            non = IPsVisited.Count
                        End If
                        If regexp1.IsMatch(Word).ToString() = True Then
                            IPsVisited.Remove(non)
                            SizeVisited.Remove(non)
                        End If
                        If regexp.IsMatch(Word).ToString() = True Then
                            k = InStr(8, Word, "/")
                            URL = Mid$(Word, 1, k)
                            URLsVisited.Add(URL)
                        End If
                        If regexpSize.IsMatch(Word).ToString() = True Then
                            fined = True
                        End If
    
    
                    Next
                End While
            End Using
    
            Dim poisk As Integer                 'номер найденного совпадающего адреса
            Dim kol, razmer As Integer
            razmer = 0
            kol = URLsVisited.Count
            Dim URLArray(kol) As String                  'массив сайтов
            Dim BootsArray(kol) As Integer               'число загрузок каждого сайта
            Dim IPArray(kol / 2, kol / 2) As String      'массив IP для каждого сайта
            Dim IPKolArray(kol) As Integer               'число IP для каждого конкретного сайта (на 1 меньше)
            Dim TrafikArray(kol) As Integer
            Dim SizeArray_for_IP(kol / 2, kol / 2) As Integer
            URLArray(0) = URLsVisited.Item(1)
            BootsArray(0) = 1
            IPArray(0, 0) = IPsVisited.Item(1)
            SizeArray_for_IP(0, 0) = SizeVisited(1)
            TrafikArray(0) = SizeVisited(1)
            For i = 2 To (URLsVisited.Count)
                poisk = System.Array.IndexOf(URLArray, URLsVisited.Item(i)) 'если очередной элемент коллекции не найден в массиве
                If poisk = -1 Then
                    URLArray(i - 1 - razmer) = URLsVisited.Item(i)
                    BootsArray(i - 1 - razmer) = 1
                    TrafikArray(i - 1 - razmer) = SizeVisited(i)
                    IPArray(i - 1 - razmer, 0) = IPsVisited.Item(i)
                    SizeArray_for_IP(i - 1 - razmer, 0) = SizeVisited(i)
                    IPKolArray(i - 1 - razmer) = 0
                Else                                                        'если найден
                    BootsArray(poisk) = BootsArray(poisk) + 1
                    TrafikArray(poisk) = TrafikArray(poisk) + SizeVisited(i)
                    IPKolArray(poisk) = IPKolArray(poisk) + 1
                    IPArray(poisk, IPKolArray(poisk)) = IPsVisited.Item(i)
                    SizeArray_for_IP(poisk, IPKolArray(poisk)) = SizeVisited(i)
                    kol = kol - 1                                           'считаем количество уникальных IP
                    razmer = razmer + 1                                     'величина на которую уменьшается массив с уникальными IP по отношению ко всему массиву IP 
                End If
            Next
    
            TextBox1.Text = TextBox1.Text & "Всего загрузок:   " & URLsVisited.Count & "  " & "Уникальных загрузок:   " & kol & vbCrLf
    
            Dim topbootArray(0 To 9) As Integer  ' десять величин наибольшей загрузки какого либо IP
            Dim maxArray(0 To 9) As Integer      ' десять номеров наиболее часто загружаемых сайтов
            Dim topTrafikArray(0 To 9) As Integer
            Dim j As Integer
            For j = 1 To 10
                For i = 1 To kol
                    If TrafikArray(i - 1) >= topTrafikArray(j - 1) Then 'из всего массива значений загрузок каждого IP ищем максимальный
                        topTrafikArray(j - 1) = TrafikArray(i - 1)
                        topbootArray(j - 1) = BootsArray(i - 1)
                        maxArray(j - 1) = i - 1
                    End If
                Next
                TrafikArray(maxArray(j - 1)) = 0
            Next
            ' For i = 0 To 60
            TextBox2.Text = TextBox2.Text & IPsVisited.Count & "  " & SizeVisited.Count & "  " & vbCrLf
            ' Next
            Dim poiskIP0, razmerIP0, maxIP_0 As Integer
            Dim IP_0_Array(topbootArray(0) - 1) As String           'массив уникальных IP для конкретного адреса
            Dim IP_0_bootArray(topbootArray(0) - 1) As Integer      'массив значений загрузок с этого IP
            Dim maxIP_0_SizeArray(topbootArray(0) - 1) As Integer
            Dim max_Size_Array(9) As Integer                          '
            Dim maxIP_0_bootArray(9) As Integer                       ' определение 10ти самых прожорливых пользователей
            Dim maxIP_0_Array(9) As String                            ' 
            For j = 0 To 9
                IP_0_Array(0) = IPArray(maxArray(j), 0)
                IP_0_bootArray(0) = 1
                maxIP_0_SizeArray(0) = SizeArray_for_IP(maxArray(j), 0)
                razmerIP0 = 0
                For i = 1 To (topbootArray(j) - 1)
                    poiskIP0 = System.Array.IndexOf(IP_0_Array, IPArray(maxArray(j), i))
                    If poiskIP0 = -1 Then
                        IP_0_Array(i - razmerIP0) = IPArray(maxArray(j), i)
                        maxIP_0_SizeArray(i - razmerIP0) = SizeArray_for_IP(maxArray(j), i)
                        IP_0_bootArray(i - razmerIP0) = 1
                    Else
                        maxIP_0_SizeArray(poiskIP0) = maxIP_0_SizeArray(poiskIP0) + SizeArray_for_IP(maxArray(j), i)
                        IP_0_bootArray(poiskIP0) = IP_0_bootArray(poiskIP0) + 1
                        razmerIP0 = razmerIP0 + 1
                    End If
                Next
                maxIP_0 = 0
    
                For i = 0 To (topbootArray(j) - 2 - razmerIP0)
                    If maxIP_0_SizeArray(i + 1) > maxIP_0_SizeArray(i) Then
                        maxIP_0 = i + 1
                    End If
                Next
                maxIP_0_Array(j) = IP_0_Array(maxIP_0)
                maxIP_0_bootArray(j) = IP_0_bootArray(maxIP_0)
                max_Size_Array(j) = maxIP_0_SizeArray(maxIP_0)
                For i = 0 To (topbootArray(j) - 1 - razmerIP0)
                    IP_0_Array(i) = ""
                    IP_0_bootArray(i) = 0
                    maxIP_0_SizeArray(i) = 0
                Next
            Next
    
            Dim maxUser_0_Array(9) As String                'массив имен пользователей для ТОР10
            Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser("C:\Users\ReskaysAI\Desktop\user_log.ini")
                MyReader.TextFieldType = FileIO.FieldType.Delimited
                MyReader.SetDelimiters(",")                 '  
                Dim currentRow As String()                  ' определяем имя пользователя для данного IP
                Dim currentField As String                  '    
                Dim vremenniy As String                     '
                vremenniy = " "                             '
                While Not MyReader.EndOfData                '
                    currentRow = MyReader.ReadFields()      '
                    For Each currentField In currentRow     '
                        For i = 0 To 9                      '
                            If currentField <> maxIP_0_Array(i) Then
                                Dim regexpIP As New System.Text.RegularExpressions.Regex("^(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])){3}$")
                                If regexpIP.IsMatch(currentField).ToString() = False Then
                                    vremenniy = currentField
                                End If
                            Else
                                maxUser_0_Array(i) = vremenniy
                            End If
                        Next
                    Next
                End While
            End Using
            Label48.Text = topTrafikArray(0)   ' 10ка значиний общего трафика для адреса
            Label49.Text = topTrafikArray(1)
            Label50.Text = topTrafikArray(2)
            Label51.Text = topTrafikArray(3)
            Label52.Text = topTrafikArray(4)
            Label53.Text = topTrafikArray(5)
            Label54.Text = topTrafikArray(6)
            Label55.Text = topTrafikArray(7)
            Label56.Text = topTrafikArray(8)
            Label57.Text = topTrafikArray(9)
    
            Label38.Text = max_Size_Array(0)   ' 10ка значений трафика пользователя для сайта
            Label39.Text = max_Size_Array(1)
            Label40.Text = max_Size_Array(2)
            Label41.Text = max_Size_Array(3)
            Label42.Text = max_Size_Array(4)
            Label43.Text = max_Size_Array(5)
            Label44.Text = max_Size_Array(6)
            Label45.Text = max_Size_Array(7)
            Label46.Text = max_Size_Array(8)
            Label47.Text = max_Size_Array(9)
    
            Label26.Text = maxUser_0_Array(0)  ' 10ка имен пользователей
            Label27.Text = maxUser_0_Array(1)
            Label28.Text = maxUser_0_Array(2)
            Label29.Text = maxUser_0_Array(3)
            Label30.Text = maxUser_0_Array(4)
            Label31.Text = maxUser_0_Array(5)
            Label32.Text = maxUser_0_Array(6)
            Label33.Text = maxUser_0_Array(7)
            Label34.Text = maxUser_0_Array(8)
            Label35.Text = maxUser_0_Array(9)
    
            LinkLabel1.Text = URLArray(maxArray(0))   ' 10ка адресов,с который идет наибольший трафик
            LinkLabel2.Text = URLArray(maxArray(1))
            LinkLabel3.Text = URLArray(maxArray(2))
            LinkLabel4.Text = URLArray(maxArray(3))
            LinkLabel5.Text = URLArray(maxArray(4))
            LinkLabel6.Text = URLArray(maxArray(5))
            LinkLabel7.Text = URLArray(maxArray(6))
            LinkLabel8.Text = URLArray(maxArray(7))
            LinkLabel9.Text = URLArray(maxArray(8))
            LinkLabel10.Text = URLArray(maxArray(9))
    
            Label16.Text = topbootArray(0)  ' 10ка значений количества перехода на сайт
            Label17.Text = topbootArray(1)
            Label18.Text = topbootArray(2)
            Label19.Text = topbootArray(3)
            Label20.Text = topbootArray(4)
            Label21.Text = topbootArray(5)
            Label22.Text = topbootArray(6)
            Label23.Text = topbootArray(7)
            Label24.Text = topbootArray(8)
            Label25.Text = topbootArray(9)
    
    вот что есть) здесь читаю файл размером 20000 строк,получаю десятку самых прожорливых пользователей и сайты откуда они съели))) если можно, исправьте так, чтобы,собственно, можно было ему кинуть файл в 8Гб и получить результат)))
    29 сентября 2011 г. 11:50
  • 1309842937.980     25 192.168.30.240 TCP_MISS/200 408 GET http://ad.interfax.ru/AdHandler/Banner.ashx? - DIRECT/46.28.16.192 -401
    1309842937.989      3 192.168.30.241 TCP_IMS_HIT/304 GET http://www.shinnik.com/bitrix/templates/shinnik/components/bitrix/news.list/table/images/arrow_down.gif - NONE/- image/gif
    1309842937.989    395 192.168.30.242 TCP_MISS/304 200 GET http://a.tribalfusion.com/displayAd.js? - DIRECT/204.11.109.24 -
    1309842938.500     66 192.168.30.243 TCP_HIT/200 20463 GET http://cdn5.tribalfusion.com/media/2467836.gif - NONE/- image/gif
    1309842938.501     15 192.168.30.244 TCP_MISS/304 233 GET http://lib.aldebaran.ru/author/makgil_gordon/makgil_gordon_omen_armageddon_2000/confrm.js - DIRECT/195.42.181.163 -
    1309783508.932   4149 192.168.13.125 TCP_MISS/200 5379 CONNECT urs.microsoft.com:443 - DIRECT/64.4.28.253 -
    1309842937.980     25 192.168.30.245 TCP_MISS/200 408 GET http://ad.interfax.ru/AdHandler/Banner.ashx? - DIRECT/46.28.16.192 -401
    1309842937.980     25 192.168.30.246 TCP_MISS/200 408 GET http://ad.interfax.ru/AdHandler/Banner.ashx? - DIRECT/46.28.16.192 -401
    1309842937.989      3 192.168.30.247 TCP_IMS_HIT/304 GET http://www.shinnik.com/bitrix/templates/shinnik/components/bitrix/news.list/table/images/arrow_down.gif - NONE/- image/gif
    1309842938.427      6 192.168.30.248 TCP_MISS/503 1387 GET http://ealo.net:81/sx110/fda.bin - DIRECT/ealo.net text/html
    1309783508.932   4149 192.168.13.125 TCP_MISS/200 5379 CONNECT urs.microsoft.com:443 - DIRECT/64.4.28.253 -
    1309842937.980     25 192.168.30.240 TCP_MISS/200 408 GET http://ad.interfax.ru/AdHandler/Banner.ashx? - DIRECT/46.28.16.192 -401
    1309842937.980     25 192.168.30.247 TCP_MISS/200 408 GET http://ad.interfax.ru/AdHandler/Banner.ashx? - DIRECT/46.28.16.192 -401
    1309842937.989      3 192.168.36.241 TCP_IMS_HIT/304 POST http://www.1shinnik.com/bitrix/templates/shinnik/components/bitrix/news.list/table/images/arrow_down.gif - NONE/- image/gif
    1309842937.989      3 192.168.30.240 TCP_IMS_HIT/304 GET http://www.3shinnik.com/bitrix/templates/shinnik/components/bitrix/news.list/table/images/arrow_down.gif - NONE/- image/gif
    1309842937.989      3 192.168.30.240 TCP_IMS_HIT/304 POST http://www.3shinnik.com/bitrix/templates/shinnik/components/bitrix/news.list/table/images/arrow_down.gif - NONE/- image/gif
    1309783508.932   4149 192.168.13.125 TCP_MISS/200 5379 CONNECT urs.microsoft.com:443 - DIRECT/64.4.28.253 -
    1309842938.427      6 192.168.30.248 TCP_MISS/503 1387 GET http://TEST111.net:81/sx110/fda.bin - DIRECT/ealo.net text/html
    1309842938.427      6 192.168.30.248 TCP_MISS/503 1387 GET http://TEST222.net:81/sx110/fda.bin - DIRECT/ealo.net text/html
    29 сентября 2011 г. 11:52
  • см. блог Hanselman, MSFT: Log Parser (... SQL queries against text files)

    • Предложено в качестве ответа Malobukv 2 октября 2011 г. 7:29
    29 сентября 2011 г. 12:00
  • это понятно что можно все свести к базам или просто постасить Internet Access Monitor))) но мне нужно этого монстра дописать(((а мозг уже кипит(((

    29 сентября 2011 г. 12:09
  • > это понятно что можно все свести к базам

    Log Parser извлекает данные из существующих текстовых файлов. язык запросов для извлечения данных является sql-подобным.

    29 сентября 2011 г. 12:45