TextFieldParser Not Setting EndOfData field - c#

I have a Validate(Stream inputStream) method. This method calls several other validation methods by passing the inputStream to each one. Each of these creates a new TextFieldParser and reads/validates the file.
When the first ValidateA(inputStream) is called, it works. But, when the 2nd ValidateB(inputStream) is called, the parser.EndOfData is true so, it does not read the fields.
I've tried to clean up the code to its simplest form.
public int Validate(Stream inputStream, ref List<string> errors)
{
inputStream.Seek(0, SeekOrigin.Begin);
errors.AddRange(ValidateA(inputStream));
// The 2nd time, the EndOfData is true, so it doesn't read the fields
inputStream.Seek(0, SeekOrigin.Begin);
errors.AddRange(ValidateB(inputStream));
...
}
private List<string> ValidateA(Stream inputStream)
{
List<string> errors = new List<string>();
// Works fine the first time
using (var parser = new TextFieldParser(inputStream))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.TrimWhiteSpace = true;
int lineNumber = 0;
while (!parser.EndOfData)
{
string[] fields = parser.ReadFields();
// Processing....
}
if (lineNumber < 2)
errors.Add(string.Format("There is no data in the file"));
}
return errors;
}
Here is where the problem occurs. The ValidateB method cannot process the file because the EndOfData field does not get reset.
private List<string> ValidateB(Stream inputStream)
{
List<string> errors = new List<string>();
using (var parser = new TextFieldParser(inputStream))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.TrimWhiteSpace = true;
int LineNumber = 0;
while (!parser.EndOfData)
{
// Processing....
}
}
return errors;
}

The comment by #HansPassant is correct and lead me to change the way I was passing data around. Instead of passing a Stream around, I converted the MemoryStream to a byte[].
Then, in the ValidateX(byte[] fileByteArray) method, I would create a new MemoryStream from the byte array and use it.
Example:
Stream stream = model.PostedFile.InputStream;
MemoryStream memStream = new MemoryStream();
stream.CopyTo(memStream);
byte[] data = memStream.ToArray();
var result = ValidateB(data);
And then,
private List<string> ValidateB(byte[] fileByteArray)
{
List<string> errors = new List<string>();
MemoryStream ms = new MemoryStream(fileByteArray);
ms.Position = 0;
ms.Seek(0, SeekOrigin.Begin);
using (var parser = new TextFieldParser(ms))
{
// Processing...
}
}
This prevented problems with the EndOfData and trying to access a Stream that was closed.

Related

Got a message " MEMORY STREAM IS NOT EXPANDABLE" after using WordprocessingDocument base on Microsoft site on MVC

Currently, I was base on "Search and replace text in a document part (Open XML SDK)" on the Microsoft site. I've realized that the code got an issue after the file has downloaded to my drive.
So I opened that file and got a message
MEMORY STREAM IS NOT EXPANDABLE at sw.Write(docText);
How to fix that?
In GenerateDocxHelper class:
private readonly MemoryStream _mem;
private Dictionary<string, string> _dicData;
public GenerateDocxHelper(string path)
{
_mem = new MemoryStream(System.IO.File.ReadAllBytes(path));
_dicData = new Dictionary<string, string>();
}
public MemoryStream ReplaceTextInWord()
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(_mem, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
foreach (var data in _dicData)
{
docText = docText.Replace(data.Key, data.Value);
}
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
_mem.Seek(0, SeekOrigin.Begin);
return _mem;
}
You should create the MemoryStream with capacity = 0 which means it is resizeable,
and then add the bytes you have read from the file.
var allBytes = File.ReadAllBytes(path);
//this makes _mem resizeable
_mem = new MemoryStream(0);
_mem.Write(allBytes, 0, allBytes.Length);
Check this answer

Method that return a string with an specifc extension

