Rekurzivní hledání souborů   otázka

VB.NET, I/O operace

Zdravím a obracím se na Vás s prosbou o radu.

Vyhledávám skupiny souborů podle přípon na siťovém disku,

plním listview včetně data vytvoření, změny a velikosti

do subitems. Používám metodu GetFiles s volbou prohledávat

i podadresáře, přípony jsou v poli, v cyklu procházím pole

a opakovaně spouštím GetFiles do vyčerpání přípon v poli,

jedná se maximálně o pět přípon či chcete-li typů souborů.

Výsledky hledání nakonec seřadím dle potřeby přímo v listview.

Problém spočívá v tom, že je to neskutečně pomalé, obdobná

úloha zadaná TotalComandru zabere mnohem méně času.

Možná by bylo rychlejší plnit List a místo listview zvolit

třeba datagridview, předat mu List do DataSource?

Ale u listview není nutné řešit zobrazení ikon a textu

v jednom sloupci nějakým vlastním sloupcem a seřazení

podle sloupce je také rychlejší než u datagridview.

Mé pokusy s Win32 API FindFirstFile, FindNextFile ve vb.Net

dosahují lepší výsledky, ale jak je to budoucí s migrací na 64bit, bude to výhledově vůbec fungovat?

Další možností je možná WMI a předávání WQL dotazů, ale moc

nevěřím, že to bude rychlejší, přesto se chci zeptat na vaše

zkušenosti a poprosit o nějaké doporučení zrychlení hledání.

Nelze urychlit GetFiles v kombinaci s backgroundworkerem ?

Doufám, že budu mít stěstí na někoho ochotného se podělit

o cenné zkušenosti mezi zdejšími protřelými professionály.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

1) Hledání spouštějte ve vlastním vlákně.

2) Nepoužíval bych parametr searchOption = True u metody GetFiles, tam by mohla být příčina pomalého hledání. Napište vlastní rekurzivní algoritmus pro hledání, je to jednoduché.

3) Je jedno jestli se výsledek načítá do ListView nebo DataGridView a jestli se používá Data Binding.

4) WMI vůbec nebrat, to bude spíš mnohem pomalejší.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Děkuji za reakce, doporučení a ukázku.

Po odstranění SearchOption.AllDirectories metody GetFiles

se rychlost zvýšila o 30%, využívám parametr SearchPattern

se zástupným znakem bez nutnosti další podmínky a plním rovnou

listview ve snaze nemuset znovu procházet List cyklem při plnění

položek.

Spouštěním ve vlastním vlákně se budu muset prokousat...

Myslíte každé volání funkce ve vlastním vlákně, výsledky vláken

do nějaké fronty úloh a posléze naplnění položek listview?

Jak potom na info o průběhu hledání z vláken a jeho zobrazení?

Případnému dalšímu popostrčení se vůbec nebráním.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jednoduše kód metody, co se stará o procházení složek, přesuňte do události DoWork komponenty BackgroundWorker, která umožňuje jednoduché využití dalšího vlákna ve Windows Forms.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ono se řekne jednoduše,:) ale jelikož místo Listu plním

rovnou Listview ve snaze ušetřit si procházení Listu

při plnění položek listview, tak po přesunu kódu do jiného

vlákna ztratím přístup ke controls původního vlákna...

Nejprve se mi podařilo nalézt:

Control.CheckForIllegalCrossThreadCalls = False

Ale nakonec se mi podařilo nalézt inspiraci zde:

http://devcity.net/PrintArticle.aspx?Art...

V události backgroundworkeru ProgressChanged obdobně jako

v příkladu plním listview navíc včetně ikony souboru plus

subitems datumy vytvoření a změny, velikost souboru.

Bohužel v porovnání s verzí bez backgroundworkeru je to

naopak pomalejší.

Není nějaká možnost to ještě vylepšit?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

tak po přesunu kódu do jiného

vlákna ztratím přístup ke controls původního vlákna...

