C# Null reference exception and StreamReader - c#

I am getting null reference exception when reading data from my txt file.
public class Appointments : List<Appointment>
{
Appointment appointment;
public Appointments()
{
}
public bool Load(string fileName)
{
string appointmentData = string.Empty;
using (StreamReader reader = new StreamReader(fileName))
{
while((appointmentData = reader.ReadLine()) != null)
{
appointmentData = reader.ReadLine();
//**this is where null ref. exception is thrown** (line below)
if(appointmentData[0] == 'R')
{
appointment = new RecurringAppointment(appointmentData);
}
else
{
appointment = new Appointment(appointmentData);
}
this.Add(appointment);
}
return true;
}
}
RecurringAppointment inherits from Appointments. File exists, file location is correct. Funny thing is that program was working 30 min ago I've only changed Load method from below to what u can see above :
public bool Load(string fileName)
{
string appointmentData = string.Empty;
using (StreamReader reader = new StreamReader(fileName))
{
while((appointmentData = reader.ReadLine()) != null)
{
appointmentData = reader.ReadLine();
if(appointmentData[0] == 'R')
{
this.Add(appointment = new RecurringAppointment(appointmentData));
}
else
{
this.Add(appointment = new Appointment(appointmentData));
}
}
return true;
}
}
Now it does not work in either case.

Your code reads two times at each loop. This means that, if your file has an odd number of rows when you read the last line of the file, the check against null inside the while statement allows your code to enter the loop but the following ReadLine returns a null string. Of course trying to read the char at index zero of a null string will throw the NRE exception.
There is also the problem of empty lines in your file. If there is an empty line then, again reading at index zero will throw an Index out of range exception
You could fix your code in this way
public bool Load(string fileName)
{
string appointmentData = string.Empty;
using (StreamReader reader = new StreamReader(fileName))
{
while((appointmentData = reader.ReadLine()) != null)
{
if(!string.IsNullOrWhiteSpace(appointmentData))
{
if(appointmentData[0] == 'R')
this.Add(appointment = new RecurringAppointment(appointmentData));
else
this.Add(appointment = new Appointment(appointmentData));
}
}
return true;
}
}

Related

C# pass file text to list when file is entered via command line argument

I am writing a program for an assignment that is meant to read two text files and use their data to write to a third text file. I was instructed to pass the contents of the one file to a list. I have done something similar, passing the contents to an array (see below). But I can't seem to get it to work with a list.
Here is what I have done in the past with arrays:
StreamReader f1 = new StreamReader(args[0]);
StreamReader f2 = new StreamReader(args[1]);
StreamWriter p = new StreamWriter(args[2]);
double[] array1 = new double[20];
double[] array2 = new double[20];
double[] array3 = new double[20];
string line;
int index;
double value;
while ((line = f1.ReadLine()) != null)
{
string[] currentLine = line.Split('|');
index = Convert.ToInt16(currentLine[0]);
value = Convert.ToDouble(currentLine[1]);
array1[index] = value;
}
If it is of any interest, this is my current setup:
static void Main(String[] args)
{
// Create variables to hold the 3 elements of each item that you will read from the file
// Create variables for all 3 files (2 for READ, 1 for WRITE)
int ID;
string InvName;
int Number;
string IDString;
string NumberString;
string line;
List<InventoryNode> Inventory = new List<InventoryNode>();
InventoryNode Item = null;
StreamReader f1 = new StreamReader(args[0]);
StreamReader f2 = new StreamReader(args[1]);
StreamWriter p = new StreamWriter(args[2]);
// Read each item from the Update File and process the data
//Data is separated by pipe |
If you want to convert Array to List, you can just call Add or Insert to make it happen.
According to your code, you can do Inventory.Add(Item).
while ((line = f1.ReadLine()) != null)
{
string[] currentLine = line.Split('|');
Item = new InventoryItem {
Index = Convert.ToInt16(currentLine[0]),
Value = Convert.ToDouble(currentLine[1])
};
Inventory.Add(Item);
}
like this.
If I understand it correctly all you want to do is read two input file, parse the data in these file in a particular format (in this case int|double) and then write it to a new file. If this is the requirement, please try out the following code, as it is not sure how you want the data to be presented in the third file I have kept the format as it is (i.e. int|double)
static void Main(string[] args)
{
if (args == null || args.Length < 3)
{
Console.WriteLine("Wrong Input");
return;
}
if (!ValidateFilePath(args[0]) || !ValidateFilePath(args[1]))
{
return;
}
Dictionary<int, double> parsedFileData = new Dictionary<int, double>();
//Read the first file
ReadFileData(args[0], parsedFileData);
//Read second file
ReadFileData(args[1], parsedFileData);
//Write to third file
WriteFileData(args[2], parsedFileData);
}
private static bool ValidateFilePath(string filePath)
{
try
{
return File.Exists(filePath);
}
catch (Exception)
{
Console.WriteLine($"Failed to read file : {filePath}");
return false;
}
}
private static void ReadFileData(string filePath, Dictionary<int, double> parsedFileData)
{
try
{
using (StreamReader fileStream = new StreamReader(filePath))
{
string line;
while ((line = fileStream.ReadLine()) != null)
{
string[] currentLine = line.Split('|');
int index = Convert.ToInt16(currentLine[0]);
double value = Convert.ToDouble(currentLine[1]);
parsedFileData.Add(index, value);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception : {ex.Message}");
}
}
private static void WriteFileData(string filePath, Dictionary<int, double> parsedFileData)
{
try
{
using (StreamWriter fileStream = new StreamWriter(filePath))
{
foreach (var parsedLine in parsedFileData)
{
var line = parsedLine.Key + "|" + parsedLine.Value;
fileStream.WriteLine(line);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception : {ex.Message}");
}
}
There are few things you should always remember while writing a C# code :
1) Validate command line inputs before using.
2) Always lookout for any class that has dispose method, instantiate it inside using block.
3) Proper mechanism in the code to catch exceptions, else your program would crash at runtime with invalid inputs or inputs that you could not validate!

Wait until string.contains() condition is met

I'm reading a file to my C# application and decompressing a tile_data BLOB using a gzip stream. I'm currently accessing the BLOB data through this method:
SQLiteCommand command = new SQLiteCommand(query, DbConn);
SQLiteDataReader reader = command.ExecuteReader();
bool isMet = false;
while (reader.Read())
{
using (var file = reader.GetStream(0))
using (var unzip = new GZipStream(file, CompressionMode.Decompress))
using (var fileReader = new StreamReader(unzip))
{
var line = fileReader.ReadLine();
while (!fileReader.EndOfStream)
{
}
Console.WriteLine("End of tile_data");
}
}
reader.Close();
Console.WriteLine("Reader closed");
Console.ReadKey();
}
catch (Exception e)
{
Console.Write(e.StackTrace);
Console.ReadKey();
}
I'm looking to wait until the fileReader detects "tertiary" (string) and then prints all data afterwards. I attempted to use a bool and a nested while loop but it came back as an infinite loop, hence the question.
The code that I used (and failed with):
if (line.Contains("tertiary"))
{
isMet = true;
}
while (!fileReader.EndOfStream && isMet)
{
Console.WriteLine(line);
}
How can I perform an operation only with my fileReader once a condition has been met?
Your fileReader.EndOfStream loop will only work if your stream has only a single line. The problem is that you're only reading from the stream once - so unless you've already read the whole thing, you're in an endless loop.
Instead, do something like this:
string line;
while ((line = fileReader.ReadLine()) != null)
{
if (line.Contains("...")) break; // Or whatever else you want to do
}
You can use this code. It find any character in the string. It is working for me.
string matchStr = "tertiary";
if (line.Any(matchStr.Contains)
{
isMet = true;
}
while (!fileReader.EndOfStream && isMet)
{
Console.WriteLine(line);
}
The line var line = fileReader.ReadLine(); be inside the while loop?
while (!fileReader.EndOfStream)
{
var line = fileReader.ReadLine();
// do some other stuff
}
Try something like this
var yourval;
var secval = fileReader.ReadLine()
while ((yourval = secval ) != null)
{
if (line.Contains("your string here"))
{
break;
}
}

c# nullreference for save on load streamreader/writer

I've made a program and I want to save the data. Saving is working, but "Loading" doesn't work.
public void Save(StreamWriter sw)
{
for (int i = 0; i < buecher.Count; i++)
{
Buch b = (Buch)buecher[i];
if (i == 0)
sw.WriteLine("ISDN ; Autor ; Titel");
sw.WriteLine(b.ISDN + ";" + b.Autor + ";" + b.Titel);
}
}
public void Load(StreamReader sr)
{
int isd;
string aut;
string tit;
while (sr.ReadLine() != "")
{
string[] teile = sr.ReadLine().Split(';');
try
{
isd = Convert.ToInt32(teile[0]);
aut = teile[1];
tit = teile[2];
}
catch
{
throw new Exception("umwandlung fehlgeschlagen");
}
Buch b = new Buch(isd, aut, tit);
buecher.Add(b);
}
}
If I'm doing that with an break after buecher.Add(b); than its everything fine but it obviously shows me only 1 book... if I'm not using the break he gives me an error "nullreference.."
Would be awesome if someone could help me
best regards
Ramon
The problem is that you are reading two lines for each iteration in the loop (and throwing away the first one). If there are an odd number of lines in the file, the second call to Read will return null.
Read the line into a variable in the condition, and use that variable in the loop:
public void Load(StreamReader sr) {
int isd;
string aut;
string tit;
// skip header
sr.ReadLine();
string line;
while ((line = sr.ReadLine()) != null) {
if (line.Length > 0) {
string[] teile = line.Split(';');
try {
isd = Convert.ToInt32(teile[0]);
aut = teile[1];
tit = teile[2];
} catch {
throw new Exception("umwandlung fehlgeschlagen");
}
Buch b = new Buch(isd, aut, tit);
buecher.Add(b);
}
}
}
You are calling sr.ReadLine() twice for every line, once in the while() and once right after. You are hitting the end of the file, which returns a null.
Different approach to this but I suggest it because it's simpler;
Load(string filepath)
{
try
{
List<Buch> buches = File.ReadAllLines(filepath)
.Select(x => new Buch(int.Parse(x.Split(';')[0]), x.Split(';')[1], x.Split(';')[2]));
{
catch
{
throw new Exception("umwandlung fehlgeschlagen");
}
}
You could do it in more lines if you find it to be more readable but I've come to prefer File.ReadAllText and File.ReadAllLines to StreamReader approach of reading files.
Instead of using the LINQ statement you could also do;
Load(string filepath)
{
try
{
string[] lines = File.ReadAllLines(filepath);
foreach (string line in lines)
{
string[] tokens = line.Split(';');
if (tokens.Length != 3)
// error
int isd;
if (!int.TryParse(tokens[0], out isd))
//error, wasn't an int
buetcher.Add(new Buch(isd, tokens[1], tokens[2]);
}
{
catch
{
throw new Exception("umwandlung fehlgeschlagen");
}
}

How to parse a message from a text file with c# that spans multiple lines?

Given this log file, how can I read a line with multiple new lines (\n) with a StreamReader?
The ReadLine method literally returns each line, but a message may span more that one line.
Here is what I have so far
using (var sr = new StreamReader(filePath))
using (var store = new DocumentStore {ConnectionStringName = "RavenDB"}.Initialize())
{
IndexCreation.CreateIndexes(typeof(Logs_Search).Assembly, store);
using (var bulkInsert = store.BulkInsert())
{
const char columnDelimeter = '|';
const string quote = #"~";
string line;
while ((line = sr.ReadLine()) != null)
{
batch++;
List<string> columns = null;
try
{
columns = line.Split(columnDelimeter)
.Select(item => item.Replace(quote, string.Empty))
.ToList();
if (columns.Count != 5)
{
batch--;
Log.Error(string.Join(",", columns.ToArray()));
continue;
}
bulkInsert.Store(LogParser.Log.FromStringList(columns));
/* Give some feedback */
if (batch % 100000 == 0)
{
Log.Debug("batch: {0}", batch);
}
/* Use sparingly */
if (ThrottleEnabled && batch % ThrottleBatchSize == 0)
{
Thread.Sleep(ThrottleThreadWait);
}
}
catch (FormatException)
{
if (columns != null) Log.Error(string.Join(",", columns.ToArray()));
}
catch (Exception exception)
{
Log.Error(exception);
}
}
}
}
And the Model
public class Log
{
public string Component { get; set; }
public string DateTime { get; set; }
public string Logger { get; set; }
public string Level { get; set; }
public string ThreadId { get; set; }
public string Message { get; set; }
public string Terms { get; set; }
public static Log FromStringList(List<string> row)
{
Log log = new Log();
/*log.Component = row[0] == string.Empty ? null : row[0];*/
log.DateTime = row[0] == string.Empty ? null : row[0].ToLower();
log.Logger = row[1] == string.Empty ? null : row[1].ToLower();
log.Level = row[2] == string.Empty ? null : row[2].ToLower();
log.ThreadId = row[3] == string.Empty ? null : row[3].ToLower();
log.Message = row[4] == string.Empty ? null : row[4].ToLower();
return log;
}
}
I would use Regex.Split and break the file up on anything that matches the date pattern (ex. 2013-06-19) at the beginning of each error.
If you can read the entire file into memory (i.e. File.ReadAllText), then you can treat it as a single string and use regular expressions to split on the date, or some such.
A more general solution that takes less memory would be to read the file line-by-line. Append lines to a buffer until you get the next line that starts with the desired value (in your case, a date/time stamp). Then process that buffer. For example:
StringBuilder buffer = new StringBuilder();
foreach (var line in File.ReadLines(logfileName))
{
if (line.StartsWith("2013-06-19"))
{
if (sb.Length > 0)
{
ProcessMessage(sb.ToString());
sb.Clear();
}
sb.AppendLine(line);
}
}
// be sure to process the last message
if (sb.Length > 0)
{
ProcessMessage(sb.ToString());
}
It is hard to see your file. But I would say read it line by line and Append to some variable.
Check for end of message. When you see it, do whatever you want to do with the message in that variable (insert into DB etc...) and then keep reading the next message.
Pseudo code
read the line
variable a = a + new line
if end of message
insert into DB
reset the variable
continue reading the message.....

Save email message as eml using C# in Lotus Notes

I need to export (save to) hard drive my Lotus Notes emails.
I figured out the way how to save attachments to HDD, but I can't figure out the way of how to save the whole email.
The code below shows how I export attachments. Can you suggest how can I modify it to save emails?
PS- I am new to programming.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Domino;
using System.Collections;
namespace ExportLotusAttachments
{
class Class1
{
public void ScanForEmails()
{
String textBox1 = "c:\\1";
NotesSession session = new NotesSession();
session.Initialize("");
NotesDbDirectory dir = null;
dir = session.GetDbDirectory("");
NotesDatabase db = null;
db = dir.OpenMailDatabase();
NotesDatabase NDb = dir.OpenMailDatabase(); //Database connection
//ArrayList that will hold names of the folders
ArrayList LotusViews2 = new ArrayList();
foreach (NotesView V in NDb.Views)
{
if (V.IsFolder && !(V.Name.Equals("($All)")))
{
NotesView getS = V;
LotusViews2.Add(getS.Name);
}
}
foreach (String obj in LotusViews2)
{
NotesDocument NDoc;
NotesView nInboxDocs = NDb.GetView(obj);
NDoc = nInboxDocs.GetFirstDocument();
String pAttachment;
while (NDoc != null)
{
if (NDoc.HasEmbedded && NDoc.HasItem("$File"))
{
object[] AllDocItems = (object[])NDoc.Items;
foreach (object CurItem in AllDocItems)
{
NotesItem nItem = (NotesItem)CurItem;
if (IT_TYPE.ATTACHMENT == nItem.type)
{
String path = textBox1;
pAttachment = ((object[])nItem.Values)[0].ToString();
if (!System.IO.Directory.Exists(path))
{
System.IO.Directory.CreateDirectory(textBox1);
}
try
{
NDoc.GetAttachment(pAttachment).ExtractFile(#path + pAttachment);
}
catch { }
}
}
}
NDoc = nInboxDocs.GetNextDocument(NDoc);
}
}
}
}
}
This post by Bob Babalan explains how to export lotus documents using Java. The same principle should work in C# or VB. The document is cnverted into MIME and written to the disk.
Or in version 8.5.3 (I think it started witn 8.5.1) you can just drag and drop it from the mail file to the file system.
I know it is a bit late, but this is, what I did. (Based on Bob Babalan)
Bobs Solution helped me alot to understand NotesMIMEEntities, but in his solution, he only traversed the MIME-Tree to the second "layer". This will traverse multiple layers.
public static void GetMIME(StreamWriter writer, NotesMIMEEntity mimeEntity)
{
try
{
string contentType = null;
string headers = null;
string content = null;
string preamble = null;
MIME_ENCODING encoding;
contentType = mimeEntity.ContentType;
headers = mimeEntity.Headers;
encoding = mimeEntity.Encoding;
// message envelope. If no MIME-Version header, add one
if (!headers.Contains("MIME-Version:"))
writer.WriteLine("MIME-Version: 1.0");
writer.WriteLine(headers);
// for multipart, usually no main-msg content...
content = mimeEntity.ContentAsText;
if (content != null && content.Trim().Length > 0)
writer.WriteLine(content);
writer.Flush();
if (contentType.StartsWith("multipart"))
{
preamble = mimeEntity.Preamble;
NotesMIMEEntity mimeChild = mimeEntity.GetFirstChildEntity();
while (mimeChild != null)
{
GetMimeChild(writer, mimeChild);
mimeChild = mimeChild.GetNextSibling();
}
}
writer.WriteLine(mimeEntity.BoundaryEnd);
writer.Flush();
}
catch (Exception ex)
{
Logging.Log(ex.ToString());
}
}
private void GetMimeChild(StreamWriter writer, NotesMIMEEntity mimeEntity)
{
string contentType = null;
string headers = null;
string content = null;
string preamble = null;
MIME_ENCODING encoding;
contentType = mimeEntity.ContentType;
headers = mimeEntity.Headers;
encoding = mimeEntity.Encoding;
if (encoding == MIME_ENCODING.ENC_IDENTITY_BINARY)
{
mimeEntity.EncodeContent(MIME_ENCODING.ENC_BASE64);
headers = mimeEntity.Headers;
}
preamble = mimeEntity.Preamble;
writer.Write(mimeEntity.BoundaryStart);
if (!content.EndsWith("\n"))
writer.WriteLine("");
writer.WriteLine(headers);
writer.WriteLine();
writer.Write(mimeEntity.ContentAsText);
if (contentType.StartsWith("multipart"))
{
preamble = mimeEntity.Preamble;
NotesMIMEEntity mimeChild = mimeEntity.GetFirstChildEntity();
while (mimeChild != null)
{
GetMimeChild(writer, mimeChild);
mimeChild = mimeChild.GetNextSibling();
}
}
writer.Write(mimeEntity.BoundaryEnd);
writer.Flush();
}
I would call this methods like this, to save the EML-File to a given path.
using (FileStream fs = new FileStream (path,FileMode.Create,FileAccess.ReadWrite,FileShare.None))
{
using (StreamWriter writer = new StreamWriter(fs))
{
NotesMimeEntity mimeEntity = notesDocument.GetMIMEEntity();
if (mimeEntity != null)
GetMIME(writer, mimeEntity);
}
}

Categories