Portable End of Line (Newline)

Portable end of line (newline)

Apologies for the partial overlap with other answers, but for the sake of completeness:

Myth: endl is 'more portable' since it writes the line ending depending on the platform convention.

Truth: endl is defined to write \n to the stream and then call flush. So in fact you almost never want to use it. All \n that are written to a text-mode stream are implicitly converted to \r\n by the CRT behind the scenes, whether you use os<<endl, os<<'\n', or fputs("\n",file).

Myth: You should open files in text mode to write text and in binary mode to write binary data.

Truth: Text mode exists in the first place because some time ago there were file-systems that distinguished between text files and binary files. It's no longer true on any sane platform I know. You can write text to binary-opened files just as well, you just loose the automatic \n -> \r\n conversion on Windows. However, this conversion causes more harm than good. Among others, it makes your code behave differently on different platforms, and tell/seek become problematic to use. Therefore it's best to avoid this automatic conversion. Note that POSIX does not distinguish between binary and text mode.

How to do text: Open everything in binary mode and use the plain-old \n. You'll also need to worry about the encoding. Standardize on UTF-8 for Unicode-correctness. Use UTF-8 encoded narrow-strings internally, instead of wchar_t which is different on different platforms. Your code will become easier to port.

Tip: You can force MSVC to open all files in binary mode by default. It should work as follows:

#include <stdio.h>
#include <iostream>
int main() {
_fmode = _O_BINARY;
std::ofstream f("a.txt"); // opens in binary mode
}

EDIT: As of 2021, Windows 10 Notepad understands UNIX line endings.

Portable end of line

std::endl is defined to do nothing besides write '\n' to the stream and flush it (§27.6.2.7). Flushing is defined to do nothing for a stringstream, so you're left with a pretty way of saying mystringstream << '\n'. The standard library implementation on your OS converts \n appropriately, so that's not your concern.

Thus endl is already the ultimate in performance and portability, and the only other thing you could want is << '\n' if you are trying to efficiently write to a file (not a stringstream). Well, << '\n' does also eliminate the pointless virtual call to stringbuf::flush. Unless profiling shows that empty function call to be taking time, don't think about it.

Portable newline transformation in Java

Use the line.separator system property

String separator = System.getProperty("line.separator") + "#"; // concatenate the character you want
String myPortableString = "#aaa" + separator + "ccc";

These properties are described in more detail here.

If you open the source code for PrintWriter, you'll notice the following constructor:

public PrintWriter(Writer out,
boolean autoFlush) {
super(out);
this.out = out;
this.autoFlush = autoFlush;
lineSeparator = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
}

It's getting (and using) the system specific separator to write to an OutputStream.

You can always set it at the property level

System.out.println("ahaha: " + System.getProperty("line.separator"));
System.setProperty("line.separator", System.getProperty("line.separator") + "#"); // change it
System.out.println("ahahahah:" + System.getProperty("line.separator"));

prints

ahaha: 

ahahahah:
#

All classes that request that property will now get {line.separator}#

What is the most portable/cross-platform way to represent a newline in go/golang?

I got curious about this so decided to see what exactly is done by fmt.Println. http://golang.org/src/pkg/fmt/print.go

If you scroll to the very bottom, you'll see an if addnewline where \n is always used. I can't hardly speak for if this is the most "cross-platform" way of doing it, and go was originally tied to linux in the early days, but that's where it is for the std lib.

I was originally going to suggest just using fmt.Fprintln and this might still be valid as if the current functionality isn't appropriate, a bug could be filed and then the code would simply need to be compiled with the latest Go toolchain.

Portable way to determine the platform's line separator

I'm no C/C++ expert, but there doesn't appear to be anything in the standard library that will directly give you the line separator. The translation is handled transparently by the text-mode file functions.

Even though you feel your approach is "kludgy", it is probably the simplest and most reliable, since you are really testing what line separator is used and written out. And is portable, since you are using standard library functions to write and read the file.

End of the line delimiter conversion between Windows and Linux

You'll have to do it yourself. (IMNO, a good library would do it
automatically, in filebuf, if opened in text mode. But the libraries
I'm familiar with don't.)

Depending on what you're doing, it may not matter. Any line oriented
input should accept trailing white space anyway, and the extra 0x0D
character is white space. So except for editors, it usually won't
matter.

If you want to suppress the extra 0x0D when writing the file (under
Windows), just open the file in binary mode. For that matter, when
portability of the file is a concern, it's often a good idea to open the
file in binary mode, and write whichever convention the protocol
requires. (Using the two character sequence 0x0D, 0x0A is more or less
standard, and is what most Internet protocols specify.) When reading,
again, open in binary mode, and write your code to accept any of the
usual conventions: the two character sequence 0x0D, 0x0A, or either a
single 0x0D or a single 0x0A. (This could be done with a filtering
streambuf.)

std::endl in a string variable?

Don't forget std::endl adds a new line and flushes the buffer.

If you simply want new lines, \n, add them to your string, using + or stream them to a stream, using << '\n'.

For example,

std::string logstring;
logstring = logstring + "Error Message" + "Number" + "Time + Date";
logstring += '\n';


Related Topics



Leave a reply



Submit