Diskuze: Jak ukončit nečítání souborů?

C# .NET .NET (C# a Visual Basic) Jak ukončit nečítání souborů? American English version English version

Avatar
jt.e
Člen
Avatar
jt.e:

Ahoj, potřeboval bych zase poradit: mám Formulářovou aplikaci, která načítá soubory (do několika Listů, ComboBoxů, TextBoxů apd. Při načítání zobrazuji okno "čekejte prosím..", no a na tomto okně bych rád měl tlačítko "storno", kterým bych chtěl přerušit načítání. Jak na to? (Napadá mne Thread, ale nevím jak s přístupem k formuláři.)

Editováno 29. ledna 21:23
 
Odpovědět 29. ledna 21:21
Avatar
Tomáš Brůna
Redaktor
Avatar
Odpovídá na jt.e
Tomáš Brůna:

Jaké soubory načítáš? A co používáš na čtení za třídu? :)

Nahoru Odpovědět 29. ledna 21:27
Lepší být šprt než blbec :)
Avatar
Tomáš Brůna
Redaktor
Avatar
Tomáš Brůna:

jedna z možností by mohla být takto:

private boolean tlacitkoStornoStisknuto;

.....tlacitko_click.......(){
 this.tlacitkoStornoStisknuto = true;
}

....nacti.....
{
 while(this.tlacitkoStornoStisknuto != true)
 {
  //čtení
 }
}
Nahoru Odpovědět 29. ledna 21:31
Lepší být šprt než blbec :)
Avatar
jt.e
Člen
Avatar
Odpovídá na Tomáš Brůna
jt.e:

ani mi tak nejde o vlastní čtení souborů, to trvá asi tak 2-3 sec, ale o ověřování existence souborů a složek - to trvá někdy dost dlouho, protože jsou často v síti.

 
Nahoru Odpovědět 29. ledna 21:37
Avatar
Tomáš Brůna
Redaktor
Avatar
Odpovídá na jt.e
Tomáš Brůna:

promiň, nějak teda nechápu dotaz :), mám bohužel takovou blbou vlastnost že většinu věcí chápu jinak než ostatní ;)

Nahoru Odpovědět 29. ledna 21:40
Lepší být šprt než blbec :)
Avatar
jt.e
Člen
Avatar
Odpovídá na Tomáš Brůna
jt.e:

Moje chyba, jsem to dost podrobně nepopsal (nepovažoval jsem to za důležité). Jde mi o to, že někdy vypadne síť, a pak mi aplikace při načítání zamrzne (třeba na 2 minuty), než zjistí, že je soubor nenalezen. Já bych chtěl mít možnost tu aplikaci ukončit, protože jsem už při tom čekání zjistil, že nefunguje síť.

 
Nahoru Odpovědět 29. ledna 21:47
Avatar
Adam Ježek
Tým ITnetwork
Avatar
Odpovídá na jt.e
Adam Ježek:

Pokud dobře vím, tak to nebude zrovna nejjednodušší.
Můžeš sem hodit těch pár řádků kódu ve kterejch kontroluješ přítomnost souboru a načítáš ho?

Možná by to šlo zabalit do vlákna a pak na něj zavolat thread.Abort(), jenže to se už moc nedoporučuje a ani nevim jestli ho to chcípne hned nebo počká na ukončení rozdělané věci.

Editováno 29. ledna 21:50
Nahoru Odpovědět  -1 29. ledna 21:50
Pokud chceš odpovědět, klikni na odpovědět. Pokud chceš vložit zdroják, klikni na vložit zdroják (</>)
Avatar
Tomáš Brůna
Redaktor
Avatar
Odpovídá na jt.e
Tomáš Brůna:

tak to netuším :(

Editováno 29. ledna 21:52
Nahoru Odpovědět 29. ledna 21:50
Lepší být šprt než blbec :)
Avatar
jt.e
Člen
Avatar
jt.e:

Přítomnost souboru testuji klasicky přes File.Existsts()

třeba tohle je první věc co načítám:

