How to avoid extra line feeds in MIME export? - xpages

I'm exporting MIME eMails with the following code:
public String fromRawMime(final Session s, final Document doc) throws NotesException {
final Stream notesStream = s.createStream();
final MIMEEntity rootMime = doc.getMIMEEntity();
// check if it is multi-part or single
if (rootMime.getContentType().equals("multipart")) {
this.printMIME(rootMime, notesStream);
} else {
// We can just write the content into the
// Notes stream to get the bytes
rootMime.getEntityAsText(notesStream);
}
// Write it out
notesStream.setPosition(0);
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.append(notesStream.read());
notesStream.close();
notesStream.recycle();
rootMime.recycle();
return out.toString();
}
// Write out a mime entry to a Stream object, includes sub entries
private void printMIME(final MIMEEntity mimeRoot, final Stream out) throws NotesException {
if (mimeRoot == null) {
return;
}
// Encode binary as base64
if (mimeRoot.getEncoding() == MIMEEntity.ENC_IDENTITY_BINARY) {
mimeRoot.decodeContent();
mimeRoot.encodeContent(MIMEEntity.ENC_BASE64);
}
out.writeText(mimeRoot.getBoundaryStart(), Stream.EOL_NONE);
mimeRoot.getEntityAsText(out);
out.writeText(mimeRoot.getBoundaryEnd(), Stream.EOL_NONE);
if (mimeRoot.getContentType().equalsIgnoreCase("multipart")) {
// Print preamble if it isn't empty
final String preamble = mimeRoot.getPreamble();
if (!preamble.isEmpty()) {
out.writeText(preamble, Stream.EOL_NONE);
}
// Print content of each child entity - recursive calls
// Include recycle of mime elements
MIMEEntity mimeChild = mimeRoot.getFirstChildEntity();
while (mimeChild != null) {
this.printMIME(mimeChild, out);
final MIMEEntity mimeNext = mimeChild.getNextSibling();
// Recycle to ensure we don't bleed memory
mimeChild.recyle();
mimeChild = mimeNext;
}
}
}
The result contains one empty line for each line. Including the content that gets added using getEntityAsText. What am I missing to get rid of the extra lines?

The email RFCs require the use of CRLF to terminate text lines.
You are using EOL_NONE, so the writeText method isn't adding anything to the text, but apparently both the CR and LF are being treated as newlines in your output. You may want to try using out.writeText with EOL_PLATFORM instead.

The devils is in the details...
the printMIME function works just fine. Changing the EOL didn't have an impact. However I added EOL_PLATFORM later on for the final result to separate the headers from the content.
The offending code is this:
notesStream.setPosition(0);
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.append(notesStream.read());
notesStream.close();
Turns out that it seems to interpret whatever was in the MIME as 2 line feeds. So the code needs to be changed to:
notesStream.setPosition(0);
String out = notesStream.readText();
notesStream.close();
so instead of a OutputStream I needed a String and instead of read() I needed readText(). Now working happily in my "project castle"

Related

Best way to export CSV string through JSON via WebAPI?

Have been stringbuilding CSV files for ages on MVC applications just fine, until now.
One mistake made me generate a CSV string bigger then the system can handle in memory, so i have been searching the web for any solution on minifing a string that could be reconstructed back on client.
So far i have been doing this:
StringBUilder sb = new StringBuilder();
foreach(stuff in manyEnumerableStuff)
sb.Append(stuff);
return csv.ToString().ToBase64();
public static string ToBase64(this string value) => Convert.ToBase64String(Encoding.Default.GetBytes(value));
The application can handle .ToString() in this HUGE case just "fine", but it fails without creating excpetions at .ToBase64String(Encoding.Default.GetBytes(value));
This only happens on huge strings because from what i know, base64 will make the string 33% bigger.
Compressed json can't solve this problem, since this happens on server side.
So I have gonne on search to minify or compress this string, but it still need to be a string and can be converted on client site Angular application.
I have found this:
public static string compress(this string big) {
var bytes = Encoding.Default.GetBytes(big);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream()) {
using (var gs = new GZipStream(mso, CompressionMode.Compress)) {
//msi.CopyTo(gs);
CopyTo(msi, gs);
}
return mso.ToArray().ToString();
}
}
private static void CopyTo(Stream src, Stream dest) {
byte[] bytes = new byte[4096];
int cnt;
while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) {
dest.Write(bytes, 0, cnt);
}
}
but I think there is no sense at all, because i can't put byte[] on json value as string without converting it back.
Is it possible to compress plain Pipe separated values that represents a .CSV file after getting the string from StringBuilder()?
I have tried GC.collect() right after parsing SB to string but still broke the application.
I'm on .Net Core 2.1, Linux server.

BufferedReader is sometimes empty

