Will XmlSerializer ever create empty documents - c#

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?

Related

Sharing violation on path

I am trying to write some string to a file, and here is the code:
private static void WriteSelfDefinedFile(string msg)
{
ArrayList logTypes = SelfDefinedLogRule(msg);
// New some StreamWriter here
StreamWriter[] sws = new StreamWriter[selfDefinedLogFileName.Length];
for(int i = 0;i<selfDefinedLogFileName.Length;i++)
{
sws[i] = new StreamWriter(selfDefinedLogDir + selfDefinedLogFileName[i], true);
Debug.Log("111");
}
// It is writting here, not important for this question,I think.
foreach(SelfDefinedLogType temp in logTypes)
{
int index = (int)temp;
foreach (SelfDefinedLogType n in Enum.GetValues(typeof(SelfDefinedLogType)))
{
if(temp == n && sws[index]!=null)
{
sws[index].WriteLine(System.DateTime.Now.ToString() + ":\t"+ msg);
break;
}
else if(sws[index] == null)
{
LogError("File " + selfDefinedLogFileName[index] + " open fail");
}
}
}
// Close the StreamWrite[] here
for(int i=0;i<selfDefinedLogFileName.Length;i++)
{
sws[i].Close();
Debug.Log("222");
}
}
When the client is sending msg to server or server replying some msg to client, this funtion will be called to write some message to some files.
And unity throws the IOException:Sharing violation on path D:\SelfDefinedLogs\SentAndReceiveMsg.txt, sometimes. I mean, it doesn't happened everytime I write.
I have closed all the opened streamWriter at the end of the funtion, but the problem still come up.I am really confused.I will be grateful if anybody gives some solutions to this problem.

Attempted to seek before beginning of stream inside a using() statement

So I got the IOException: Attempted to Seek before the beginning of the stream. But when I looked into it the seek statement was inside of a using statement. I might be missunderstanding the using() because as far as I knew this initializes the in this case filestream before running the encased code.
private string saveLocation = string.Empty;
// This gets called inside the UI to visualize the save location
public string SaveLocation
{
get
{
if (string.IsNullOrEmpty(saveLocation))
{
saveLocation = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + #"\Pastes";
Initializer();
}
return saveLocation;
}
set { saveLocation = value; }
}
And this is the function it calls
private void Initializer()
{
// Check if the set save location exists
if (!Directory.Exists(saveLocation))
{
Debug.Log("Save location did not exist");
try
{
Directory.CreateDirectory(saveLocation);
}
catch (Exception e)
{
Debug.Log("Failed to create Directory: " + e);
return;
}
}
// Get executing assembly
if (string.IsNullOrEmpty(executingAssembly))
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
executingAssembly = Uri.UnescapeDataString(uri.Path);
}
// Get the last received list
if (!string.IsNullOrEmpty(executingAssembly))
{
var parent = Directory.GetParent(executingAssembly);
if (!File.Exists(parent + #"\ReceivedPastes.txt"))
{
// empty using to create file, so we don't have to clean up behind ourselfs.
using (FileStream fs = new FileStream(parent + #"\ReceivedPastes.txt", FileMode.CreateNew)) { }
}
else
{
using (FileStream fs = new FileStream(parent + #"\ReceivedPastes.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
if (fs.Seek(-20000, SeekOrigin.End) >= 0)
{
fs.Position = fs.Seek(-20000, SeekOrigin.End);
}
using (StreamReader sr = new StreamReader(fs))
{
while (sr.ReadLine() != null)
{
storedPastes.Add(sr.ReadLine());
}
}
}
}
}
isInitialized = true;
}
Are the commentors have posted: the file is less than 20000 bytes. It seems like you assume that Seek will stay at position 0 if the file is not large enough. It doesn't. It throws ArgumentException in that case.
Another thing. Seek will move the position for you. No need to do both. Either use:
fs.Seek(-20000, SeekOrigin.End);
or set the position:
fs.Position = fs.Length - 20000;
So what you really wanted to write is:
if (fs.Length > 20000)
fs.Seek(-20000, SeekOrigin.End);

System.IO exception coming while saving XML document in C#

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.

extract ISO with winrar automatically with c# or batch

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);
}
}

Binary reader skips instructions

I'm trying to read from a binary file with BinaryReader.
This is how I call my reading method :
foreach (Movie film in TreeBuilder.myMovies)
{
if (File.Exists(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + film.MovieName + ".txt"))
{
string[] myArray = operationManager.BinaryReading(film.MovieName);
if (myArray != null)
{
this.textStarring.Text = myArray[1];
this.textProduced.Text = myArray[2];
this.textMusic.Text = myArray[3];
this.textYear.Text = myArray[4];
this.textTime.Text = myArray[5];
}
else
{
MessageBox.Show("An error occured");
}
}
This is my reading method :
public string[] BinaryReading(string name)
{
FileStream myStream = new FileStream(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + name + ".txt", FileMode.Open);
BinaryReader reader = new BinaryReader(myStream);
string loadString = reader.ReadString();
string[] loadArray = loadString.Split(',');
reader.Close();
myStream.Close();
return loadArray;
}
Now something within these lines is not working. My file is not empty because since it's only a string I can read whats in the file.
My problem is I'm trying to find whats wrong with a break point but as soon as I get past this line :
string loadString = reader.ReadString();
My program starts to run again. How is that possible ? This prevents me from checking what's inside my String[] and what are my values after the method call.
Any idea why ? Thanks in advance.
Update :
I tried to move my breakpoint here
string[] loadArray = loadString.Split(',');
But my program never stops so it never gets past the previous line.
Also this is my Writting method :
foreach (Movie film in TreeBuilder.myMovies)
{
if (film.MovieName == name)
{
FileStream myStream = new FileStream(#"C:\Users\DaPhunk\Documents\Visual Studio 2010\Projects\YLK\Binary\" + film.MovieName + ".txt", FileMode.Create);
BinaryWriter writer = new BinaryWriter(myStream);
writer.Write(film.MovieName + "," + starring + "," + produced + "," + music + "," + year + "," + lenght);
writer.Close();
myStream.Close();
}
}
Your string will be prefixed with a length field. That makes the .txt extension misleading.
Since it 'suddenly started working again' : is it possible you opened (and saved) one of the files with a Text editor?
Also, your current Read and Write methods are not thread-safe, you should enclose the Stream and Reader/Writer objects in using() {} statements.

Categories