I've got a program that downloads a set of thumbnail images specified in a remote XML file. There can be up to 30 thumbnails downloaded. I'm using a foreach loop iterating through an XmlNodeList of all the <item> tags in the XML file and inside that foreach loop I start a new Thraed that runs the downloadThumb method. Here is my downloadThumb method: - public void downloadThumb(object Url)
-
{
-
string url = Url.ToString();
-
Uri parts = new Uri(url);
-
string query = parts.Query;
-
string filename = query.Replace("?ssid=", "");
-
if(!File.Exists("./thumbs/" + filename + "-Thumbnail.jpg"))
-
{
-
HttpWebRequest thumbreq = (HttpWebRequest)WebRequest.Create(url);
-
HttpWebResponse thumbres = (HttpWebResponse)thumbreq.GetResponse();
-
BinaryReader thumb = new BinaryReader(thumbres.GetResponseStream());
-
FileStream fstream = new FileStream("./thumbs/" + filename + "-Thumbnail.jpg", FileMode.Create, FileAccess.Write);
-
BinaryWriter file = new BinaryWriter(fstream);
-
byte[] thumbnail = thumb.ReadBytes((int)thumbres.ContentLength);
-
file.Write(thumbnail);
-
file.Close();
-
thumb.Close();
-
fstream.Close();
-
thumbres.Close();
-
}
-
}
Probably not the prettiest way, but it's the only way I could get it to write the thumbnail images properly to disk.
Anyway, I want the ./thumbs/ folder (with all the images inside) to be deleted when I close the program. I set up this in my .designer.cs file:
this.Closing += new System.ComponentModel.CancelEventHandler(this.Form _Closing);
And my Form_Closing method: - public void Form_Closing(object sender, CancelEventArgs cArgs)
-
{
-
dataGridView1.Dispose();
-
if (Directory.Exists("./thumbs"))
-
{
-
Directory.Delete("./thumbs", true);
-
}
-
}
dataGridView1 being the datagridview that I'm posting the information I'm parsing out of the XML file to. I figured that because I'm displaying the thumbnail I'm downloading inside a dataGridViewImageCell that disposing the dataGridView would sever the association with the files...that's not the case. I need to know how I can disassociate the process with those files so I can delete them automatically. Can I get some help?
27 10157
If you open an Image or Bitmap object from a file, it counts as the file being in use
Can we see the code that you use to open the thumbnails from the local harddrive?
I'm going to guess that you are using a loop that loads the thumbs into a list or array. - for (int Index =0; Index<30; Index++)
-
{
-
mythumbs[Index] = Image.FromFile(ThumbnailPathList[Index]);
-
}
Am I close?
Here is the entire process from parsing all the <item>'s out of the XML up to the end of the foreach loop, which includes loading the bitmap. - XmlNodeList items = xdoc.GetElementsByTagName("item");
-
overallProgress.Maximum = items.Count;
-
foreach (XmlElement item in items)
-
{
-
XmlNodeList child = item.ChildNodes;
-
string title = child[0].InnerText.ToString();
-
string date = child[2].InnerText.ToString();
-
string full = child[6].InnerText.ToString();
-
string thumb = child[8].InnerText.ToString();
-
string description = child[9].InnerText.ToString();
-
//ThreadPool.QueueUserWorkItem(downloadThumb, thumb);
-
Thread t = new Thread(downloadThumb);
-
t.Start(thumb);
-
t.Join();
-
downloadThumb(thumb);
-
Uri parts = new Uri(thumb);
-
string query = parts.Query;
-
string filename = query.Replace("?ssid=", "");
-
DataGridViewRow newRow = new DataGridViewRow();
-
newRow.Height = 90;
-
DataGridViewImageCell thumbCell = new DataGridViewImageCell();
-
DataGridViewCheckBoxCell downloadCell = new DataGridViewCheckBoxCell();
-
thumbCell.Value = new Bitmap("./thumbs/" + filename + "-Thumbnail.jpg");
-
downloadCell.Value = true;
-
newRow.Cells.Add(downloadCell);
-
newRow.Cells.Add(thumbCell);
-
dataGridView1.Rows.Add(newRow);
-
downloadCell.Selected = true;
-
overallProgress.PerformStep();
-
}
You can see I'm loading the bitmap like this:
thumbCell.Value = new Bitmap("./thumbs/" + filename + "-Thumbnail.jpg");
So disposing of the dataGridView should do the trick.
Out of curiosity, are you trying to access the file somewhere else in your program, or is the file access getting left open after you've closed it?
If you want to close the file handle, you can read the file into a memory stream, close the file, and load the image from the memory stream. Of course, this means you'll have all your images loaded into memory (can get big if your images are large), but you won't have the open file handle.
Also, just a heads up, if you close the memory stream on an animated bitmap you'll throw a GDI+ exception.
The images are all .jpg, and together all 30 add up to maybe 90 KB, so the size isn't an issue. So I would want to load the files into a memory stream inside the foreach loop then use that memory stream inside my new Bitmap() declaration instead of using the filename? How do I close the file once I've gotten it loaded into a memory stream? This might actually be the answer to my problem, I'm already downloading the file from the internet, maybe I'll just use the memory stream I get from the downloaded file as my new bitmap instead of writing it to a file...
Yup:
new Bitmap("./thumbs/" + filename + "-Thumbnail.jpg");
As long as that image object is alive, that file is in use.
For the purposes of this discussion, I'll submit some code I wrote a while back exploring exactly this issue. http://members.shaw.ca/gtexmo/Code/C...PictureViewer/
There's a switch statement in there with the code for how I'm loading the image. Basically, I open the file, read it into a byte array, then close the file. After that I read that memory stream into an image object and go from there. I do not close the memory stream so as to avoid the GDI+ exception.
Ok, I managed to make the downloadThumb method return a memorystream that I then use for my Bitmap() object. Here is my full code: - using System;
-
using System.IO;
-
using System.Net;
-
using System.Xml;
-
using System.Drawing;
-
using System.Windows.Forms;
-
-
namespace WindowsFormsApplication1
-
{
-
public partial class Form1 : Form
-
{
-
string screenshotXML;
-
-
public Form1()
-
{
-
InitializeComponent();
-
}
-
-
public MemoryStream downloadThumb(object Url)
-
{
-
MemoryStream thumbMem;
-
string url = Url.ToString();
-
Uri parts = new Uri(url);
-
string query = parts.Query;
-
HttpWebRequest thumbreq = (HttpWebRequest)WebRequest.Create(url);
-
HttpWebResponse thumbres = (HttpWebResponse)thumbreq.GetResponse();
-
BinaryReader thumb = new BinaryReader(thumbres.GetResponseStream());
-
byte[] thumbnail = thumb.ReadBytes((int)thumbres.ContentLength);
-
thumbMem = new MemoryStream(thumbnail);
-
thumb.Close();
-
thumbres.Close();
-
return thumbMem;
-
}
-
-
public void getXml(string gamertag)
-
{
-
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://www.bungie.net/stats/halo3/PlayerScreenshotsRss.ashx?gamertag=" + gamertag);
-
req.Method = "GET";
-
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
-
if (response.Headers["Content-Type"] == "text/html")
-
{
-
MessageBox.Show("This gamertag is not valid.");
-
gamertagBox.Focus();
-
gamertagBox.SelectAll();
-
}
-
else
-
{
-
dataGridView1.Rows.Clear();
-
StreamReader responseStream = new StreamReader(response.GetResponseStream());
-
screenshotXML = responseStream.ReadToEnd();
-
XmlDocument xdoc = new XmlDocument();
-
xdoc.LoadXml(screenshotXML);
-
XmlNodeList items = xdoc.GetElementsByTagName("item");
-
overallProgress.Maximum = items.Count;
-
foreach (XmlElement item in items)
-
{
-
XmlNodeList child = item.ChildNodes;
-
string title = child[0].InnerText.ToString();
-
string date = child[2].InnerText.ToString();
-
string full = child[6].InnerText.ToString();
-
string thumb = child[8].InnerText.ToString();
-
string description = child[9].InnerText.ToString();
-
DataGridViewRow newRow = new DataGridViewRow();
-
newRow.Height = 90;
-
DataGridViewImageCell thumbCell = new DataGridViewImageCell();
-
DataGridViewCheckBoxCell downloadCell = new DataGridViewCheckBoxCell();
-
Bitmap thumbImg = new Bitmap(downloadThumb(thumb));
-
thumbCell.Value = thumbImg;
-
downloadCell.Value = true;
-
newRow.Cells.Add(downloadCell);
-
newRow.Cells.Add(thumbCell);
-
dataGridView1.Rows.Add(newRow);
-
downloadCell.Selected = true;
-
overallProgress.PerformStep();
-
}
-
}
-
dataGridView1.ClearSelection();
-
response.Close();
-
}
-
-
private void getXML_Click(object sender, EventArgs e)
-
{
-
-
string gamertag = gamertagBox.Text;
-
if (gamertag != "")
-
{
-
getXml(gamertag);
-
}
-
else
-
{
-
MessageBox.Show("You must enter a gamertag.");
-
gamertagBox.Focus();
-
}
-
}
-
}
-
}
See how on line 67 I'm using the downloadThumb(thumb) method inside the new Bitmap(). There must be a better way to do this...this seems so bloated.
And another thing, I liked how when I was using threading to run the downloadThumb thread each time a row was added to the dataGridView it automatically showed up, instead of waiting until the foreach loop finishes THEN showing the completely updated dataGridView box. Is there any way to do what I want here, with the downloadThumb method returning a memorystream, while running downloadThumb inside a thread?
Use the .Clone() function on the image. -
Bitmap tempbm=new Bitmap("./thumbs/" + filename + "-Thumbnail.jpg");
-
thumbCell.Value=tempbm.Clone();
-
tempbm.Dispose();
-
No muss, no fuss
Is there a way to run the downloadThumb method via a thread? I've found that the amount of memory used by the program for actually downloading the thumbnail files to a folder is more than he amount that I use when I just use a MemoryStream, so I'd like to stick with that, but how can I do a cross-thread access to the memory stream variable?
Could you start a thread that will download an image, then use a callback to return the image object which will then be put into wherever you want it to go? I don't know much about threading since I haven't used it much, but I'm pretty sure you can create a thread to do the work of generating the image itself, and then set up a callback to do something with that image when the thread is done.
I worded my message wrong. I've already got a method that will download the file from the supplied URL to either a file or a MemoryStream, the issue I'm having is that you can't share data between threads (at least I don't know a way to do it) so I need to get the MemoryStream (which is actually my preferred method over downloading to a file) from the method in one thread back into the main thread. Can I do that?
Try to not pass the MemoryStream between threads. Instead have the downloading method raise an event when it is done, with the completed downloaded image as the argument of the event.
Have a method as the event handler for the "ImageDownloaded" event doing whatever you need it to do: SaveToHDD, ShowImage, AddToDataBase.
This should help separate the activities a little bit. Later when you find your next best way to download it isn't tightly integrated with the program flow; your new download method will still raise the event and the rest of the program will not know the difference.
In theory you could have several different methods that obtain an image in different ways yet all raise the same event: FTP, HTTP, FileCopy, FileSystemWatcher... anything that can recognize or obtain a new image can raise the event with the rest of the program being blissfully ignorant of the *how* and just worry about its own part after the fact.
I'm not sure I understand how to do this. I understand what you're saying, and what I need to do, I just don't know how. As much as I hate asking for help in this way, can you give me an example, in code, of what I should do.
In truth I've only been doing this for about 2 weeks total, so I'm still very new to C#.
Use the .Clone() function on the image. - Bitmap tempbm=new Bitmap("./thumbs/" + filename + "-Thumbnail.jpg");
-
thumbCell.Value=tempbm.Clone();
-
tempbm.Dispose();
No muss, no fuss
Did you give this a try? It definitely looks way slicker than what I have, so I tried implementing it... the file handle is still left open. There is a reason for this, it's intended behaviour by the Image class. The only way I've found to get around this is to load it into memory still...
Please let me know if this worked for you... if it did, I must be doing something wrong.
I didn't try it because I don't want to mess with files at all. Like I said, the program uses more memory when downloading the images to files than it does when I download it to a memorystream, so I'd rather use a memorystream.
I still need help with the example of tlhintoq's suggestion.
Oh sorry, I was talking to Platter in that particular message. I'm just wondering if he's doing something I'm not to make that work.
(Since there no longer seems to be the ability to quote messages)
Gary: You're saying your file handle is kept open? The .Clone() method should not transfer the open file handle to the new image. But I will double check. I know I was doing the .Clone() to get rid of open file handles, but maybe I did something else to make it work
(I noticed that about the quoting thing too.... what happened?)
Yea, I used the code you had and it left the handle open for me. I tried nulling the object as well as disposing it and still the same.
Yea, I see that it keeps it open. My situation was a little different (involved Icon files) and seemed to work for that.
I just created this and it seemed to work? -
private static Bitmap OpenBm(string location)
-
{
-
Bitmap a = (Bitmap)Bitmap.FromFile(location);
-
Bitmap b = new Bitmap(a.Width, a.Height, a.PixelFormat);
-
b.SetResolution(a.HorizontalResolution, a.VerticalResolution);
-
//copy any other PropertyItems you may want?
-
Graphics gb = Graphics.FromImage(b);
-
gb.DrawImage(a, 0, 0);
-
-
a.Dispose();
-
return b;
-
}
-
Hmmm ok. At that point I think one is as good as the other; the memory streams are working for me so I'll stick with that. Like I said before, I did some reading on the subject and Microsoft intends for this behaviour (though I feel like there should be an option built in).
(Since there no longer seems to be the ability to quote messages)
(I noticed that about the quoting thing too.... what happened?)
Select text
Copy
Hit the quote balloon button
Paste
*Optionally assign a name to the quote inside the tag
Yes yes I know I can type [ quote ] and such, but there used to be a nice reply button
I find it interesting that the quote link still exists in other forums such as the lounge: http://bytes.com/forums/lounge/87789...nties-new-tech
That indicates that it still exists but has been SET to not be on in the various development forums such as this one. That is truly odd.
I noticed a bit of a change in the appearance of the forums lately and I seem to recall it happened about then. I wonder if a setting got missed in the changeover?
Ah, here's the answer... it was intended. http://bytes.com/forums/feedback/878...-when-replying
But I guess they're looking at putting it back in (yay!).
I add my vote/voice to having it back on.
Or maybe on for users>newbie
Sign in to post your reply or Sign up for a free account.
Similar topics
by: Paul |
last post by:
Hi,
VB.NET is saying the file I am creating is in use by another process and
won't complete its task of moving the file to the specified destination
folder.
Here is my code (the main bit...
|
by: Tim |
last post by:
Hi
This is the problem: Read BLOB data from SQL Server. Create an image on the
HD and assign it to a picture box. Works fine the first time. This is a
usercontrol on a tab. When I close the tab...
|
by: Mike Dole |
last post by:
When I am updating a picturebox with an image (extracted) from an
access database I keep getting a "The process cannot access the file
"c:\foto1.jpg because it is being used by another process"...
|
by: Jurgen Oerlemans |
last post by:
Hello,
I perform several actions on a file:
* copy "xxx.txt" from directory 1 to "file.txt" directory 2
* process "file.txt" which is in directory 2
* delete the file in directory 1
.... and...
|
by: taylorcarr |
last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: Sonnysonu |
last post by:
This is the data of csv file
1 2 3
1 2 3
1 2 3
1 2 3
2 3
2 3
3
the lengths should be different i have to store the data by column-wise with in the specific length.
suppose the i have to...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
| |