Pildi kustutamine ilma faili lockimiseta

by melborp 2. september 2009 21:52

Eelmises postituses mainisin, et eile tegelesin programmiga, mis kustutaks kataloogist kõik pildid, mida ei ole võimalik avada. Miks? Ma nimelt taastasin terve hunniku faile (nende hulgas ka pilte) kettalt, kuhu oli värskelt installeeritud op. süsteem ja seda kasutama hakatud ning seejärel avastati, et failid k.a. pildid jäid kopeerimata ning olid nüüd kaotsi läinud. Kõik failid, millele ei oldud veel jõudnud kirjutada, oli võimalik taastada. Aga igaks juhuks proovisin taastada ka neid faile, millel oli taastamisprogrammil punane või orants ikoon ees (suure tõenäosusega ei õnnestu taastada). Seega taastati ka faile, mis tegelikult polnud avatavad. Veidi üle 12000 pildi taastati ja mitte ei tahtnud käsitsi läbi käia pilte ja kustutada ükshaaval need, mis pole avatavad.

Tagasi programmi juurde.

Alguses proovisin kasutada Image klassi, aga kahjuks lockib see failid mõneks ajaks. Seega on kustutamine keerukas (isegi pärast Dispose –i oli fail veel kinni ning kohene kustutamine polnud võimalik). Otsisin alternatiivi WPF –st. WPF –s on olemas niisugune klass nagu BitmapImage. Selleks peate refereerima:

  • WindowsBase.dll
  • PresentationCore.dll

Peale mõningast uurimist ja testimist jõudsin järgneva töötava lahenduseni:

   1: var files = Directory.GetFiles(@"E:\Data\BUps\Test\", "*.jpg");
   2:  
   3: foreach (var file in files)
   4: {
   5:     BitmapImage image = new BitmapImage();
   6:     try
   7:     {
   8:         image = new BitmapImage();
   9:         image.BeginInit();
  10:         image.StreamSource = new FileStream(file, FileMode.Open, FileAccess.Read);
  11:         image.CacheOption = BitmapCacheOption.None;
  12:         image.EndInit();
  13:         image.StreamSource.Dispose();
  14:     }
  15:     catch (FileFormatException exc)
  16:     {
  17:         image.StreamSource.Dispose();
  18:         File.Delete(file);
  19:     }
  20:     catch (NotSupportedException exc)
  21:     {
  22:         image.StreamSource.Dispose();
  23:         File.Delete(file);
  24:     }
  25: }

Kui fail polnud avatav, siis sain ma kahte tüüpi vigasid – faili formaat polnud toetatud või siis ei saadud aru, et tegu on pildi failiga üldse. Nendel puhkudel kustutasin.

Properteid muudan ma BeginInit ja EndInit vahel, kuna muul juhul nende muutmine ignoreeritakse. BitmapImage implementeerib niisugust liidest nagu ISupportInitialize.

Niimoodi õnnestus mul pilti laadida ilma, et fail oleks lukustatud. Ja peale Dispose –i sain seda edukalt teha.

Täiendus: Kui nüüd aus olla, eile öösel mul see Image klassiga ja Dispose –imisega ei toiminud. Fail oli lukus. Hetkel aga toimis. Seega kui Image ilusti Dispose –da, siis fail pole lukus ja kustutamine on võimalik koheselt.

Igatahes, huvitav oli kasutada WPF –i klassi ja väga lihtne kood tuli.

Image klassiga näeks lahendus välja järgmine:

   1: var files =
   2:         Directory.GetFiles(
   3:             @"E:\Data\BUps\Kristel\Test\",
   4:             "*.jpg"
   5:          );
   6:  
   7: foreach (var file in files)
   8: {
   9:     try
  10:     {
  11:         using (var image = Image.FromFile(file))
  12:         {
  13:             //Teen midagi pildiga
  14:         }
  15:     }
  16:     catch (Exception exc)
  17:     {
  18:         File.Delete(file);
  19:     }
  20: }

Ma tegin lisaks ka pisikese jõudlustesti Image klassi ja WPF klassi vahel.

Need koodid käies läbi 341 pilti kogusuurusega 80MB võttis:

  • Image klassi puhul aega: 12661 ms (12 sekundit)
  • WPF klassi puhul aega: 966 ms (alla sekundi)

Huvitav info. Edu.

Tags:

.Net | C# | Huvitav leid | WPF

Kommentaarid


 Lauri Lüüs 
september 3. 2009 21:04
Siin sa teed ju 2 täiesti erinevat asja, esimesel puhul loed faili streami ehk pildi faili ei loeta täies mahus ülesse, teisel puhul loed asja pildina mällu.


september 5. 2009 03:55
Sul on õigus, nad pole päris võrreldavad.
Image puhul sa pead alati faili laadima mällu - kas siis faili path -i järgi või enda FileStrem abil.
BitmapImage puhul on võimalik CacheOption abil määrata, kas pilt laetakse mällu ja millal. Antud juhul ma pilti mällu ei laegi.
Kui panna CacheOption -ile BitmapCacheOption.OnLoad väärtus None asemel, siis laetaks pilt mällu ja sellisel juhul võtab sama arvu piltide läbi käimine ja kustutamine 22 sekundit (peaaegu poole rohkem kui Image klassiga).
Samas antud kontekstis piisab mulle sellest, et BitmapImage valideerib ära pildi formaadi ja avatavuse (arvatavsti metadata järgi) ning tervet pilti mällu ei laeta, ja sel juhul on BitmapImage ikka megakiire võrreldes Image klassiga.

Lisa kommentaar




  Country flag

biuquote
  • Kommentaar
  • Preview
Loading



Autorist

Taavi Kõosaar

 Tere, olete sattunud mu blogi peale. Olen Taavi Kõosaar - tarkvara arendaja, arhitekt ja konsultant keskendudes arendamisele .NET -i platvormil. Hetkel asun peamiselt Rootsis, kus töötan Süsteemi Arhitektina toote/teenuse arendamisel, mida kasutatakse üle Euroopa. Lisaks tööle blogin, kirjutan artikleid, pean loenguid, treeninguid, reisin, loen raamatuid, sukeldun, teen sporti, fotografeerin, osalen Eesti arendajate kommuunis ...

Siit leiate minu mõtisklused ja seiklused tarkvara arendamisega, .NET -ga ja Team Systemiga.

Kalender

<<  september 2010  >>
estekonerela
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

Liikmelisus

www.eneta.ee

Team System MVP

Tutvu minu LinkedIn profiiliga

Minu Eneta profiil

Lugejatest

Kaart:

Lugejad:

Hetkel lehel:

hit counters

Külastajaid:

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

Siin toodud arvamuseid saab käsitleda vaid kui minu isiklike arvamusi, need ei kajast vähimalgi kombel ühegi minu tööandja arvamusi ja nägemusi.

© Copyright 2010 Melborp.NET