After importing plenty of XML files into application i tried to do modifications on it by using XML document class, for this i created few methods to do modifications.
The thing is the starting method it's working fine and when comes to the second one it's displaying System.IO exception like "File is already using another process".
So any one help me out how can i solve this issue.
Sample code what i'm doing:
Method1(fileList);
Method2(fileList);
Method3(fileList);
private void Method1(IList<RenamedImportedFileInfo> fileList)
{
try
{
string isDefaultAttribute = Resource.Resources.ImportIsDefaultAttribute;
string editorsPath = editorsFolderName + Path.DirectorySeparatorChar + meterType;
string profilesPath = profileFolderName + Path.DirectorySeparatorChar + meterType;
string strUriAttribute = Resource.Resources.ImportUriAttribute;
foreach (RenamedImportedFileInfo renameInfo in fileList)
{
if (renameInfo.NewFilePath.ToString().Contains(editorsPath) && (renameInfo.IsProfileRenamed != true))
{
var xmldoc = new XmlDocument();
xmldoc.Load(renameInfo.NewFilePath);
if (xmldoc.DocumentElement.HasAttribute(isDefaultAttribute))
{
xmldoc.DocumentElement.Attributes[isDefaultAttribute].Value = Resource.Resources.ImportFalse;
}
XmlNodeList profileNodes = xmldoc.DocumentElement.GetElementsByTagName(Resource.Resources.ImportMeasurementProfileElement);
if (profileNodes.Count == 0)
{
profileNodes = xmldoc.DocumentElement.GetElementsByTagName(Resource.Resources.ImportBsMeasurementProfileElement);
}
if (profileNodes.Count > 0)
{
foreach (RenamedImportedFileInfo profileName in oRenamedImportedFileList)
{
if (profileName.NewFilePath.ToString().Contains(profilesPath))
{
if (string.Compare(Path.GetFileName(profileName.OldFilePath), Convert.ToString(profileNodes[0].Attributes[strUriAttribute].Value, CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase) == 0)
{
profileNodes[0].Attributes[strUriAttribute].Value = Path.GetFileName(profileName.NewFilePath);
renameInfo.IsProfileRenamed = true;
break;
}
}
}
}
xmldoc.Save(renameInfo.NewFilePath);
xmldoc = null;
profileNodes = null;
}
}
oRenamedImportedFileList = null;
}
catch (NullReferenceException nullException) { LastErrorMessage = nullException.Message; }
}
Thanks,
Raj
You are probably opening the same file twice in your application. Before you can open it again, you have to close it (or leave it open and work on the same document without opening it again).
For help on how to implement this, please show us more code so we can give you advice.
Related
Due to some issues by running .xlsm files over the network it was decided not to use VBA anymore and to develop standalone apps that will edit regular excel files.
Since I have a some C# and Visual Studio knowledge I decided to use those tools. Since Iterop.Excel is really slow I decided to use SpreadsheetLight.
Everything went smooth during while reading and analyzing data but after I added some records and save the file the file become corrupted: when trying to open with excel I got the following message:
"We found A problem with some content. Do you want us to recover as much as we can? If you trust the source of this workbook, click yes". After click yes got the message that it cannot be recovered because is corrupt.
Even if I don't add any records and just save the file got corrupted.
The thing is that the file opens without any issues in OpenOffice, all the records are there.
Any help will be appreciated!
Below the class that implements the r/w of the excel file:
class SPREADSHEET_TOOLS
{
public string file_name;
public SLDocument doc;
public List<string> sheets;
MemoryStream ms;
public SPREADSHEET_TOOLS()
{
}
public bool init(string _file_name)
{
this.file_name = _file_name;
ms = new MemoryStream();
try
{
FileStream stream = File.Open(this.file_name, FileMode.Open);
this.doc = new SLDocument(stream);
this.sheets = doc.GetSheetNames();
stream.Close();
}
catch (IOException)
{
MessageBox.Show("Fisierul este deschis de un alt utilizator. Nu poate fi accesat!!!!");
return false;
}
return true;
}
public List<string>getUniqeRowValues(string sheet,int row)
{
List<string> values = new List<string>();
if (this.sheets.Contains(sheet))
{
this.doc.SelectWorksheet(sheet);
while (this.doc.GetCellValueAsString(row, 1) != "")
{
if (values.Count == 0)
{
values.Add(this.doc.GetCellValueAsString(row, 1));
}
else
{
if (!values.Contains(this.doc.GetCellValueAsString(row, 1)))
{
values.Add(this.doc.GetCellValueAsString(row, 1));
}
}
row++;
}
}
return values;
}
public List<string>getChildValues(string sheet, string parent, int row, int column_parent, int column_child)
{
List<string> values = new List<string>();
if (this.sheets.Contains(sheet))
{
this.doc.SelectWorksheet(sheet);
while (this.doc.GetCellValueAsString(row, column_parent) != "")
{
if (this.doc.GetCellValueAsString(row, column_parent) == parent)
{
values.Add(this.doc.GetCellValueAsString(row, column_child));
}
row++;
}
}
return values;
}
public int getLastRow(string sheet)
{
int row=0;
if (this.sheets.Contains(sheet))
{
this.doc.SelectWorksheet(sheet);
row = 1;
while (this.doc.GetCellValueAsString(row, 1) != "")
{
row++;
}
}
return row;
}
public bool writeRow(string[] data, string sheet,int row)
{
if (this.sheets.Contains(sheet))
{
this.doc.SelectWorksheet(sheet);
for (int i=0; i < data.Length; i++)
{
InlineString str = new InlineString();
//bool a = this.doc.SetCellValue(row,i+1,data[i]);
}
//this.doc.SaveAs(this.ms);
foreach (string s in this.sheets)
{
this.doc.SelectWorksheet(s);
}
this.doc.DocumentProperties.Creator = "CP";
this.doc.SaveAs("E:\\C-SHARP\\PONTAJ\\PONTAJ\\BUBU.XLSX");
MessageBox.Show("Saved!");
return true;
}
return false;
}
}
I also faced the same problem, Excel file gets corrupted after downloading.
So I have done some fixes and update SpreadSheetLight code to .NET 6.
You can download source code from here: https://github.com/bhavinvachhani403/SpreadSheetLight_Net6.0
I hope this will helps you to solve your problem.
I had the same error and I solved it by changing the version of DocumentFormat.OpenXml to version 2.5
This question already has answers here:
Sorting Files by date
(8 answers)
Closed 2 years ago.
I created a Windows application to run on any Windows 10 OS with a button function which when the user click, will load all available .map files name from a certain folder. Upon loading the available file, it will display all the files in a ListView forms and which the files will be based on the files naming. However, how do I make it to sort according to the date of the file has been created/modified?
Here is my code :
private void btnLot_Click(object sender, EventArgs e)
{
string _ext = string.Empty;
DialogResult result = openLotDialog.ShowDialog();
if (result == System.Windows.Forms.DialogResult.Cancel)
{
return;
}
lvMapFiles.Items.Clear();
m_IUpperPCBMacData = null;
m_ILowerPCBMacData = null;
picDevTop.Invalidate();
if (System.IO.Path.GetExtension(m_FolderDialog.SelectedPath).Trim() != "")
{
MessageBox.Show(this, "Please select a folder. Don't select a file.", "Open Folder Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string[] files = Directory.GetFiles(openLotDialog.SelectedPath);
// Add these files into list view
pathDirectory = openLotDialog.SelectedPath;
//pathDirectory = m_FolderDialog.SelectedPath;
fileExtension = string.Empty;
int i = 0;
foreach (string s in files)
{
fileName = System.IO.Path.GetFileNameWithoutExtension(s);
_ext = System.IO.Path.GetExtension(s);
if (fileName.Trim().ToUpper().Contains("_TEMP"))
{
System.IO.File.Delete(s);
continue;
}
if (fileName.Trim().ToUpper().Contains("_SUMMARY"))
{
continue;
}
if (_ext.Trim().ToUpper() != ".MAP")
{
continue;
}
if (fileExtension.Trim() == "")
{
fileExtension = System.IO.Path.GetExtension(s);
}
ListViewItem _lvi1 = new ListViewItem();
_lvi1.SubItems.Add("");
lvMapFiles.Items.Add(_lvi1);
lvMapFiles.Items[i].Text = fileName;
i++;
}
//m_CalcParticle = true;
CUtil.Instance.ResetDefectCodeAndDescription();
if (ReadMapFiles(pathDirectory + "\\" + lvMapFiles.Items[0].Text + fileExtension))
{
lvMapFiles.Items[0].Selected = true;
LoadDefectCodeList();
LoadDefectMenuList();
}
else
{
lvMapFiles.Items.Clear();
MessageBox.Show(this, "Fail to Open Map File. Make sure to select the correct Map file.", "Read Map Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Assuming the code below will read and add all available files to the ListView, is there any way I can add a function to sort the files first before adding to the ListView?
foreach (string s in files)
{
fileName = System.IO.Path.GetFileNameWithoutExtension(s);
_ext = System.IO.Path.GetExtension(s);
if (fileName.Trim().ToUpper().Contains("_TEMP"))
{
System.IO.File.Delete(s);
continue;
}
if (fileName.Trim().ToUpper().Contains("_SUMMARY"))
{
continue;
}
if (_ext.Trim().ToUpper() != ".MAP")
{
continue;
}
if (fileExtension.Trim() == "")
{
fileExtension = System.IO.Path.GetExtension(s);
}
ListViewItem _lvi1 = new ListViewItem();
_lvi1.SubItems.Add("");
lvMapFiles.Items.Add(_lvi1);
lvMapFiles.Items[i].Text = fileName;
i++;
}
Thank you for the help!
You can leverage the System.IO.DirectoryInfo type, as well as LINQ in order to apply sorting.
First include the appropriate namespaces, if they are not already present.
using System.Collections.Generic;
using System.IO;
using System.Linq;
Then update the files variable assignment to load the directory, sort by creation date (ascending).
IEnumerable<string> files = new DirectoryInfo(openLotDialog.SelectedPath)
.GetFiles()
.OrderBy(x => x.CreationTime)
.Select(x => x.FullName);
Note that there may be other properties or methods available on System.IO.FileInfo that may be beneficial to use as opposed to reverting back to the full path.
I have a very large file, almost 2GB in size. I am trying to write a process to read the file in and write it out without the first row. I pretty much have been only able to read and write one line at a time which takes forever. I can open it, remove the first row and save it faster in TextPad, though that is still very slow.
I use this code to get the number of records in the file:
private long getNumRows(string strFileName)
{
long lngNumRows = 0;
string strMsg;
try
{
lngNumRows = 0;
using (var strReader = File.OpenText(#strFileName))
{
while (strReader.ReadLine() != null)
{
lngNumRows++;
}
strReader.Close();
strReader.Dispose();
}
}
catch (Exception excExcept)
{
strMsg = "The File could not be read: ";
strMsg += excExcept.Message;
System.Windows.MessageBox.Show(strMsg);
//Console.WriteLine("Thee was an error reading the file: ");
//Console.WriteLine(excExcept.Message);
//Console.ReadLine();
}
return lngNumRows;
}
This only takes seconds to run. When I add the following code it takes forever to run. Am I doing something wrong? Why does the write add so much time? Any ideas on how I can make this faster?
private void ProcessTextFiles(string strFileName)
{
string strDataLine;
string strFullOutputFileName;
string strSubFileName;
int intPos;
long lngTotalRows = 0;
long lngCurrNumRows = 0;
long lngModNumber = 0;
double dblProgress = 0;
double dblProgressPct = 0;
string strPrgFileName = "";
string strOutName = "";
string strMsg;
long lngFileNumRows;
try
{
using (StreamReader srStreamRdr = new StreamReader(strFileName))
{
while ((strDataLine = srStreamRdr.ReadLine()) != null)
{
lngCurrNumRows++;
if (lngCurrNumRows > 1)
{
WriteDataRow(strDataLine, strFullOutputFileName);
}
}
srStreamRdr.Dispose();
}
}
catch (Exception excExcept)
{
strMsg = "The File could not be read: ";
strMsg += excExcept.Message;
System.Windows.MessageBox.Show(strMsg);
//Console.WriteLine("The File could not be read:");
//Console.WriteLine(excExcept.Message);
}
}
public void WriteDataRow(string strDataRow, string strFullFileName)
{
//using (StreamWriter file = new StreamWriter(#strFullFileName, true, Encoding.GetEncoding("iso-8859-1")))
using (StreamWriter file = new StreamWriter(#strFullFileName, true, System.Text.Encoding.UTF8))
{
file.WriteLine(strDataRow);
file.Close();
}
}
Not sure how much this will improve the performance, but surely, opening and closing the output file for every line that you want to write is not a good idea.
Instead open both files just one time and then write the line directly
using (StreamWriter file = new StreamWriter(#strFullFileName, true, System.Text.Encoding.UTF8))
using (StreamReader srStreamRdr = new StreamReader(strFileName))
{
while ((strDataLine = srStreamRdr.ReadLine()) != null)
{
lngCurrNumRows++;
if (lngCurrNumRows > 1)
file.WriteLine(strDataRow);
}
}
You could also remove the check on lngCurrNumRow simply making an empty read before entering the while loop
strDataLine = srStreamRdr.ReadLine();
if(strDataLine != null)
{
while ((strDataLine = srStreamRdr.ReadLine()) != null)
{
file.WriteLine(strDataRow);
}
}
Depending on the memory of your machine. You could try the following (my big file was "D:\savegrp.log" I had a 2gb file knocking about) This used about 6gb memory when I tried it
int counter = File.ReadAllLines(#"D:\savegrp.log").Length;
Console.WriteLine(counter);
It does depends on the memory available..
File.WriteAllLines(#"D:\savegrp2.log",File.ReadAllLines(#"D:\savegrp.log").Skip(1));
Console.WriteLine("file saved");
I am trying to redact some word files using c# and openxml. I need to do controlled replace of the numbers with certain phrase. Each word file contains different amount of info. I want to use OPENXML powertools for this purspose.
I used normal openxml method to replace but it very unreliable and gets random errors such as zero length error.I used regex replace and that seems to work but it replaces it through out the document which is highly undesirable.
Here is some snippet of the code :
private void redact_Replaceall(string wfile)
{
try
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(wfile, true))
{
var ydoc = doc.MainDocumentPart.GetXDocument();
IEnumerable<XElement> content = ydoc.Descendants(W.body);
Regex regex = new Regex(#"\d+\.\d{2,3}");
int count1 = OpenXmlPowerTools.OpenXmlRegex.Match(content, regex);
int count2 = OpenXmlPowerTools.OpenXmlRegex.Replace(content, regex, replace_text, null);
statusBar1.Text = "Try 1: Found: " + count1 + ", Replaced: " + count2;
doc.MainDocumentPart.PutXDocument();
}
}
catch(Exception e)
{
MessageBox.Show("Replace all exprienced error: " + e.Message);
}
}
Basically, I want to do this redaction based on content of paragraph. I am able to get the paragraphs using but not the id's
IEnumerable<XElement> content = ydoc.Descendants(W.p);
Here is my approach using the normal openxml method but I get alot of errors depending on the file.
foreach (DocumentFormat.OpenXml.Wordprocessing.Paragraph para in bod.Descendants<DocumentFormat.OpenXml.Wordprocessing.Paragraph>())
{
foreach (var run in para.Elements<Run>())
{
foreach (var text in run.Elements<Text>())
{
string temp = text.Text;
int firstlength = first.Length + 1;
int secondlength = second.Length + 1;
if (text.Text.Contains(first) && !(temp.Length > firstlength))
{
text.Text = text.Text.Replace(first, "DELETED");
}
if (text.Text.Contains(second) && !(temp.Length > secondlength))
{
text.Text = text.Text.Replace(second, "DELETED");
}
}
}
}
Here is the last new approach but I am stuck on it
private void redact_Replacebadones(string wfile)
{
try
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(wfile, true))
{
var ydoc = doc.MainDocumentPart.GetXDocument();
/* from XElement xele in ydoc.Root.Elements();
List<string> lhsElements = xele.Elements("lhs")
.Select(el => el.Attribute("id").Value)
.ToList();
*/
/// XElement
IEnumerable<XElement> content = ydoc.Descendants(W.p);
foreach (var p in content )
{
if (p.Value.Contains("each") && !p.Value.Contains("DELETED"))
{
string to_overwrite = p.Value;
Regex regexop = new Regex(#"\d+\.\d{2,3}");
regexop.Replace(to_overwrite, "Deleted");
p.SetValue(to_overwrite);
MessageBox.Show("NAME :" + p.GetParagraphInfo() +" VValue:"+to_overwrite);
}
}
doc.MainDocumentPart.PutXDocument();
}
}
catch (Exception e)
{
MessageBox.Show("Replace each exprienced error: " + e.Message);
}
}
May be a bit late. OpenXML Power tools by Eric white has a Function SearchAndReplace where you can replace Text content, so you don't have to handle it with RegEx.
This function handles also text which is splitted into runs. (If you edit a word, a word can be splittet in runs, so you dint find the search phrase directly.)
May be this helps somebody.
Alright, The following code I've had in production for over a year with no changes. It has been working quite well. Within the past month more then a handful machines report that the xml documents are completely empty. They do not even contain a xml header . I cannot duplicate the files suddenly being empty, nor can i suggest a way for it to happen. I am hoping someone has had a similar issue that they solved.
Most of the machine that have been using this code have been using it for about a year, if not more. The empty files used to have data and lists in them.The files do not serialize at the same time. The save / serialize one after the other before the program exits.
My questions:
is it possible for the code below to create an empty file?
What else would cause them to be suddenly empty?
Has anyone else had issues with XML-serializer in the past month? (This problem has only happened in the past month on builds that have been stable for 3+ months.)
If you have questions or i missing something ask please. There also is a wide variety of types that i serialize... so if you can imagine it I probably have something similar that gets serialized.
public class BackEnd<T> {
public string FileSaveLocation = "this gets set on startup";
public bool DisabledSerial;
public virtual void BeforeDeserialize() { }
public virtual void BeforeSerialize() { }
public virtual void OnSuccessfulSerialize() { }
protected virtual void OnSuccessfulDeserialize(ListBackEnd<T> tmpList) { }
protected virtual void OnDeserialize(ListBackEnd<T> tmpList) { }
public virtual void serialize()
{
if (DisabledSerial)
return;
try
{
BeforeSerialize();
using (TextWriter textWrite = new StreamWriter(FileSaveLocation))
{
(new XmlSerializer(this.GetType())).Serialize(textWrite, this);
Debug.WriteLine(" [S]");
textWrite.Close();
}
OnSuccessfulSerialize();
}
catch (Exception e)
{
Static.Backup.XmlFile(FileSaveLocation);
Log.ErrorCatch(e,
"xml",
"serialize - " + typeof(T) + " - " + (new FileInfo(FileSaveLocation)).Name);
}
}
public virtual object deserialize(TextReader reader)
{
if (this.DisabledSerial)
return false;
ListBackEnd<T> tmp = null;
this.BeforeDeserialize();
if (reader == null && !File.Exists(this.FileSaveLocation))
{
Log.Write(Family.Error,
"xml",
"deserialize - " + this.GetType() + " - file not found. " + (new FileInfo(FileSaveLocation)).Name);
}
else
{
try
{
using (TextReader textRead = ((reader == null) ? new StreamReader(this.FileSaveLocation) : reader))
{
tmp = (ListBackEnd<T>)this.get_serializer().Deserialize(textRead);
Debug.WriteLine(" [D]");
textRead.Close();
}
OnSuccessfulDeserialize(tmp);
if (tmp != null)
{
this._Items = tmp._Items;
this.AutoIncrementSeed = tmp.AutoIncrementSeed;
if (this._Items.Count > this.AutoIncrementSeed && this._Items[0] is ItemStorage)
this.AutoIncrementSeed = this._Items.Max(item => (item as ItemStorage).Key);
}
}
catch (Exception e)
{
// this only copies the file
Static.Backup.XmlFile(FileSaveLocation);
// this only logs the exception
Log.ErrorCatch(e,
"xml",
"deserialize - " + typeof(T) + " - " + (new FileInfo(FileSaveLocation)).Name);
}
}
//{ Log.ErrorCatch(e, "xml", "deserialize" + this.GetType() + " - " + this.FileSaveLocation); }
OnDeserialize(tmp);
tmp = null;
return (_Items.Count > 0);
}
}
We've encountered this problem several times at $WORK, with the symptom being an empty file of the correct size but filled with zero bytes.
The solution we found was to set the WriteThrough value on the FileStream:
using (Stream file = new FileStream(settingTemp, FileMode.Create,
FileAccess.Write, FileShare.None,
0x1000, FileOptions.WriteThrough))
{
using (StreamWriter sw = new StreamWriter(file))
{
...
}
}
The only reason I can think that this would happen is that this line:
(new XmlSerializer(this.GetType())).Serialize(textWrite, this);
throws an exception and the textwriter is created and disposed without ever having anything written to it. I'd look at your log for errors.
What does
Static.Backup.XmlFile(FileSaveLocation);
do?