I'm making a WPF C# Application and I need to copy a file. As the title says whenever I select any file it says its open in another process, so I'm guessing its something to do with my code.
I've attempted to rewrite the File.Copy code to be able to be able to track the progress of the copying.
My file copying code
public static void CopyFile(string file, string destination, ProgressBar progressCallback)
{
try
{
if (!Directory.Exists(destination)) Directory.CreateDirectory(destination);
} catch (IOException e)
{
MessageBox.Show("There was an error while creating the resource packs directory " + e.Message, "Canno't create directory", MessageBoxButton.OK);
return;
}
int halfAMeg = (int)(1024 * 1024 * 0.4);
FileStream strIn = null;
FileStream strOut = null;
try
{
strIn = new FileStream(file, FileMode.Open);
strOut = new FileStream(Path.Combine(destination, file), FileMode.Create);
}
catch (IOException e)
{
MessageBox.Show("There was an error while copying the file: " + e.Message, "Canno't copy file", MessageBoxButton.OK);
return;
}
byte[] buf = new byte[halfAMeg];
while (strIn.Position < strIn.Length)
{
int len = strIn.Read(buf, 0, buf.Length);
strOut.Write(buf, 0, len);
progressCallback.Maximum = Int32.MaxValue;
progressCallback.Value = (int)(Int32.MaxValue / (strIn.Position / strIn.Length));
}
strIn.Close();
strOut.Close();
}
Any help would be greatly appreciated.
EDIT 10/22: This question was made years ago when I greatly underestimated my C++ ability. I apologise for the poor code and poorly written question!
Related
I have to do transfer files from one host to other so i have decided to go with zip (IONIC) but problem with that is it eat's lot of memory when it comes for larger file, so i have decided to go with 7Z dll. i had tried to achieve compress & Uncompress which works perfectly fine on my console after changing some settings (unchecked prefer-32 bit from https://blog.jongallant.com/2011/10/7-zip-dll-file-does-not-exist/).
but which fails on ASP.net application and i am getting "Can not load 7-zip library or internal COM error! Message: failed to load library." when i try to compress or uncompress.
the code what i have tried.
protected void btnCompress_Click(object sender, EventArgs e)
{
var dllPath = "";
if (Environment.Is64BitOperatingSystem)
{
dllPath = HttpContext.Current.Server.MapPath(#"7z\7z64.dll");
}
else
dllPath = HttpContext.Current.Server.MapPath(#"7z\7z.dll");
var tmpPath = System.IO.Path.Combine(txtTempPath.Text, txtDir.Text);
try
{
SevenZip.SevenZipCompressor.SetLibraryPath(dllPath);
SevenZipCompressor sz = new SevenZipCompressor();
sz.CompressionLevel = CompressionLevel.Ultra;
sz.CompressionMode = CompressionMode.Create;
sz.CompressionMethod = CompressionMethod.Default;
sz.FastCompression = true;
sz.CompressDirectory(tmpPath, tmpPath + "_7Zip.7z");
//Directory.Delete(backupFolder, true);
Response.Write("<script>alert('Compressed successfully');</script>");
}
catch (Exception ex)
{
Response.Write("<script>alert('" + ex.Message + "');</script>");
//throw ex;
}
}
protected void btnExtract_Click(object sender, EventArgs e)
{
try
{
var tmpPath = System.IO.Path.Combine(txtTempPath.Text, txt7z.Text);
SevenZipExtractor.SetLibraryPath(#"C:\Program Files\7-Zip\7z.dll");
SevenZipExtractor zip = new SevenZipExtractor(tmpPath);
zip.ExtractArchive(System.IO.Path.GetFileNameWithoutExtension(tmpPath));
Response.Write("<script>alert('Extracted successfully');</script>");
}
catch (Exception ex)
{
Response.Write("<script>alert('" + ex.Message + "');</script>");
}
}
please someone suggest a proper solution for this,
Thanks in Advance.
I think using (Environment.Is64BitProcess) instead of Environment.Is64BitOperatingSystem) will work if you have set correct dll path.Make sure that dll exists in that path.
I have json file that I want to share between two processess. So I created a memory mapped file as follows.
private void CreateMemoryMappedFile()
{
var info = Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "/" + model.Data.Settings.OrcaUISpecificSettings.TimeOutFolder);
string path = Path.Combine(info.FullName + #"\" + model.Data.Settings.OrcaUISpecificSettings.File);
FullPath = path;
try
{
mmf = MemoryMappedFile.CreateFromFile(path, FileMode.CreateNew, "MyMemoryFile", 1024 * 1024);
}
catch (Exception ex)
{
}
}
public MemoryMappedViewStream GetAccessor()
{
MemoryMappedViewStream FileMapView = null;
if (FileMapView != null)
{
return FileMapView;
}
FileMapView = mmf.CreateViewStream();
return FileMapView;
}
And to read and write to the files I am doing the following
public void WriteToMemoryMappedFile(string Data)
{
try
{
mutex.WaitOne();
byte[] bytes = Encoding.ASCII.GetBytes(Data);
var accessor = GetAccessor();
accessor.Write(bytes, 0, Data.Length);
mutex.ReleaseMutex();
}
catch (Exception ex)
{
}
}
public string ReadFromMemoryMappedFile()
{
mutex.WaitOne();
var accessor = GetAccessor();
using (BinaryReader binReader = new BinaryReader(accessor))
{
byte[] reader = binReader.ReadBytes((int)accessor.Length);
string result = Encoding.Default.GetString(reader);
mutex.ReleaseMutex();
return result.Replace("NULL", "");
}
}
My problem is I have an Activity Monitor for my app. So after x amount of time I am updating the json file with InActiveStatus. Along the same lines I am listening to any file changes(Look at D_IDle event). Problem is If a normal file is changed I get the FileSytemWatcher changed event firing just fine. But when I use a Memory Mapped File to update the status, the FileSystemWatcher changed event never gets fired please help.
private void D_IsIdle(object sender, EventArgs e)
{
MonitorDirectory();
//AppViewModel.SerializeData("InActive");
AppViewModel.SerializeDataToMemoryMap("InActive");
d.IsIdle -= D_IsIdle;
}
public void MonitorDirectory()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(AppViewModel.GetDriectory());
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Filter = "*.json";
fileSystemWatcher.Changed += FileSystemWatcher_Changed;
fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
//IT NEVER COMES HERE
}
Using FileSystemWatcher with memory mapped files must be some kind of anti-pattern:). If you are on a local system, use one of the process synchronization primitives (e.g. semaphores) to signal change.
My guess is that the FileSystemWatcher triggers when the file handle is closed to avoid other processed reading partially written files.
The code that I have included below successfully writes to a CSV file. But if the CSV file that I am writing to happens to be open in Excel, I get a System.IO.Exception that indicates that "the file is being used by another process."
How can I change my code so that the program will continuing running and wait until the CSV is no longer open in Excel?
private void timer1_Tick(object sender, EventArgs e)
{
int actmonth, actyear, actsecond;
System.DateTime fecha = System.DateTime.Now;
actmonth = fecha.Month;
actyear = fecha.Year;
if (actmonth <= 9)
{
valorfechaact = System.Convert.ToString(actyear) + "00" + System.Convert.ToString(actmonth);
}
else
{
valorfechaact = System.Convert.ToString(actyear) + "0" + System.Convert.ToString(actmonth);
}
actsecond = fecha.Second;
string label;
label = label1.Text;
string at = "#";
string filename = valorfechaact + ".csv";
string ruta3 = System.IO.Path.Combine(at, label, filename);
if (Directory.Exists(label1.Text))
{
StreamWriter wr = new StreamWriter(ruta3, true);
wr.WriteLine("1asd" + actsecond);
wr.Close();
wr.Dispose();
}
else
{
System.Console.WriteLine("no se puede escribir en el archivo");
timer1.Stop();
}
}
You can write a Methode which try to open the File with a FileStream and return a boolean Flag
A possible Solution is
public static class FileInfoExtension
{
public static bool IsLocked(this FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException)
{
return true;
}
finally
{
stream?.Close();
}
return false;
}
}
Then you can use it
var fileInfo = new FileInfo(ruta3);
if (!fileInfo.IsLocked())
{
// do code
}
A very simple (and bad) Solution to wait is
while (file.IsLocked())
{
Thread.Sleep(100);
}
General is your Code unclear and difficult to read.
You have much redudant code and few variable are bad named.
Maybe this Guidline can help you https://github.com/dennisdoomen/CSharpGuidelines
Maybe a little bit clearer solution is
private void timer1_Tick(object sender, EventArgs e)
{
var directory = label1.Text;
if (!Directory.Exists(directory))
{
Console.WriteLine("no se puede escribir en el archivo");
timer1.Stop();
return;
}
var now = DateTime.Now;
_valorfechaact = now.Month <= 9 ? $"{now.Year}00{now.Month}" : $"{now.Year}0{now.Month}";
var fullname = Path.Combine("#", directory, $"{_valorfechaact}.csv");
var fileInfo = new FileInfo(fullname);
if (fileInfo.IsLocked())
{
Console.WriteLine($"The File {fullname} is locked!");
return;
}
using (var wr = new StreamWriter(fullname, true))
{
wr.WriteLine("1asd" + now.Second);
}
}
You could take a look at this question:
Checking if an Excel Workbook is open
One of the approaches that are discussed is to simply attempt to access the file. If that throws an exception, you can wait and try again.
If you really want to wait until the workbook is writable you can do that, e.g. by using a while loop (probably you'll want to add a time out, or if relevant alert the user that he/she needs to close the file in Excel).
In code it could be something like:
int someLargeNumberOfIterations = 100000000;
while(FileIsLocked(filepath) && elapsedMs < timeoutMs) {
Thread.SpinWait(someLargeNumberOfIterations);
// Set elapsed
}
// Write the file
where FileIsLocked is a function you write based on the aforementioned post and timeoutMs is some appropriate timeout.
I had developed a filewatcher program to monitor a folder, if there are any changed of the file, it will copy the file to another folder.
But I found that there will be error message when writing the original file (e.g. file being prcoess by another application...) it seems that the file locked when running [System.IO.File.Copy] copying to another folder.
Is there any solution can avoid the original file locked by the filewatcher/System.IO.File.Copy? Thanks.
The following is my code:
private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e)
{
DateTime lastWriteTime = File.GetLastWriteTime(e.FullPath);
if (lastWriteTime != lastRead)
{
txtLog.Text += e.ChangeType + ": " + e.FullPath + "\r\n";
txtLog.Focus();
txtLog.Select(txtLog.TextLength, 0);
txtLog.ScrollToCaret();
try
{
string myPath = e.FullPath;
string myFile = e.Name;
System.IO.FileInfo myFileInfo = new System.IO.FileInfo(myFile);
string myAttibs = myFileInfo.Attributes.ToString();
System.IO.File.Copy(myPath, #"D:\\Folder\\Output\\" + myFile, true);
lastRead = lastWriteTime;
}
catch (System.IO.IOException ex)
{
System.IO.IOException myex = ex;
}
catch (System.Exception ex)
{
System.Exception myex = ex;
}
}
}
I ran into the same problem. I am not fond of my solution, as it feels hackish. But it works:
FileSystemWatcher fsWatcher = new FileSystemWatcher();
fsWatcher.Created += new FileSystemEventHandler( fsWatcher_Created );
private void fsWatcher_Created( object sender, FileSystemEventArgs e )
{
RaiseFileFoundEvent( e.FullPath );
while ( !TestOpen( e.FullPath ) ) ;
RaiseFileCopyDoneEvent( e.FullPath );
}
private bool TestOpen( string filename )
{
try
{
FileStream fs = new FileStream( filename, FileMode.Open,
FileAccess.Write, FileShare.None );
fs.Close();
return true;
}
catch ( Exception )
{
return false;
}
}
private void RaiseFileFoundEvent( string fullPath )
{
// a file is found, but the copy is not guaranteed to be finished yet.
}
private void RaiseFileCopyDoneEvent( string fullPath )
{
// the file is found, and we know the copy is done.
}
There's not a good way to solve this problem. How should the program behave if you're in the middle of copying the file to a new location when another application wants to write to it?
If you're willing to copy a corrupted file (that was written-to while you were copying), you'll have to write your own Copy method that uses FileShare.ReadWrite.
The following are my codes but it cant handle more than 500 lines at one time.
It needs to add a , to the end of the line and at the same time detect. What i'm currently doing is separating them into 2 different textbox then save the one which i need by copy pasting but the app seems to hang if the file is too big.
Can someone help me with making it more efficient. Would really appreciate it.
private void button1_Click_1(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.Cancel)
return;
System.IO.StreamReader Reader = new System.IO.StreamReader(openFileDialog1.FileName);
//Create a filestream
FileStream fStr;
try
{
//Set filestream to the result of the pick of the user
fStr = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);
//Create a streamreader, sr, to read the file
StreamReader sr = new StreamReader(fStr);
//While the end of the file has not been reached...
while (sr.Peek() >= 0)
{
//Create a 'line' that contains the current line of the textfile
string line = sr.ReadLine().ToLower();
if (line.Contains("staff"))
{
line += ","; //Add a , to the end of the line**Important**
textBox1.Text += line + Environment.NewLine;
releventcount += 1;
}
else
{
line += ","; //Add a , to the end of the line**Important**
textBox2.Text += line + Environment.NewLine;
irreleventcount += 1;
}
label1.Text = "Relevent: ";
label2.Text = "Irrelevant: ";
}
//Close the file so other modules can access it
sr.Close();
//If something goes wrong, tell the user
}
catch (Exception)
{
MessageBox.Show("Error opening file", "Check the CODE ! ~.~");
}
}
I'm not sure what it is you're eventually trying to accomplish here. There are several more succinct ways to do what your current code is doing, but they won't significantly improve the speed of reading.
The bottleneck in your code is that you're appending strings. Using a StringBuilder is good advice, but you can do better than that by creating a List<string> and then calling string.Join at the end. For example:
if (openFileDialog1.ShowDialog() == DialogResult.Cancel)
return;
List<string> staff = new List<string>();
List<string> other = new List<string>();
foreach (var line in File.ReadLines(openFileDialog1.FileName))
{
line = line.ToLower();
if (line.Contains("staff"))
{
staff.Add(line);
}
else
{
other.Add(line);
}
}
relevantcount = staff.Count;
irrelevantCount = other.Count;
textBox1.Text = string.Join(","+Environment.NewLine, staff);
textBox2.Text = string.Join("."+Environment.NewLine, other);
Also, you say that your code can only handle 500 lines at a time. Is there something in your user interface that prevents it from handling more? Certainly, there's nothing in the code you showed that has such a low limit.
500 lines is nothing.
Try File.ReadAllLines and File.WriteAllLines.
Then you can do your work on an array of strings in memory and avoid the iterative IO.
Reading files line by line is very slow. You can make this code much faster by reading a large block of data (or even the entire file if it's not too enormous). For example, use a File.ReadAllLines to read the entire file as separate lines, or use a FileStream and Read() into a buffer, and find the individual lines for yourself by looking for newline (\n, \r) characters.
To export the data, don't copy and paste it fom a text box - Write the results to one or two new files, and then just open them.
It is much, much more efficient to use StringBuilders to gather the text for the textboxes than to continuously append text.
Also, you should wrap your various streams in using blocks.
Here is a rewrite that should be much more efficient:
private void button1_Click_1(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.Cancel)
return;
try
{
//Set filestream to the result of the pick of the user
using (var fStr = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read))
{
//Create a streamreader, sr, to read the file
using (var sr = new StreamReader(fStr))
{
var sbTextBox1 = new System.Text.StringBuilder(10000);
var sbTextBox2 = new System.Text.StringBuilder(10000);
//While the end of the file has not been reached...
while (sr.Peek() >= 0)
{
//Create a 'line' that contains the current line of the textfile
string line = sr.ReadLine().ToLower();
if (line.Contains("staff"))
{
//Add a , to the end of the line**Important**
sbTextBox1.Append(line).Append(",").AppendLine();
releventcount += 1;
}
else
{
//Add a , to the end of the line**Important**
sbTextBox2.Append(line).Append(",").AppendLine();
irreleventcount += 1;
}
}
textBox1.Text = sbTextBox1.ToString();
textBox2.Text = sbTextBox2.ToString();
label1.Text = "Relevent: ";
label2.Text = "Irrelevant: ";
//Close the file so other modules can access it
sr.Close();
}
}
}
catch (Exception)
{
MessageBox.Show("Error opening file", "Check the CODE ! ~.~");
}
}