I've noticed that if I persist an object back into file using a Datacontractserializer, if the length of the new xml is shorter than the xml originally present in the file the remnants of the original xml outwith the length of the new xml will remain in the file and will break the xml.
Does anyone have a good solution to fix this?
Here's the code I am using to persist the object:
/// <summary>
/// Flushes the current instance of the given type to the datastore.
/// </summary>
private void Flush()
{
try
{
string directory = Path.GetDirectoryName(this.fileName);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
FileStream stream = null;
try
{
stream = new FileStream(this.fileName, FileMode.OpenOrCreate);
for (int i = 0; i < 3; i++)
{
try
{
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, new System.Text.UTF8Encoding(false)))
{
stream = null;
// The serializer is initialized upstream.
this.serializer.WriteObject(writer, this.objectValue);
}
break;
}
catch (IOException)
{
Thread.Sleep(200);
}
}
}
finally
{
if (stream != null)
{
stream.Dispose();
}
}
}
catch
{
// TODO: Localize this
throw;
//throw new IOException(String.Format(CultureInfo.CurrentCulture, "Unable to save persistable object to file {0}", this.fileName));
}
}
It's because of how you are opening your stream with:
stream = new FileStream(this.fileName, FileMode.OpenOrCreate);
Try using:
stream = new FileStream(this.fileName, FileMode.Create);
See FileMode documentation.
I believe this is due to using FileMode.OpenOrCreate. If the file already exits, I think the file is being opened and parts of the data are being overwritten from the start byte. If you change to using FileMode.Create it forces any existing files to be overwritten.
Related
Got a bit of a strange issue with a bit of code in Xamarin Forms:
public void GetSettings()
{
var assembly = typeof(SettingsPage).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream("FishBike_GPS.config.txt");
try
{
using (var reader = new System.IO.StreamReader(stream)) //load current settings from the config text file
{
configText = reader.ReadToEnd();
}
CurrentRentalSetting = Int32.Parse(configText);
stream.Dispose();
}
catch
{
configText = "Error reading file!";
}
}
public void SetSettings()
{
var assembly = typeof(SettingsPage).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream("FishBike_GPS.config.txt");
try
{
using (var streamWriter = new System.IO.StreamWriter(stream)) //save current settings from the config text file
{
streamWriter.WriteLine("test");
}
stream.Dispose();
}
catch
{
configText = "Error writing to file!";
infoLabel2.Text = configText;
}
}
The read function using streamreader works perfectly fine and reads the file displaying it ect, however although I'm using the same setup for the stream the streamwriter does not. Any help would be appreciated thanks.
I have a REST GET API that is written using WCF library to return Stream of a specific requested file that is located on API server that hosts that web service application. The service works well if the size of the requested file is small; that is less than 100 MB. But if file size is greater than > 100 MB, then the service returns 0 bytes without any logged information I can get the library method (saying, the "catch" block).
The library method (the class library project) returns Stream of needed file is
public Stream GetFile(string fileId, string seekStartPosition=null)
{
_lastActionResult = string.Empty;
Stream fileStream = null;
try
{
Guid fileGuid;
if (Guid.TryParse(fileId, out fileGuid) == false)
{
_lastActionResult = string.Format(ErrorMessage.FileIdInvalidT, fileId);
}
else
{
ContentPackageItemService contentItemService = new ContentPackageItemService();
string filePath = DALCacheHelper.GetFilePath(fileId);
if (File.Exists(filePath))
{
fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
long seekStart = 0;
// if seek position is specified, move the stream pointer to that location
if (string.IsNullOrEmpty(seekStartPosition) == false && long.TryParse(seekStartPosition, out seekStart))
{
// make sure seek position is smaller than file size
FileInfo fi = new FileInfo(filePath);
if (seekStart >= 0 && seekStart < fi.Length)
{
fileStream.Seek(seekStart, SeekOrigin.Begin);
}
else
{
_lastActionResult = string.Format(ErrorMessage.FileSeekInvalidT, seekStart, fi.Length);
}
}
}
else
{
_lastActionResult = string.Format(ErrorMessage.FileNotFoundT, fileId);
Logger.Write(_lastActionResult,
"General", 1, Constants.LogId.RESTSync, System.Diagnostics.TraceEventType.Error, System.Reflection.MethodBase.GetCurrentMethod().Name);
}
}
}
catch(Exception ex)
{
Logger.Write(ex,"General", 1, Constants.LogId.RESTSync, System.Diagnostics.TraceEventType.Error, System.Reflection.MethodBase.GetCurrentMethod().Name);
}
return fileStream;
}
API method on the client side project (where .svc file is):
[WebGet(UriTemplate = "files/{fileid}")]
public Stream GetFile(string fileid)
{
ContentHandler handler = new ContentHandler();
Stream fileStream = null;
try
{
fileStream = handler.GetFile(fileid);
}
catch (Exception ex)
{
Logger.Write(string.Format("{0} {1}", ex.Message, ex.StackTrace), "General", 1, Constants.LogId.RESTSync, System.Diagnostics.TraceEventType.Error, System.Reflection.MethodBase.GetCurrentMethod().Name);
throw new WebFaultException<ErrorResponse>(new ErrorResponse(HttpStatusCode.InternalServerError, ex.Message), HttpStatusCode.InternalServerError);
}
if (fileStream == null)
{
throw new WebFaultException<ErrorResponse>(new ErrorResponse(handler.LastActionResult), HttpStatusCode.InternalServerError);
}
return fileStream;
}
As you are using REST, I presume you are using the WebHttpBinding. You need to set the MaxReceivedMessageSize on the client binding to be sufficient for the maximum expected response size. The default is 64K. Here's the msdn documentation for the property if you are creating your binding in code. If you are creating your binding in your app.config, then this is the documentation you need.
I used the lib Nunrar site to extract a .rar file:
RarArchive.WriteToDirectory(fs.Name, Path.Combine(#"D:\DataDownloadCenter", path2), ExtractOptions.Overwrite);
the decompression works fine, but I can't after this operation of extract delete the original compressed file
System.IO.File.Delete(path);
because the file is is used by another process
the hole function :
try
{
FileStream fs = File.OpenRead(path);
if(path.Contains(".rar")){
try
{
RarArchive.WriteToDirectory(fs.Name, Path.Combine(#"D:\DataDownloadCenter", path2), ExtractOptions.Overwrite);
fs.Close();
}
catch { }
}
catch { return; }
finally
{
if (zf != null)
{
zf.IsStreamOwner = true; // Makes close also shut the underlying stream
zf.Close(); // Ensure we release resources
}
}
try
{
System.IO.File.Delete(path);
}
catch { }
So can I delete the compressed file after extract it?
I don't know what zf is but you can also likely wrap that in a using statement. Try replacing your FileStream fs part with this
using( FileStream fs = File.OpenRead(path))
{
if(path.Contains(".rar"))
{
try
{
RarArchive.WriteToDirectory(fs.Name, Path.Combine(#"D:\DataDownloadCenter", path2), ExtractOptions.Overwrite);
}
catch { }
}
}
This way fs is closed even if path doesn't contain .rar. You're only closing the fs if rar exists within the filename.
Also, does the library have its own stream handling? It could have a method that closes it.
I also had this issue with nunrar, nether close() or a using statement seem to fix this.
unfortunately the Documentation is scarce, so im now using the SharpCompress library it is a fork of the nunrar library according to the devs of nunrar.The documentation on SharpCompress is also scarce (but less) so here is my method im using:
private static bool unrar(string filename)
{
bool error = false;
string outputpath = Path.GetDirectoryName(filename);
try
{
using (Stream stream = File.OpenRead(filename))
{
var reader = ReaderFactory.Open(stream);
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
Console.WriteLine(reader.Entry.Key);
reader.WriteEntryToDirectory(outputpath, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true });
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Failed: " + e.Message);
error = true;
}
if (!error)
{
File.Delete(filename);
}
return error;
}
Add the following libraries to the top
using SharpCompress.Common;
using SharpCompress.Readers;
Install using nuget.This method works for SharpCompress v0.22.0(latest at the time of writing)
In my class "DiaryManager" I got two List with two different types (T) and I want to save it to file, then I want to load it.
I got it to work with one of my list's as I am going to show you.
My list that I save and load in my working code is named "m_diary". The save method is this one:
/// <summary>
/// Saves the object information
/// </summary>
public void Save()
{
// Gain code access to the file that we are going
// to write to
try
{
// Create a FileStream that will write data to file.
FileStream writerFileStream =
new FileStream(DATA_FILENAME, FileMode.Create, FileAccess.Write);
// Save our dictionary of friends to file
m_formatter.Serialize(writerFileStream, m_diary);
// Close the writerFileStream when we are done.
writerFileStream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
And my load method is this one:
/// <summary>
/// Load the object to the program
/// </summary>
public void Load()
{
// Check if we had previously Save information of our friends
// previously
if (File.Exists(DATA_FILENAME))
{
try
{
// Create a FileStream will gain read access to the
// data file.
FileStream readerFileStream = new FileStream(DATA_FILENAME,
FileMode.Open, FileAccess.Read);
// Reconstruct information of our friends from file.
m_diary = (List<Diary>)
m_formatter.Deserialize(readerFileStream);
// Close the readerFileStream when we are done
readerFileStream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
The "DATA_FILENAME" is this constant:
private const string DATA_FILENAME = "TrainingDiary.dat";
This code works perfect from my windows form class.
But now Iv added one more list with a different type.
How do I save and load that second list to?? :)
Best regards
Cyrix
You can do it using similar code for the second list, or you can write a generic method:
public static void Save<T>(string fileName, List<T> list)
{
// Gain code access to the file that we are going
// to write to
try
{
// Create a FileStream that will write data to file.
using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, list);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
And a load method:
public static List<T> Load<T>(string fileName)
{
var list = new List<T>();
// Check if we had previously Save information of our friends
// previously
if (File.Exists(fileName))
{
try
{
// Create a FileStream will gain read access to the
// data file.
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
var formatter = new BinaryFormatter();
list = (List<T>)
formatter.Deserialize(stream);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return list;
}
Usage of Load:
var list = new List<string> {"one", "two", "three"};
Save("first.dat", list);
var list2 = Load<string>("first.dat");
foreach (var VARIABLE in list2)
{
Console.WriteLine(VARIABLE);
}
Also see using Statement to handle open/close streams;
You should create a class that contains all the data (lists) you want to save. Then just save that class to file.
I need to read csv file twice. but after first reading:
using (var csvReader = new StreamReader(file.InputStream))
{
fileFullText += csvReader.ReadToEnd();
file.InputStream.Seek(0, SeekOrigin.Begin);
csvReader.Close();
}
using file in enother function:
public static List<string> ParceCsv(HttpPostedFileBase file)
{
//file.InputStream.Seek(0, SeekOrigin.Begin);
using (var csvReader = new StreamReader(file.InputStream))
{
// csvReader.DiscardBufferedData();
// csvReader.BaseStream.Seek(0, SeekOrigin.Begin);
string inputLine = "";
var values = new List<string>();
while ((inputLine = csvReader.ReadLine()) != null)
{
values.Add(inputLine.Trim().Replace(",", "").Replace(" ", ""));
}
csvReader.Close();
return values;
}
}
The file.Length is 0.
Can anybody help?
The reason is that SteramReader's Dispose() method also closes the underlying stream; In your case file.InputStream. The using statement calls Dispose() implicitly. Try to replace using with disposes of both your StreamReaded-s after you finished both read operations. As I remember some stream classes have a bool option to leave underlying stream open after dispose.
.NET 4.5 fixed this issue by introducing leaveOpen parameter in SteamReader constructor. See: MSDN
public StreamReader(
Stream stream,
Encoding encoding,
bool detectEncodingFromByteOrderMarks,
int bufferSize,
bool leaveOpen
)
One more thing. You do not need to close SteramReader yourself (the line with csvReader.Close();) when you wrap it in using statement, thus Dispose() and Close() are the same in case of StreamReader.
if your using HttpPostedFileBase you need to clone it first,
use the code this git here
or just add this as a class in your namespace:
public static class HttpPostedFileBaseExtensions
{
public static Byte[] ToByteArray(this HttpPostedFileBase value)
{
if (value == null)
return null;
var array = new Byte[value.ContentLength];
value.InputStream.Position = 0;
value.InputStream.Read(array, 0, value.ContentLength);
return array;
}
}
now you can read the HttpPostedFileBase like so:
private static void doSomeStuff(HttpPostedFileBase file)
{
try
{
using (var reader = new MemoryStream(file.ToByteArray()))
{
// do some stuff... say read it to xml
using (var xmlTextReader = new XmlTextReader(reader))
{
}
}
}
catch (Exception ex)
{
throw ex;
}
}
after using this you can still write in your main code:
file.SaveAs(path);
and it will save it to the file.