Im a long time trying to solve one problem. I have one method that Serialize a string, follows the code:
XmlRetorno()
var algumasDef = new XmlWriterSettings {
Indent = true,
OmitXmlDeclaration = true
};
var nameSpace = new XmlSerializerNamespaces();
nameSpace.Add(string.Empty, "urn:sngpc-schema");
var meuXml = new XmlSerializer(GetType(), "urn:sngpc-schema");
using (var minhaString = new StringWriterWithEncoding(Encoding.GetEncoding("iso-8859-1"))) {
using (var escreve = XmlWriter.Create(minhaString, algumasDef)) {
meuXml.Serialize(escreve, this, nameSpace);
}
return minhaString.ToString();
}
Then, my next step is to compact that string to a zip file, my method to zip.
CompactXml()
string ziparEssaString = msg.XmlRetorno();
byte[] byteArray = new byte[ziparEssaString.Length];
int indexBA = 0;
foreach (char item in ziparEssaString.ToArray()) {
byteArray[indexBA++] = (byte)item;
}
//prepare to compress
using (MemoryStream ms = new MemoryStream()) {
using (GZipStream sw = new GZipStream(ms, CompressionMode.Compress)) {
sw.Write(byteArray, 0, byteArray.Length);
}
//transform bytes[] zip to string
byteArray = ms.ToArray();
StringBuilder sB = new StringBuilder(byteArray.Length);
foreach (byte item in byteArray) {
sB.Append((char)item);
}
return sB.ToString();
}
I need to compress a string that is formatted .xml and when I unpack I need the extension to be .xml too, my webservice return an error. Please, i need one light.

Putting Multiple Pdfs in a MemoryStream

