Bonjour à tous,

Je découvre les threads et je rencontre un problème dans le développement de mes essais. En effet, j'ai crée une class qui lorsqu'on lui fourni une liste d'adresse url pointant vers des fichiers va télécharger ceux-ci et les enregistres après avoir vérifié que le fichier n’existe pas et qui, si il existe, index le nom du fichier. Ça marche pas trop mal mais certains fichiers pose problème à l'ouverture du stream créer par File.OpenWrite (ligne 81).

J'en déduit qu'il est utilisé par un autre thread. Je ne comprend pas pourquoi car lorsque je le crée, j'utilise un lock pour sécuriser la création du nom et du fichier. Comment puis-je corriger le problème?

Merci de votre aide et éclaircissement.

Ci-après le code simplifié

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
internal class CtrlrDownload
{
	private BackgroundWorker _bgWorker;
	private ParallelOptions po = new ParallelOptions();
	private CancellationTokenSource cts = new CancellationTokenSource();
	object padlock = new object();
	private int _nbATraiter = 0;
	private int _nbTraite = 0;
	private bool _isCanceled = false;
	string pathWhereSave;
	List<int> indexOk = new List<int>();
	private int err=0;
	ConcurrentDictionary<int, string> _errors = new ConcurrentDictionary<int, string>();
 
	public bool HasError {  get => _errors.Count > 0; }
 
 
	public void Run( Dictionary<int, Mark> lst, string folderPath )
	{
		if ( !Directory.Exists( folderPath ) )
			Directory.CreateDirectory( folderPath );
 
			pathWhereSave = folderPath;
 
		if ( lst.Count == 0 )
			return false;
 
		cts = new CancellationTokenSource();
		po = new ParallelOptions()
		{
			CancellationToken = cts.Token,
			MaxDegreeOfParallelism = 4
		};
 
		_bgWorker.RunWorkerAsync( lst );
	}
 
	private void BgWorker_DoWork( object sender, DoWorkEventArgs e )
	{
		Dictionary<int, Mark> lst = e.Argument as Dictionary<int, Mark>;
 
		try
		{
			Parallel.ForEach( lst, po,
				keyValuePair => DownloadUrl( keyValuePair.Key, keyValuePair.Value )
			);
		}
		catch ( OperationCanceledException ) //Cancel the parallel.foreach
		{ }
		catch ( Exception ex ) //other exception
		{}
	}
 
	private void DownloadUrl( int index, UrlBase common )
	{
		try
		{
			DownloadFile(common.Url, common.Url.Split('/').Last(), index);
        }
		catch (Exception ex)
		{
			MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error );
			_errors.TryAdd( index, ex.Message );
		}
 
		Interlocked.Increment(ref _nbTraite); //thread safe
	}
 
	public void DownloadFile( string url, string fileName, int index )
	{
		lock( padlock )
		{
			fileName = CreateFileName( pathWhereSave, fileName );
			File.Create( Path.Combine(Path.Combine( pathWhereSave, fileName ) );
		}
 
		HttpWebRequest request = (HttpWebRequest)WebRequest.Create( url );
		HttpWebResponse response = (HttpWebResponse)request.GetResponse();
		long fileSize = response.ContentLength;
 
		using ( Stream outputStream = File.OpenWrite( Path.Combine( pathWhereSave, fileName ) ) )
		//FIXME : System.IO.IOException*: 'Le processus ne peut pas accéder au fichier 'nomfichier', car il est en cours d'utilisation par un autre processus.' 
		using ( Stream inputStream = response.GetResponseStream() )
		{
			byte[] buffer = new byte[ 4096 ];
			int bytesRead, percentComplete;
			long totalBytesRead = 0;
			do
			{
				bytesRead = inputStream.Read( buffer, 0, buffer.Length );
				outputStream.Write( buffer, 0, bytesRead );
				totalBytesRead += bytesRead;
				percentComplete = (int)( totalBytesRead * 100 / fileSize );
			} while ( bytesRead != 0 );
		}
	}
 
	public static string CreateFileName( string folderPath, string fileName )
	{
		if ( File.Exists( Path.Combine( folderPath, fileName ) ) )
		{
			string extension = Path.GetExtension( fileName );
			string nameWithoutExtension = Path.GetFileNameWithoutExtension( fileName );
			int count = 1;
			while ( File.Exists( Path.Combine( folderPath, fileName ) ) )
			{
				fileName = nameWithoutExtension + "-" + count + extension;
				count++;
			}
		}
		return fileName;
	}
}