I have Loader class where I load txt file into BufferedReader from resources and return this field. I use this method but it acts really strange(for me). When I don't put
String str = bufferReader.readLine(); after
bufferReader = new BufferedReader(fileReader);
(in Loader class) than bufferReader in another class is empty, and readLine() returns null. When I write that piece of code in Loader class, I can read each line from txt, except the 1. one which is read in Loader class. Also, I can't read last line if I dont put enter at the end.
public BufferedReader loadFromFileToBufferReader(String fileName) {
ClassLoader classLoader = getClass().getClassLoader();
System.out.print(getClass().getClassLoader().getResource("resources/" + fileName));
File file = new File(classLoader.getResource("resources/" + fileName).getFile());
BufferedReader bufferReader = null;
try (FileReader fileReader = new FileReader(file)) {
bufferReader = new BufferedReader(fileReader);
String str = bufferReader.readLine();
} catch (IOException e) {
System.err.println("Something went terribly wrong with file reading");
}
return bufferReader;
}
and usage:
public Database() {
productsInDatabse = new ArrayList<>();
codesList = new ArrayList<>();
loader = new LoadFromFile();
BufferedReader output = loader.loadFromFileToBufferReader("database.txt");
Product product;
String line;
String[] array;
try {
line = output.readLine();
while (line != null) {
You should paste your code here because it's hard to deduce all the possible causes of this without seeing the code on 100% but I am guessing you have it the same file open at the same time from multiple sources without closing it before from one? Could be literally millions of little things, just telling you how the same error happened to me.

Getting Values out of a String with patterns

I have textfiles, which have attributes saved in Strings. Those Strings have a pattern like this:
[attributeName]:[value]
I can't generalize the [value], because it could be of any primitive datatype.
Saving the effectively values is not my concern, because it's depending on the user which attribute has to be loaded. The same file won't be loaded very often.
Now I have 2 problems:
1) For some reason the program which creates those files sometimes adds spaces around the : at some attributes and [value] could also contain spaces, so I have to get rid of those
2) Making the reading of those attributes more performant:
I've come up with this method:
public String getAttribute(File file, String attribute)
{
try
{
BufferedReader reader = new BufferedReader(new FileReader(file), 1024);
String line;
Pattern p = Pattern.compile(Pattern.quote(attribute), Pattern.CASE_INSENSITIVE);
while ((line = reader.readLine()) != null)
{
int i = line.indexOf(":");
if(line.charAt(i-1) == ' ')
line = line.substring(0,i-2) + line.substring(i);
if(line.charAt(i+1) == ' ')
line = line.substring(0,i) + line.substring(i+2);
if (p.matcher(line).find())
{
return line.replace(attribute, "").trim();
}
}
} catch (IOException e)
{
e.printStackTrace();
}
return null;
}
However, this method will probably be one of the most called by my application, so I can't leave it so unperformant as it is right now,
Thanks for any help!
I modified code to find appropriate line. Check example code below.
If you have a lot of files and attributes in these files you could think about saving somewhere pair attribute=value in code. In example code I provided very primitive cache by using Table interface from guava library.
Example code:
# guava library
import com.google.common.collect.Table;
import com.google.common.collect.HashBasedTable;
# apache commons lang
import static org.apache.commons.lang.StringUtils.startsWithIgnoreCase;
# apache commons io
import static org.apache.commons.io.IOUtils.closeQuietly;
[...]
# very primitive cache implementation. To find a value in table you have to
# pass row and column keys. In this implementation row is equal to file
# absolute path (because you can have 2 files with the same name) and column
# is equal to attribute name.
# If you have a lot of files and attributes probably you will have to clear
# from time to time the cache otherwise you will get out of memory
private static final Table<String, String, String> CACHE = HashBasedTable.create();
[...]
public String getAttribute(File file, String attribute) {
# get value for the given attribute from the given file
String value = CACHE.get(file.getAbsolutePath(), attribute);
# if cache does not contain value, method will read value from file
if (null == value) {
BufferedReader reader = null;
String value = null;
try {
reader = new BufferedReader(new FileReader(file), 1024);
String line;
while ((line = reader.readLine()) != null) {
# From your description I understood that each line in file
# starts with attribute name
if (startsWithIgnoreCase(line, attribute) {
# if we found correct line we simple split it by ':'
String[] array = line.split(":");
# this is to ensure that line contains attribute name
# and value
if (array.length >= 2) {
# we found value for attribute and we remove spaces
value = array[1].trim();
# we put value to the cache to speed up finding
# value for the same attribute in the future
CACHE.put(file.getAbsolutePath(), attribute, value);
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
# you should always close
closeQuietly(reader);
}
}
return value;
}

Streamwriter and Streamreader

I have my uni assignment and it's only very basic coding but I have to do
A user shall be able to store records to a file. On start-up a user shall be able to select a file of records and load these into the program.
I am having trouble with this as it will save but once I close the program and re-open it they are gone, any ones help is appreciated.
This is what I have so far:
private void Save_Click(object sender, EventArgs e)
{
SaveToFile(records, file);
}
private void SaveToFile(List<Client> records, string file)
{
//File.WriteAllText(file, String.Empty);
StreamWriter writer = new StreamWriter(file);
StreamReader reader = new StreamReader(file);
try
{
AddMember();
for (int i = 0; i < records.Count; i++)
{
writer.WriteLine(records[i].WriteToFile());
}
writer.Close();
}
catch (IOException z)
{
MessageBox.Show("Error" + z);
}
}
Before closing the StreamWriter you should call Flush() method. Flush() Clears all buffers for the current writer and causes any buffered data to be written to the underlying stream.
reader.clos();
you forgot this
This is just a guess, but it sounds like you might be overwriting the file when you start the program.
In your SaveToFile method, you have the following two lines at the start:
StreamWriter writer = new StreamWriter(file);
StreamReader reader = new StreamReader(file);
The first one will create a new file with the name in file. The second one isn't needed if you're not doing any reading from the file.
Now, if you have a similar block of code in somewhere else in your program that is executed before the SaveToFile method is called, it will overwrite the file (and since you most likely don't write anything in that earlier part of the code, you're left with a blank file).
To prevent this, there are two suggestions I'll offer:
Only create a StreamWriter when you are going to be writing to the file. Any other times you create a StreamWriter, you will be overwriting the existing file.
If you don't want to overwrite the file, you can use the overload of the constructor that takes a second parameter (a boolean) to indicate whether or not to append new data to the file:
StreamWriter writer = new StreamWriter(file, true);
Additionally, I'd suggest getting to know and use using blocks, as this will take care of closing and flushing the StreamWriter (and its underlying stream) for you, even if an exception occurs and is unhandled:
private void SaveToFile(List<Client> records, string file)
{
try
{
AddMember();
// If you don't want to append but overwrite, use:
// using (StreamWriter writer = new StreamWriter(file))
using (StreamWriter writer = new StreamWriter(file, append))
{
for (int i = 0; i < records.Count; i++)
{
writer.WriteLine(records[i].WriteToFile());
}
}
}
catch (IOException z)
{
MessageBox.Show("Error" + z);
}
}

Add a string property to a linklabel?

I am currently making an "app launcher" which reads a text file line by line. Each line is a path to a useful program somewhere else on my pc. A link label is automatically made for each path (i.e. each line) in the text file.
I would like the .Text property of the link label to be an abbreviated form of the path (i.e. just the file name, not the whole path). I have found out how to shorten the string in this way (so far so good !)
However, I would also like to store the full path somewhere - as this is what my linklabel will need to link to. In Javascript I could pretty much just add this property to linklabel like so: mylinklabel.fullpath=line; (where line is the current line as we read through the text file, and fullpath is my "custom" property that I would like to try and add to the link label. I guess it needs declaring, but I am not sure how.
Below is the part of my code which creates the form, reads the text file line by line and creates a link label for the path found on each line:
private void Form1_Load(object sender, EventArgs e) //on form load
{
//System.Console.WriteLine("hello!");
int counter = 0;
string line;
string filenameNoExtension;
string myfile = #"c:\\users\matt\desktop\file.txt";
//string filenameNoExtension = Path.GetFileNameWithoutExtension(myfile);
// Read the file and display it line by line.
System.IO.StreamReader file = new System.IO.StreamReader(myfile);
while ((line = file.ReadLine()) != null)
{
//MessageBox.Show(line); //check whats on each line
LinkLabel mylinklabel = new LinkLabel();
filenameNoExtension = Path.GetFileNameWithoutExtension(line); //shortens the path to just the file name without extension
mylinklabel.Text = filenameNoExtension;
//string fullpath=line; //doesn't work
//mylinklabel.fullpath=line; //doesn't work
mylinklabel.Text = filenameNoExtension; //displays the shortened path
this.Controls.Add(mylinklabel);
mylinklabel.Location = new Point(0, 30 + counter * 30);
mylinklabel.AutoSize = true;
mylinklabel.VisitedLinkColor = System.Drawing.Color.White;
mylinklabel.LinkColor = System.Drawing.Color.White;
mylinklabel.Click += new System.EventHandler(LinkClick);
counter++;
}
file.Close();
}
So, how can I store a full path as a string inside the linklabel for use in my onclick function later on?
You could derive a new custom class or you could use a secondary data store for your additional info the easiest solution would be to use a dictionary.
dictonary<string,string> FilePaths = new dictonary<string,string>();
private void Form1_Load(object sender, EventArgs e) //on form load
{
...
FilePath[filenameNoExtension] = line;
}
You Can Access the Path
FilePath[mylinklabel.Tex]
One option you have is to have a method that truncates your string (and even adds "..."). You can then store the full path in the Tag property of the Linklabel. And here's an example of the first part (truncating the text).
public static string Truncate(this string s, int maxLength)
{
if (string.IsNullOrEmpty(s) || maxLength <= 0)
return string.Empty;
else if (s.Length > maxLength)
return s.Substring(0, maxLength) + "...";
else
return s;
}
Hope that helps some

Resources