/// <summary>
/// načte položky ze souboru
/// </summary>
/// <param name="c"></param>
/// <param name="filename"></param>
/// <param name="silent">true=nebude zobrazovat chybové zprávy</param>
public static void LoadComboItems(this ComboBox c, string filename, bool silent)
{
    if (c.Items.Count > 0) c.Items.Clear();

    try
    {
        string[] lines = File.ReadAllLines(filename, Encoding.Default);
        foreach (string s in lines) c.Items.Add(s);
    }
    catch (Exception e)
    {
        if (silent == false)
        {
            string msg = e.Message + "\nChyba pro soubor:\n" + filename;
            MessageBox.Show(msg, "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}
Editováno 29. ledna 21:57
 
Nahoru Odpovědět 29. ledna 21:55
Avatar
Odpovídá na jt.e
Petr Čech (czubehead):

Můžeš to dát do async metody, budeš mít statickou vlastnost bool která bude říkat, jestli se má přerušit načítání. Tu vlastnost zkontroluješ vždy před každým File.Exists, když bude true, nějak to načítání dropneš, třeba returnem.
Asi to není nejlepší řešení, ale je nejjednodušší.
Můžeš se podívat sem: https://msdn.microsoft.com/…ary/dd537607(v=vs.110).aspx

Editováno 29. ledna 22:06
Nahoru Odpovědět 29. ledna 22:04
Why so serious? -Joker
Avatar
jt.e
Člen
Avatar
jt.e:

Teď mě napadá, že můžu dát do vlákna pouze File.Exists, a to pak kdykoliv ukončit, ale nevím jako moc rozumné je to řešení....

 
Nahoru Odpovědět 29. ledna 22:04
Avatar
jt.e
Člen
Avatar
Odpovídá na Petr Čech (czubehead)
jt.e:

ale to zase nemůžu kontrolovat při metodě File.Exists, myslím si, že z nějakého důvodu trvá dlouho pouze první zjištění, (nejspíš, že jde o podobné umístění), pak to jde rychle.

Editováno 29. ledna 22:09
 
Nahoru Odpovědět 29. ledna 22:07
Avatar
jt.e
Člen
Avatar
jt.e:

To bych asi musel vytvořit další vlákno, které bude kontrolovat ten statický bool a ukončovat vlákno s file.exists. Není to moc "krkolomné" řešení?

 
Nahoru Odpovědět 29. ledna 22:12
Avatar
Petr Čech (czubehead):

Takže tohle jsem vyplodil: tak by se to mělo správně dělat. Jen tam může být malá prodleva mezi kliknutím a zrušením.

private CancellationTokenSource tokenSource;

        private bool? CheckFiles(IEnumerable<string> files, CancellationToken token)
        {
            try
            {
                foreach (var s in files)
                {
                    token.ThrowIfCancellationRequested();
                    Thread.Sleep(400); //kontrola
                }
                return true;
            }
            catch (OperationCanceledException e)
            {
                MessageBox.Show("canceled");
                return null;
            }
        }

        private async void startBtn_click(object sender, EventArgs e)//start
        {
            tokenSource = new CancellationTokenSource();

            List<string> fileList = new List<string>();
            for (int i = 0; i < 20; i++)
            {
                fileList.Add("");
            }

            bool? loaded=await Task.Factory.StartNew(()=>CheckFiles(fileList,tokenSource.Token),tokenSource.Token);
            MessageBox.Show(loaded.ToString());
        }

        private void stopBtn_click(object sender, EventArgs e)
        {
            tokenSource.Cancel();
        }
Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
Nahoru Odpovědět  +1 29. ledna 23:08
Why so serious? -Joker
Avatar
jt.e
Člen
Avatar
jt.e:

Sice zatím vůbec nechápu co to vlastně dělá, k věcem jako IEnumerable, CancellationToken, async a await jsem se ještě nedostal. Ale je to to co jsem potřeboval. Díky moc.

 
Nahoru Odpovědět 30. ledna 14:27
Avatar
Odpovídá na jt.e
Petr Čech (czubehead):

Aha :D na async a await se podívej, jsou to dost užitečné věci, hlavně pro formulářové aplikace. CancellationToken je zkrátka tkaový blackbox, může ti být celkem jedno, jak to funguje uvniř.
IEnumerable si můžeš představit jako list, ale je lepší dávat jako parametr IEnumerable místo Listu, protože potom tam můžeš dát prakticky jakoukoliv kolekci, třeba i pole a ne jen list. IEnumerable je také užitečný jako návratový typ, protože se dá potom použít yield- další užitečná věcička.

Nahoru Odpovědět 30. ledna 15:02
Why so serious? -Joker
Avatar
jt.e
Člen
Avatar
jt.e:

Teď jsem si ještě udělal takovou testovací aplikaci. Protože pořád tomu moc nerozumím, tak nevím, co mám špatně:

public partial class Form1 : Form
{
    private CancellationTokenSource tokenSource;

    public Form1()
    {
        InitializeComponent();
    }

    private bool? CheckFile(string filename, CancellationToken token)
    {
        try
        {
            //token.ThrowIfCancellationRequested(); - před fileexists to ingnoruje
            bool exists = File.Exists(filename);

            token.ThrowIfCancellationRequested();
            return exists;
        }
        catch (OperationCanceledException)
        {
            return null;
        }
    }

    private async void btStart_Click(object sender, EventArgs e)
    {
        tokenSource = new CancellationTokenSource();

        bool? result = await Task.Factory.StartNew(() => CheckFile(@"\\192.128.14.2\test.file", tokenSource.Token), tokenSource.Token);

        if (result == null) MessageBox.Show("Přerušeno uživatelem.");
        else
        {
            string msg = (result.Value) ? "Soubor existuje" : "Soubor nenalezen!";
            MessageBox.Show(msg);
        }
    }

    private void btCancel_Click(object sender, EventArgs e)
    {
        if(tokenSource!=null) tokenSource.Cancel();
    }
}

aplikaci lze sice bez problémů ukončit...
Jak bych to měl upravit, abych stiskem tlačítka ukončil metodu CheckFile? Teď se mi to chová tak, že se CheckFile vykonává do konce, ale pak vypíše přerušeno uživatelem.

 
Nahoru Odpovědět 30. ledna 18:14
Avatar
Odpovídá na jt.e
Petr Čech (czubehead):

To je přesně očekávané chování, předpokládal jsem kontrolování velkého množství malých souborů.

Nahoru Odpovědět 30. ledna 18:20
Why so serious? -Joker
Avatar
jt.e
Člen
Avatar
Odpovídá na Petr Čech (czubehead)
jt.e:

Ono právě nejdéle trvá ověření toho prvního souboru. Ty ostatní pokud jsou ve stejné složce, se ověří pak už rychle.

 
Nahoru Odpovědět 30. ledna 18:26
Avatar
Odpovídá na jt.e
Petr Čech (czubehead):

Obávám se, že to nejde File.Exists nejde přerušit v průběhu. Nešlo by to ani kdyby to bylo ve vlastním vlákně.
Nic ale nebrání tomu, abys dělal jakože to už nepracuje, protože ta úloha se stejně přeruší a vrátí null
asi takto:

private async void btStart_Click(object sender, EventArgs e)
{
    tokenSource = new CancellationTokenSource();

    bool? result = await Task.Factory.StartNew(() => CheckFile(@"\\192.128.14.2\test.file", tokenSource.Token), tokenSource.Token);

    if (result == null) return;//zrušeno
    //tady je už jisté, že operace nebyla zrušena

    string msg = (result.Value) ? "Soubor existuje" : "Soubor nenalezen!";
    MessageBox.Show(msg);
}

private void btCancel_Click(object sender, EventArgs e)
{
    tokenSource?.Cancel();
    MessageBox.Show("Přerušeno uživatelem.");
    //prezentační logika po zrušení
}

Zbytek kódu samozřejmě zůstane. Opravdu to nejde lépe, nebylo by to thread-safe. Nešlo by to myslím ani ukončením procesu.

Nahoru Odpovědět 30. ledna 18:32
Why so serious? -Joker
Avatar
Petr Čech (czubehead):

nebo nebudeš nic předstírat a přiznáš barvu: (asi čistější)

private CancellationTokenSource tokenSource;
private bool wasIoException=false;//došlo k vnitřní chybě?

private bool? CheckFile(List<string> filenames, CancellationToken token)//pokud je těch souborů víc,
//a chceš je kontrolovat najednou, mělo by to vypadat takto:
{
    wasIoException=false;
    try
    {
        foreach(var file in filenames)
        {
            token.ThrowIfCancellationRequested();//kontrolovat to až potom je úplně k ničemu
            if(!File.Exists(file))
                return false;
        }
        return true;
    }
    catch (OperationCanceledException)
    {
        return null;
    }
    catch(IOException)//nepřístupnost souboru
    {
        //tady nemůžeš k UI, musíš to ošetřit až dál
        wasIoException=true;//proto si to zapíšeš
        return null;
    }
}

private async void btStart_Click(object sender, EventArgs e)
{
    tokenSource = new CancellationTokenSource();

    bool? result = await Task.Factory.StartNew(() => CheckFile(@"\\192.128.14.2\test.file", tokenSource.Token), tokenSource.Token);

    if (result == null)
    {
        checking_canceled();
        return;//zrušeno
    }
    //tady je už jisté, že operace nebyla zrušena

    string msg = (result.Value) ? "Soubor existuje" : "Soubor nenalezen!";
    MessageBox.Show(msg);
}

private void btCancel_Click(object sender, EventArgs e)
{
    tokenSource?.Cancel();
    //ukážeš něco jako rušení operace
}

private void checking_canceled()
{
    //tady můžeš pracovat s UI
    //logika, kdy je to už opravdu přerušené
    //vypneš hlášku rušení operace
    if(wasIoException)
    {
        //nastala chyba při kontrolování, ale operace nebyla zrušena
    }
    else
    {
        //operace byla zrušena uživatelem
    }
}
Nahoru Odpovědět  +1 30. ledna 18:49
Why so serious? -Joker
Avatar
jt.e
Člen
Avatar
Odpovídá na Petr Čech (czubehead)
jt.e:

Vypadá to nádherně. Díky moc.

 
Nahoru Odpovědět 30. ledna 19:03
Avatar
Nahoru Odpovědět 30. ledna 19:30
Why so serious? -Joker
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 23 zpráv z 23.