V žádném případě, pouze je potřeba invokovat kód pro UI v hlavním vlákně. Kdybyste podle mé rady používal BackgroundWorker, byl byste toho ušetřen.

Control.CheckForIllegalCrossThreadCalls = False

Tuhle zrůdnost v žádném případě nepoužívat!!!

V události backgroundworkeru ProgressChanged obdobně jako

v příkladu plním listview

Proč v ProgressChanged, která je určena pro aktualizaci průběhu operace?! K tomu slouží DoWork.

Pomalejší je to jistě mimo jiné proto, protože před aktualizací ListView nevoláte BeginUpdate a po ní EndUpdate a proto se to překresluje i když nemusí.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

pouze je potřeba invokovat kód pro UI v hlavním vlákně

Snažím se o tom něco načíst, proč se ušetřit, nejhorší

je nalézt dobrý příklad jinak nemám šanci to pochopit.

Myslíte tím něco na tento způsob s BeginInvoke:

http://msdn.microsoft.com/en-us/library/...

Pokouším se s tím seznámit a přidat ještě událost, která bude

informovat o průběhu hledání, např. právě prohledávaný adresář,

případně počet nalezených souborů, jak nejlépe událost vytvořit.

Bude-li mít někdo chvilku zkoukněte, zda-li postupuji správně.

Přidám deklaraci:

Private _onProgressChanged As EventHandler

...dále v New:

_onProgressChanged = New EventHandler(AddressOf OnProgressChanged)

...pak:

Private Sub OnProgressChanged(ByVal sender As Object, ByVal e As EventArgs)
            RaiseEvent ProgressChanged(sender, e)
        End Sub

... takhle předat do události parametry:

Public Class MyEventArgs
        Inherits EventArgs

        Public Sub New(ByVal directory As String, ByVal count As Long)
            Me.directory = directory
            Me.count = count
        End Sub

        Public directory As String
        Public count As Long
    End Class

... v RecurseDirectory vyvolat událost do listboxu :

BeginInvoke(_onProgressChanged, New Object() {Me, New MyEventArgs(directoryPath, _listBox.Items.Count)})

Potom ve Form1 v události ProgressChanged aktualizuji Label.

Funguje to... Ale je postup správný ?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ako povedal p. Linhart, spravte si vlastný rekurzívny mechanizmus.

Napríklad niečo podobné tomuto, tento kód vyhľadáva súbory určitých prípon, ktoré si určíte sami:

'Na začiatok súboru
Imports System.IO



'Do triedy/modulu
Public Sub SearchFiles(ByVal dir As DirectoryInfo, ByVal list As List(Of FileInfo), ByVal extensions As List(Of String))
    For Each file As FileInfo In dir.GetFiles'Pre každý súbor v zložke
        If extensions.Contains(file.Extension) Then'Ak je prípona súboru v zozname
            list.Add(file)' Vložiť súbor do zozname
        End If
    Next
    For Each dira As DirectoryInfo In dir.GetDirectories()'Pre každú podzložku
        SearchFiles(dira, list, extensions)'Rekurzívne volanie
    Next
End Sub



'Použitie:
Dim ext As New List(Of String)
'Do ext uložte zoznam hľadaných prípon
ext.Add(".sln")
ext.Add(".vbproj")
ext.Add(".csproj")
Dim lst As New List(Of FileInfo)
SearchFiles(New DirectoryInfo("C:\Users\Niky\Documents\Visual Studio 2010\Projects"), lst, ext)
'V lst máte zoznam súborov s príponou .sln alebo .vbproj alebo .csproj
nahlásit spamnahlásit spam 5 / 5 odpovědětodpovědět

Jsem programátor začátečník a příspěvek na který odpovídám je starý 3 roky, ale třeba se někomu bude hodit tento link, kde je tento problém řešen(a zřejmě výborně vyřešen) v C#: https://stackoverflow.com/questions/6061...

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback