.NET i operacje na DUŻYCH plikach

0

Witam.
Dodałem słowo "DUŻYCH" w temacie, bo to słowo klucz. Przesiedziałem kilka godzin szukając w internecie ( także na stornach 4programmers ) rozwiązania i nic. Problem polega na tym, że W pracy korzystamy z oprogramowania ( pomijam szczegóły ), które daje eksport swojej bazy do postaci tekstowej ( wszystko jest w ASCI - nie ma żadnych danych binarnych ).

Sama baza wygląda tak, że rekordów jest około 85 000 a plik ma wielkość ok 35 MB. każdy rekord w eksporcie zaczyna się od znaku # a każdy atrybut jest w innym wierusz, czyli np:

'# koleżanka
ID:
imie:
Nazwisko:
Al:
kod:
numer:
'# koleżanka
ID:
imie:
Nazwisko:
Al:
kod:
numer:
'# koleżanka
ID:
imie:
Nazwisko:
Al:
kod:
numer:

przykład oczywiście nie ma nic wspólnego z bazą :)... ale oddaje jej istotę... koleżanek jest 85 000....

Teraz pytanie: Wczytałem te dane do stringa - ok poszło momentalnie. Problem pojawił się jak chciałem dzielić tego stringa na poszczególne rekordy... Na przykład:
szukałem sobie znaków :"#" metodą .IndexOf("#") potem dzieliłem myString.Substring( int , int) i wynik wpisywałem od razu do okna obok i przy 2500 rekordach ( pomniejszyłem bazę ). trwała to w nieskończoność.... Pytanie mam dosyć ogólne ( na razie ): czy C# i .NET nadaje się w ogóle do takich operacji ? jak tak to z jakich Narzędzi korzystać, bo powypisywane w tutorialach

myString.Substring
s1.IndexOf()

i w ogóle metody z kursów na programy typu "Hello World", czy "Ala ma kota" tu się nie przydają.

1

Jeżeli wczytałeś ten plik do stringa, to nie jest to duży plik :)

1

35 MB to malutki pliczek
ale zapewne za każdym razem szukasz znaku "#" i kopiujesz do innego stringa to co pozostaje - w takim przypadku za każdym razem kopiujesz w pamięci 35MB - razy ilość rekordów to jest prawie 3 TB danych do przerzucenia i przetworzenia przez procesor a to już sporo

niczego nie kopiuj z miejsca w miejsce - użyj wyrażeń regularnych do wyciągnięcia rekordów - jeżeli wyswietlasz na raz te rekordy to na kontrolce z której korzystasz użyj BeginUpdate / EndUpdate żeby się nie odświeżała za każdym razem - to też trwa bardzo długo

W ogóle nie powinieneś wczytywać tego pliku do pamięci na raz - powinieneś go traktować jako strumień i partiami wczytywać kolejne porcje danych - w ten sposób dwukrotnie zmniejszysz wymagania na pamięć swojego programu, a sam program będzie działał jeszcze szybciej

0

A tak z troche innej strony... Nie masz mozliwosci polaczenia sie z ta baza z poziomu swojej aplikacji?;p

0

Mało popularna aplikacja i nie daje możliwości posegregowania danych w taki sposób jaki jest nam potrzebny. Spróbuję zastosować się do wskazówek Świetny Mleczarz i jak się nie uda wkleję tu fragment kodu....

0

Zrobiłem sobie przerwę, i sprawdziłem coś takiego (proszę nie krzyczeć :D):

            Console.WriteLine("zapis pliku testowego");
            System.IO.StreamWriter fileToWrite = new System.IO.StreamWriter("test.txt");
            for (int i = 0; i < 500000; i++)
            {
                fileToWrite.WriteLine("#kolezanka\n{0}\nimie{1}\nNazwisko{2}\nUlica{3}\nKod\nNumer{0}\n", i, i + 1, i + 2, i + 3);
            }
            fileToWrite.Close();
            Console.WriteLine("Odczyt pliku tekstowego");
            System.Diagnostics.Stopwatch t = new System.Diagnostics.Stopwatch();
            t.Start();
            System.IO.StreamReader fileToRead = new System.IO.StreamReader("test.txt");
            string[] data = fileToRead.ReadToEnd().Split('#');
            fileToRead.Close();
            for (int i = 100; i < 120; i++)
            {
                Console.WriteLine(data[i]);
            }
            t.Stop();
            Console.WriteLine("zakonczono czytanie pliku, czas {0}", t.ElapsedMilliseconds);

