I have the following code (or the equivalent thereof):
var provider = new System.Net.Http.MultipartFormDataStreamProvider([...]);
try
{
if (provider.FileData.Count != 0)
{
foreach (System.Net.Http.MultipartFileData file in provider.FileData)
{
Trace.WriteLine(file.Headers.ContentDisposition.FileName);
Trace.WriteLine("Server file path: " + file.LocalFileName);
AddAttachment(file.LocalFileName, file.Headers.ContentDisposition.FileName.Replace("\"", ""));
if (attachmentPaths.Length != 0)
{
attachmentPaths += ";";
}
attachmentPaths += file.Headers.ContentDisposition.Name.Replace("\"", "");
}
}
}
catch (Exception ex)
{ ... }
...
public void AddAttachment(string attachmentFileName, string attachmentName)
{
var AttachmentList = new List<System.Net.Mail.Attachment>();
System.Net.Mail.Attachment newAttachment = new System.Net.Mail.Attachment(attachmentFileName);
newAttachment.Name = attachmentName;
AttachmentList.Add(newAttachment);
}
And I'm getting the "Process cannot access the file ... because it is being used by another process" error. I'd just like to know where my application could be getting the error. I can't tell where in here it is actually trying to access the file. My best guess is in the Attachment constructor, but I'm really not sure.
I was able to figure out a way to test it in a debugger. And the answer was yes, the System.Net.Mail.Attachment constructor is what was trying to access the file.
Related
I'm trying to extract an ISO to a folder with the same name without .iso on the end.
I'm having a problem with winrar as it will not start the extract when I start up with the seach starting in the folder with the ISO.
UPDATED with answer code
private void ExtractISO(string toExtract, string folderName)
{
// reads the ISO
CDReader Reader = new CDReader(File.Open(toExtract, FileMode.Open), true);
// passes the root directory the folder name and the folder to extract
ExtractDirectory(Reader.Root, folderName /*+ Path.GetFileNameWithoutExtension(toExtract)*/ + "\\", "");
// clears reader and frees memory
Reader.Dispose();
}
private void ExtractDirectory(DiscDirectoryInfo Dinfo, string RootPath, string PathinISO)
{
if (!string.IsNullOrWhiteSpace(PathinISO))
{
PathinISO += "\\" + Dinfo.Name;
}
RootPath += "\\" + Dinfo.Name;
AppendDirectory(RootPath);
foreach (DiscDirectoryInfo dinfo in Dinfo.GetDirectories())
{
ExtractDirectory(dinfo, RootPath, PathinISO);
}
foreach (DiscFileInfo finfo in Dinfo.GetFiles())
{
using (Stream FileStr = finfo.OpenRead())
{
using (FileStream Fs = File.Create(RootPath + "\\" + finfo.Name)) // Here you can Set the BufferSize Also e.g. File.Create(RootPath + "\\" + finfo.Name, 4 * 1024)
{
FileStr.CopyTo(Fs, 4 * 1024); // Buffer Size is 4 * 1024 but you can modify it in your code as per your need
}
}
}
}
static void AppendDirectory(string path)
{
try
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
catch (DirectoryNotFoundException Ex)
{
AppendDirectory(Path.GetDirectoryName(path));
}
catch (PathTooLongException Ex)
{
AppendDirectory(Path.GetDirectoryName(path));
}
}
The user selects the folder to extract (.ISO) toExtract. I then use it in the Process.Start() in the background worker. That just seems to open the mounting software and doesn't extract the ISO to the desired folder name.
Thanks in advance for your help.
Or if anyone could give me a batch to extract the ISO instead and to call it from c# passing toExtract and the folder name that would be helpful too.
Thanks
If external Class Libraries are OK!
Then use SevenZipSharp or .NET DiscUtils to extract ISO's...
These two ClassLibraries can manage ISO and Extract them!
For DiscUtils you can find some codes for ISO Management [CDReader Class] at the Link I provided.
But For SevenZipSharp, Please Explore the ClassLibrary source and find the Code to Extract or Google to find it!
To get the Name of the folder just use Path.GetFileNameWithoutExtension((string)ISOFileName) which will return "ISOFile" for an iso named "ISOFile.iso". And then you can use it with your desired path.
UPDATE
Code To Extract ISO Image with DiscUtils :
using DiscUtils;
using DiscUtils.Iso9660;
void ExtractISO(string ISOName, string ExtractionPath)
{
using (FileStream ISOStream = File.Open(ISOName, FileMode.Open))
{
CDReader Reader = new CDReader(ISOStream, true, true);
ExtractDirectory(Reader.Root, ExtractionPath + Path.GetFileNameWithoutExtension(ISOName) + "\\", "");
Reader.Dispose();
}
}
void ExtractDirectory(DiscDirectoryInfo Dinfo, string RootPath, string PathinISO)
{
if (!string.IsNullOrWhiteSpace(PathinISO))
{
PathinISO += "\\" + Dinfo.Name;
}
RootPath += "\\" + Dinfo.Name;
AppendDirectory(RootPath);
foreach (DiscDirectoryInfo dinfo in Dinfo.GetDirectories())
{
ExtractDirectory(dinfo, RootPath, PathinISO);
}
foreach (DiscFileInfo finfo in Dinfo.GetFiles())
{
using (Stream FileStr = finfo.OpenRead())
{
using (FileStream Fs = File.Create(RootPath + "\\" + finfo.Name)) // Here you can Set the BufferSize Also e.g. File.Create(RootPath + "\\" + finfo.Name, 4 * 1024)
{
FileStr.CopyTo(Fs, 4 * 1024); // Buffer Size is 4 * 1024 but you can modify it in your code as per your need
}
}
}
}
static void AppendDirectory(string path)
{
try
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
catch (DirectoryNotFoundException Ex)
{
AppendDirectory(Path.GetDirectoryName(path));
}
catch (PathTooLongException Exx)
{
AppendDirectory(Path.GetDirectoryName(path));
}
}
Use It with Like This :
ExtractISO(ISOFileName, Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\");
Working! Tested By Me!
And Of Course You can always add more Optimization to the code...
This Code is Just a Basic One!
For UDF or for making Windows ISO Files after servicing(DISM) with out needs the above accepted answer is not working for me so i tried this working method with DiscUtils
using DiscUtils;
public static void ReadIsoFile(string sIsoFile, string sDestinationRootPath)
{
Stream streamIsoFile = null;
try
{
streamIsoFile = new FileStream(sIsoFile, FileMode.Open);
DiscUtils.FileSystemInfo[] fsia = FileSystemManager.DetectDefaultFileSystems(streamIsoFile);
if (fsia.Length < 1)
{
MessageBox.Show("No valid disc file system detected.");
}
else
{
DiscFileSystem dfs = fsia[0].Open(streamIsoFile);
ReadIsoFolder(dfs, #"", sDestinationRootPath);
return;
}
}
finally
{
if (streamIsoFile != null)
{
streamIsoFile.Close();
}
}
}
public static void ReadIsoFolder(DiscFileSystem cdReader, string sIsoPath, string sDestinationRootPath)
{
try
{
string[] saFiles = cdReader.GetFiles(sIsoPath);
foreach (string sFile in saFiles)
{
DiscFileInfo dfiIso = cdReader.GetFileInfo(sFile);
string sDestinationPath = Path.Combine(sDestinationRootPath, dfiIso.DirectoryName.Substring(0, dfiIso.DirectoryName.Length - 1));
if (!Directory.Exists(sDestinationPath))
{
Directory.CreateDirectory(sDestinationPath);
}
string sDestinationFile = Path.Combine(sDestinationPath, dfiIso.Name);
SparseStream streamIsoFile = cdReader.OpenFile(sFile, FileMode.Open);
FileStream fsDest = new FileStream(sDestinationFile, FileMode.Create);
byte[] baData = new byte[0x4000];
while (true)
{
int nReadCount = streamIsoFile.Read(baData, 0, baData.Length);
if (nReadCount < 1)
{
break;
}
else
{
fsDest.Write(baData, 0, nReadCount);
}
}
streamIsoFile.Close();
fsDest.Close();
}
string[] saDirectories = cdReader.GetDirectories(sIsoPath);
foreach (string sDirectory in saDirectories)
{
ReadIsoFolder(cdReader, sDirectory, sDestinationRootPath);
}
return;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
it has extracted from a application source ISOReader but modified for my requirements
total source is available at http://www.java2s.com/Open-Source/CSharp_Free_CodeDownload/i/isoreader.zip
Try this:
string Desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
Process.Start("Winrar.exe", string.Format("x {0} {1}",
Desktop + "\\test.rar",
Desktop + "\\SomeFolder"));
That would extract the file test.rar to the folder SomeFolder. You can change the .rar extention to .iso, it'll work the same.
As far as I can see in your current code, there is no command given to extract a file, and no path to the file that has to be extracted. Try this example and let me know if it works =]
P.S. If you'd like to hide the extracting screen, you can set the YourProcessInfo.WindowStyle to ProcessWindowStyle.Hidden.
I hace confrunted recently with this kind of .iso extraction issue. After trying several methods, 7zip did the job for me, you just have to make sure that the latest version of 7zip is installed on your system. Maybe it will help
try
{
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = false;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
cmd.Start();
cmd.StandardInput.WriteLine("C:");
//Console.WriteLine(cmd.StandardOutput.Read());
cmd.StandardInput.Flush();
cmd.StandardInput.WriteLine("cd C:\\\"Program Files\"\\7-Zip\\");
//Console.WriteLine(cmd.StandardOutput.ReadToEnd());
cmd.StandardInput.Flush();
cmd.StandardInput.WriteLine(string.Format("7z x -y -o{0} {1}", source, copyISOLocation.TempIsoPath));
//Console.WriteLine(cmd.StandardOutput.ReadToEnd());
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();
Console.WriteLine(cmd.StandardOutput.ReadToEnd());
}
catch (Exception e)
{
Console.WriteLine(e.Message + "\n" + e.StackTrace);
if (e.InnerException != null)
{
Console.WriteLine(e.InnerException.Message + "\n" + e.InnerException.StackTrace);
}
}
I'm working on an app that uses Bing's API to search and download images.
Bing's API provides a set of image links and I iterate over them and download each one.
The problem that I'm having is that sometimes the downloaded file size is 0Kb.
I assume that happens because WebClient first creates the filename and then tries to write to it. So when it can't write to it for some reason this happens. The problem is that it happens without throwing an exception so my 'Catch' statement can't catch this and delete the file.
public void imageFetcher(string performerName, int maxNumberOfImages, RichTextBox richTextBox)
{
string performersDirPath = Environment.CurrentDirectory + #"\Performers\";
string performerPath = performersDirPath + performerName + #"\";
if (!Directory.Exists(performersDirPath))
{
Directory.CreateDirectory(performersDirPath);
}
if (!Directory.Exists(performerPath))
{
Directory.CreateDirectory(performerPath);
}
// Searching for Images using bing api
IEnumerable<Bing.ImageResult> bingSearch = bingImageSearch(performerName);
int i = 0;
foreach (var result in bingSearch)
{
downloadImage(result.MediaUrl, performerPath + performerName + i + ".jpg",richTextBox);
i++;
if (i == maxNumberOfImages)
{
break;
}
}
}
The download method:
public void downloadImage(string imgUrl, string saveDestination, RichTextBox richTextBox)
{
if (File.Exists(saveDestination))
{
richTextBox.ForeColor = System.Drawing.Color.Red;
richTextBox.AppendText("The File: " + saveDestination + "Already exists");
}
else
{
try
{
using (WebClient client = new WebClient())
{
client.DownloadFileCompleted += new AsyncCompletedEventHandler(((sender, e) => downloadFinished(sender, e, saveDestination , richTextBox)));
Uri imgURI = new Uri(imgUrl, UriKind.Absolute);
client.DownloadFileAsync(imgURI, saveDestination);
}
}
catch (Exception e)
{
richTextBox.AppendText("There was an exception downloading the file" + imgUrl);
richTextBox.AppendText("Deleteing" + saveDestination);
File.Delete(saveDestination);
richTextBox.AppendText("File deleted!");
}
}
}
This happens also when I try to wait for the client to finish using:
client.DownloadFileAsync(imgURI, saveDestination);
while (client.IsBusy)
{
}
Can anyone please tell me what I'm doing wrong?
In other simular question the solution was to keep the Webclient instance open until download is finished.. I'm doing this with this loop:
while (client.IsBusy){}
Yet the results are the same.
Update:
I resorted to not use webclient, instead I used this code:
try
{
byte[] lnBuffer;
byte[] lnFile;
using (BinaryReader lxBR = new BinaryReader(stream))
{
using (MemoryStream lxMS = new MemoryStream())
{
lnBuffer = lxBR.ReadBytes(1024);
while (lnBuffer.Length > 0)
{
lxMS.Write(lnBuffer, 0, lnBuffer.Length);
lnBuffer = lxBR.ReadBytes(1024);
}
lnFile = new byte[(int)lxMS.Length];
lxMS.Position = 0;
lxMS.Read(lnFile, 0, lnFile.Length);
}
using (System.IO.FileStream lxFS = new FileStream(saveDestination, FileMode.Create))
{
lxFS.Write(lnFile, 0, lnFile.Length);
}
This solves the problem almost complelty, there are still one or two 0KB files but I assume it's because of network errors.
To see possible exceptions - try changing DownloadFileAsync to just DownloadFile - my problem was "Can not create SSL/TLS secure channel". Hope this will help someone.
The process cannot access the file because it is being used by another process
private void DeleteReport()
{
int invid = Convert.ToInt32(Session["InvId"]);
string FileName = invid + "_Report" + ".pdf";
string path1 = Server.MapPath("~/Report/" + FileName);
if (File.Exists(path1))
{
File.Delete(path1);
}
}
The error tells you, that the file is used and can't be deleted. So nothing wrong. As you did not formulate a
real question, lets try to help you in following way.
I guess that only your program is using the report, so good possible, you block the report
somewhere else.
E.g., the following code
string path = "C:\\Temp\\test.txt";
FileStream file = File.Open(path, FileMode.OpenOrCreate);
if (File.Exists(path))
File.Delete(path);
raises the same error. It does not necessarily mean that the process is another process.
What you can do is for example, for testing purpose, install SysInternal
http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx and add following code around your
File.Delete statement. Then you will see, what process uses the file:
try
{
File.Delete(path);
}
catch (Exception)
{
using (Process tool = new Process())
{
tool.StartInfo.FileName = #"C:\Program Files (x86)\SysinternalsSuite\handle.exe"; //Your path
tool.StartInfo.Arguments = path + " /accepteula";
tool.StartInfo.UseShellExecute = false;
tool.StartInfo.RedirectStandardOutput = true;
tool.Start();
tool.WaitForExit();
string outputTool = tool.StandardOutput.ReadToEnd();
string matchPattern = #"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
foreach (Match match in Regex.Matches(outputTool, matchPattern))
{
Process p = Process.GetProcessById(int.Parse(match.Value));
MessageBox.Show(p.ProcessName); // OR LOG IT
}
}
throw;
}
Credit for handle.exe call to https://stackoverflow.com/a/1263609/2707156
I'm using the following code to download a file and verify if the download succeeded:
try
{
UpdateAvailable = false;
Downloading = true;
using (var webclient = new WebClient { CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore) })
{
var file = Path.Combine(basePath, filename);
await webclient.DownloadFileTaskAsync(updaterexe_fileurl, Path.Combine(basePath, updaterexe_filename));
await webclient.DownloadFileTaskAsync(updatefileurl, file);
}
if (!File.Exists(filename))
{
Error = "Error downloading update. Please try again.";
Log.Error("Error downloading update. Please try again (file does not exist).");
}
else
{
DownloadReady = true;
}
}
catch (Exception ex)
{
Log.Error("Error downloading update: " + ex);
Error = ex.Message;
}
finally
{
Downloading = false;
}
This works in most cases. But I got multiple reports from end-users that sometimes they get the 'try again' error message.
How is this even possible? Clearly, WebClient didn't throw an exception, but it also failed to download the file (it did not exist on disk).
Is this a caching issue? Am I missing any other error handling?
If it's a disk caching issue, I thought about adding the following:
int count = 0;
while (count < 3 || !File.Exists(filename))
{
Thread.Sleep(1000);
count++;
}
But this feels very hacky.
Any ideas?
You download to file, which is Path.Combine(basePath, filename) but you never check to see whether file exists, you check to see whether filename exists.
If basePath and the current working directory differ, the file "won't exist".
Solved
I figured out that the GetNewFolderNameBasedOnDate method internally didn't close the file. I have that method fixed and it working normal now
I am trying to move selected files from one folder to another using BackgroundWorker process in C#. Here is my DoWork() method that determine whether to move the files or just copy. My File.Move() throws an exception that "The process cannot access the file because it is being used by another process". I tried different methods as mentioned in the threads here in stackoverflow.
private void FileProcessor_DoWork(object sender, DoWorkEventArgs e)
{
// Copy files
long bytes = 0;
string destSubFolder = String.Empty;
string destFile = string.Empty;
foreach (FileInfo file in oSettings.SourceFiles)
{
try
{
this.BeginInvoke(OnChange, new object[] { new UIProgress(file.Name, bytes, oSettings.MaxBytes) });
destSubFolder = GetNewFolderNameBasedOnDate(file);
//Create a new subfolder under the current active folder
string newPath = Path.Combine(oSettings.TargetFolder, destSubFolder);
// Create a new target folder, if necessary.
if (!System.IO.Directory.Exists(newPath))
{
System.IO.Directory.CreateDirectory(newPath);
}
destFile = Path.Combine(oSettings.TargetFolder, destSubFolder, file.Name);
if (chkDeleteSourceFiles.Checked)
{
FileInfo f = new FileInfo(file.FullName);
if (f.Exists)
{
File.Move(file.FullName, destFile);
}
}
else
{
File.Copy(file.FullName, destFile, true);
}
//Thread.Sleep(2000);
}
catch (Exception ex)
{
UIError err = new UIError(ex, file.FullName);
this.Invoke(OnError, new object[] { err });
if (err.result == DialogResult.Cancel) break;
}
bytes += file.Length;
}
}
I tried to delete the files in "RunWorkerCompleted" method too. But didn't resolve the problem. This fails when it tries to delete the last file in the list.
private void FileProcessor_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Operation completed, update UI
ChangeUI(false);
foreach (FileInfo file in oSettings.SourceFiles)
{
File.Delete(file.FullName);
}
}
GetNewFolderNameBasedOnDate() calls GetDateTaken() which was the culprit. Earlier I didn't use FileStream object but used Image myImage = Image.FromFile(filename); I didn't know that Image.FromFile locks the file.
private DateTime GetDateTaken(string fileName)
{
try
{
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
Image myImage = Image.FromStream(fs);
PropertyItem propItem = myImage.GetPropertyItem(36867);
DateTime dtaken;
//Convert date taken metadata to a DateTime object
string sdate = Encoding.UTF8.GetString(propItem.Value).Trim();
string secondhalf = sdate.Substring(sdate.IndexOf(" "), (sdate.Length - sdate.IndexOf(" ")));
string firsthalf = sdate.Substring(0, 10);
firsthalf = firsthalf.Replace(":", "-");
sdate = firsthalf + secondhalf;
dtaken = DateTime.Parse(sdate);
return dtaken;
}
}
catch (Exception ex)
{
return DateTime.Now;
}
}
Instead of creating new FileInfo objects, keep it simple and re-use the same one. I suspect the problem is that you have multiple references to the same file in your code, which prevents it from being removed. Try something like this to move it:
if (chkDeleteSourceFiles.Checked)
{
if (file.Exists)
{
file.MoveTo(destFile);
}
}
My guess is that it is the BeginInvoke call to OnChange and the new UIProgress() object that is holding onto the file. Does UIProgress open the file? You could try just using Invoke() and see if that helps.