I'm trying to take preexisting pdf files and read them all into a memory stream to then be shown on a telerik pdf viewer. If I just do one file it works but as soon as I try multiple files it gives me a internal null error (object ref not set to blah blah) and can't step in the code to see where its actualy null. Am I doing this wrong or something?
List<string> applicableReports = CurrentWizard.GetApplicableReports();
previousReportsStream = new MemoryStream();
Stream[] streams = new Stream[applicableReports.Count];
for (int i = 0; i < streams.Length; i++)
{
streams[i] = new MemoryStream(DocumentHelper.Instance.ConvertFileToByteArray(applicableReports[i]));
streams[i].CopyTo(previousReportsStream);
}
RadPdfViewer radPdfViewer = new RadPdfViewer();
RadFixedDocument document = new PdfFormatProvider(previousReportsStream, FormatProviderSettings.ReadAllAtOnce).Import();
radPdfViewer.Document = document;
This is where error is thrown:
RadFixedDocument document = new PdfFormatProvider(previousReportsStream, FormatProviderSettings.ReadAllAtOnce).Import();
DocumentHelper File to byte[]:
public byte[] ConvertFileToByteArray(string fileName)
{
FileInfo fileInfo = new FileInfo(fileName);
byte[] fileData = null;
using (FileStream fileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read))
{
BinaryReader binaryReader = new BinaryReader(fileStream);
fileData = binaryReader.ReadBytes((int)fileStream.Length);
}
return fileData;
}
One possible cause is the h process is out of memory because the code creates many MemoryStream object and does not dispose them.
Try change code to this:
List<string> applicableReports = CurrentWizard.GetApplicableReports();
previousReportsStream = new MemoryStream();
try
{
for (int i = 0; i < streams.Length; i++)
{
using( MemoryStream memStream = new MemoryStream(DocumentHelper.Instance.ConvertFileToByteArray(applicableReports[i]))
{
memStream.CopyTo(previousReportsStream);
}
}
RadPdfViewer radPdfViewer = new RadPdfViewer();
RadFixedDocument document = new PdfFormatProvider(previousReportsStream, FormatProviderSettings.ReadAllAtOnce).Import();
radPdfViewer.Document = document;
}
finally
{
previousReportsStream.Close();
}
As MemoryStream implements the IDisposable interface, you call dispose it to free the native resources; if not, the it will lead to high memory usage.
Please read MSDN for more details.

how to append memory stream

private MemoryStream ConvertWebChartChartToImage(WebChartControl chart)
{
using (var pcl = new PrintableComponentLink(new PrintingSystem())
{
PageHeaderFooter = new PageHeaderFooter(new PageHeaderArea(new string[] { "A", "Header" },
SystemFonts.DialogFont, BrickAlignment.Center),
new PageFooterArea(new string[] { "B" },
SystemFonts.DialogFont, BrickAlignment.Center)),
Component = ((IChartContainer)chart).Chart,
Landscape = true
})
{
((Chart)pcl.Component).OptionsPrint.SizeMode = DevExpress.XtraCharts.Printing.PrintSizeMode.Stret ch;
TransDistributionWCh.Legend.AlignmentHorizontal = LegendAlignmentHorizontal.Right;
pcl.CreateDocument();
var stream = new MemoryStream();
pcl.PrintingSystem.ExportToPdf(stream);
return stream;
}
}
private void ConvertHTMLStringToPDF()
{
using (var stream = new MemoryStream())
{
var listChartControl = new List<WebChartControl>(new List<WebChartControl>
{
SuccTransDistributionWCh,
AmountPerDayWCh,
TransPerDayWCh,
AmountPerTransPerDayWCh,
ActiveTerminalPerDayWCh,
TransNoWCh,
TransAmountWCh,
TransNoAmountWCh
});
foreach (var item in listChartControl)
{
var temp = ConvertWebChartChartToImage(item);
stream.Write(temp.ToArray(), 0, temp.ToArray().Length);
}
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("Accept-Header", stream.Length.ToString(CultureInfo.InvariantCulture));
HttpContext.Current.Response.AddHeader("Content-Disposition", ("Attachment") + "; filename=chart.pdf");
HttpContext.Current.Response.AddHeader("Content-Length", stream.Length.ToString(CultureInfo.InvariantCulture));
HttpContext.Current.Response.ContentEncoding = Encoding.Default;
HttpContext.Current.Response.BinaryWrite(stream.ToArray());
}
HttpContext.Current.Response.End();}
i am use web control chart dev express
and need convert web control chart to pdf
my question:How do I add data to memory stream ?
this code show last web chart
i suggest the zero number wrong
stream.Write(temp.ToArray(), 0, temp.ToArray().Length);
search the google and this site Unfortunately problem not solved
I have no idea, how ExportToPdf method works, but if it was written by human, there will be enough to use single stream:
private void ConvertWebChartChartToImage(WebChartControl chart, Stream stream)
{
// ...
pcl.PrintingSystem.ExportToPdf(stream);
}
private void ConvertHTMLStringToPDF()
{
using (var stream = new MemoryStream())
{
// ...
foreach (var item in listChartControl)
{
ConvertWebChartChartToImage(item, stream);
}
// ...
}
}
Note, that your original code leads to unnecessary memory allocations:
stream.Write(
temp.ToArray(), // allocate temporary array, copy stream content into array
0,
temp.ToArray().Length // allocate another array, copy stream content into array
);
and doesn't dispose MemoryStream instance, returned from ConvertWebChartChartToImage method.
Also, if you want to copy content of one Stream to another Stream, there are CopyTo/CopyToAsync methods.

Writing to MemoryStream with StreamWriter returns empty

I am not sure what I am doing wrong, have seen a lot of examples, but can't seem to get this working.
public static Stream Foo()
{
var memStream = new MemoryStream();
var streamWriter = new StreamWriter(memStream);
for (int i = 0; i < 6; i++)
streamWriter.WriteLine("TEST");
memStream.Seek(0, SeekOrigin.Begin);
return memStream;
}
I am doing a simple test on this method to try and get it to pass, but no matter what, my collection count is 0.
[Test]
public void TestStreamRowCount()
{
var stream = Foo();
using (var reader = new StreamReader(stream))
{
var collection = new List<string>();
string input;
while ((input = reader.ReadLine()) != null)
collection.Add(input);
Assert.AreEqual(6, collection.Count);
}
}
Note: I changed some syntax above without compiling in the Test method. What is more important is the first method which seems to be returning an empty stream (my reader.ReadLine() always reads once). Not sure what I am doing wrong. Thank you.
You are forgetting to flush your StreamWriter instance.
public static Stream Foo()
{
var memStream = new MemoryStream();
var streamWriter = new StreamWriter(memStream);
for (int i = 0; i < 6; i++)
streamWriter.WriteLine("TEST");
streamWriter.Flush(); <-- need this
memStream.Seek(0, SeekOrigin.Begin);
return memStream;
}
Also note that StreamWriter is supposed to be disposed of, since it implements IDisposable, but that in turn generates another problem, it will close the underlying MemoryStream as well.
Are you sure you want to return a MemoryStream here?
I would change the code to this:
public static byte[] Foo()
{
using (var memStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memStream))
{
for (int i = 0; i < 6; i++)
streamWriter.WriteLine("TEST");
streamWriter.Flush();
return memStream.ToArray();
}
}
[Test]
public void TestStreamRowCount()
{
var bytes = Foo();
using (var stream = new MemoryStream(bytes))
using (var reader = new StreamReader(stream))
{
var collection = new List<string>();
string input;
while ((input = reader.ReadLine()) != null)
collection.Add(input);
Assert.AreEqual(6, collection.Count);
}
}
Since you are not using "using" or streamWriter.Flush() the writer did not commit changes to the stream. As result Stream itslef does not have data yet. In general you want to wrap manipulation with Stream and StremaWriter instances with using.
You also should consider returning new instance of MemoryStream:
using(var memStream = new MemoryStream())
{
....
return new MemoryStream(memStream.ToArray(), false /*writable*/);
}
Try flushing streamWriter after writing your lines.

Categories

Resources