Około 0,5 sekundy, plik ma 35,5 MB, rekordów widać ile :)

2

A czemu wczytywać do jednego stringa? Ja bym wczytał plik do tablicy stringów (metodą File.ReadAllLines), a potem przechodził w pętli i wybierał linijki zaczynające się od #. Proste i prawdopodobnie szybsze niż Regexy.

0

Dziękuję za wskazówki i fourfour za wstawienie fragmentu kodu... faktycznie 35 MB, to nie duży plik - wygłupiłem się ( ale pewnie nie takie rzeczy tu widzieliście ). Znalazłem problem.. a właściwie trzy: Jeden był związany ze sposobu odczytywania danych - który dzięki wam rozgryzłem.
Drugi jeszcze, że źle w pętli obliczałem przesunięcie wskaźnika do czytania tekstu ( nie wiem jak to się fachowo nazywa ) i wylatywałem poza stringa... chyba... no w każdym razie wskaźnik źle przesuwałem.

I trzeci nierozwiązany: Świetny Mleczarz dobrze zasugerowałeś że to sprawa się rozeszła się o wypisywanie w pętli stringów do richTextBox - zwolniło to program niemiłosiernie... ale temat kontrolek zostawię na inny na inny dzień. Na teraz wystarczy mi że nie lubią pętli :D... à propos BeginUpdate / EndUpdate jest do listboxa - nie ma czegoś takiego do richTextBox ? jak już nadmieniliśmy temat ?

0

Witam,

A nie można się do tego zabrać mniej więcej tak?

// -----------------------------------------------------------------------
// <copyright file="Record.cs" company="4programmers.net">
//   mr-owl, 4programmers.net, All Right Reserved
// </copyright>
// <summary>
//   Defines the Program type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ConsoleApplication1
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class Record
    {
        public int Id { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public string Al { get; set; }

        public string Code { get; set; }

        public string Number { get; set; }
    }
}
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Program.cs" company="4programmers.net">
//   mr-owl, 4programmers.net, All Right Reserved
// </copyright>
// <summary>
//   Defines the Program type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ConsoleApplication1
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;

    class Program
    {
        static void Main(string[] args)
        {
            var fileName = "SampleFileName";

            foreach (var record in GetRecords(fileName))
            {
                //rob co chcesz ze swoim pojedynczym rekordem
            }
        }

        private static IEnumerable<Record> GetRecords(string fileName)
        {
            Record record = null;

            using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                using (var sr = new StreamReader(fs, Encoding.Default))
                {
                    while (sr.Peek() > -1)
                    {
                        var line = sr.ReadLine();

                        if (string.IsNullOrEmpty(line))
                        {
                            continue;
                        }

                        if (line.Equals("'# koleżanka"))
                        {
                            if (record != null)
                            {
                                yield return record;
                            }

                            record = new Record();
                        }
                        else
                        {
                            if (record != null)
                            {
                                var code = line.Substring(0, line.IndexOf(":"));
                                switch (code)
                                {
                                    case "ID":
                                        record.Id = int.Parse(line.Substring(line.IndexOf(":")));
                                        break;
                                    case "imie":
                                        record.FirstName = line.Substring(line.IndexOf(":"));
                                        break;
                                    case "Nazwisko":
                                        record.LastName = line.Substring(line.IndexOf(":"));
                                        break;
                                    case "kod":
                                        record.Code = line.Substring(line.IndexOf(":"));
                                        break;
                                    case "numer":
                                        record.Number = line.Substring(line.IndexOf(":"));
                                        break;
                                }
                            }
                        }
                    }

                    if (record != null)
                    {
                        yield return record;
                    }
                }
            }
        }
    }
}

Pozdrawiam,

mr-owl

P.S. Kod jest jako poglądowy i może zawierać błędy

1 użytkowników online, w tym zalogowanych: 0, gości: 1