UPI Study › Courses › C++ Programming › Free lessons › Lesson 10.2 Free with a free account
Decimal and Text in File Streams
C++ Programming · Chapter 10: File Access and MemorySection 10.2 · lesson 70 of 84video coming soon
← Non-Sequential File AccessNext lesson: Designing a File-Driven Record System →
In this lesson
Precision and formatting concerns.
- Weigh text storage against raw bytes
- Write a double so it reads back exactly
- Choose a delimiter, and avoid the getline trap
- Convert text fields back to numbers with a check
Transcript
Everything said in the video, section by section (1,744 words). Read along, or search it.
Opening Problem
Round Trips Can Silently Lose Data
Writing a number to a file converts it into characters. Reading it back converts those characters into a number again. Neither step is guaranteed to be lossless, and by default, it isn't. A value can leave your program, be written, be read back, and no longer be the value you started with, with nothing anywhere reporting a problem. This section is about controlling that round trip deliberately.
Two Approaches
Text Versus Binary Storage of Doubles
A double in memory is eight bytes with a fixed meaning. There are two quite different things a program can do with it. Text storage converts the value into the characters a person would write, and stores those. Binary storage copies the eight bytes exactly as they sit in memory. Written a thousand times each way, the binary file is exactly eight thousand bytes. The text file here is more than twice the size, because a value like one seventh needs nineteen characters plus a line ending.
Trade-offs
Weighing Readability Against Exactness
Text is readable by a person, and highly portable: any machine, any language, any tool. Its fidelity is only as good as the precision you request. Binary is meaningless without a program that knows the layout, and type widths and byte order differ between machines. But binary is exact, and its size is predictable. That text fidelity is recoverable, which is why text is the default choice for most work. Binary suits bulk numbers for your own program. Text suits configuration, reports, and shared data.
The Problem
Default Precision Corrupts Point One Plus Point Two
Here's the problem in its clearest form. A value is computed, zero point one plus zero point two, written to a file, and read straight back. The file contains zero point three. Not because anything went wrong, but because a stream's default precision is six significant digits, the same display setting as on the screen. Six digits was plenty to display the value. It wasn't enough to reconstruct it. In memory, it's zero point three zero zero, and then a four, out at the seventeenth digit. Read back, it's zero point two nine nine, nine nine. They don't match. And nothing reported this. The write succeeded, the read succeeded, and the program now holds a different number. Repeat the cycle, loading, adjusting and saving, and the drift compounds.
The Fix
Writing Enough Digits for Exact Recovery
Now follow the round trip. With the default precision, the value is written as zero point three, and read back as something slightly different. The loss happens at the moment of writing. With enough digits, the file holds all seventeen, and the value read back is exactly the original. Run the second call and the match is exact. Reading isn't at fault in either case. It faithfully reconstructs whatever the file actually holds. The number of digits needed isn't a guess. The library states it: numeric limits of double, max digits ten. That's seventeen for every double, on any conforming implementation. Write the name rather than the literal seventeen, so the code stays correct if the type ever changes.
Digit Counts
Three Easily Confused Digit Settings
Three digit counts are easily confused. Max digits ten is how many digits to write so a value can be read back exactly: seventeen for a double. That's the one for saving data. Digits ten is how many decimal digits a value can carry reliably: fifteen for a double. That's the honest precision of the type. And the stream default of six is neither of those. It's a display setting, chosen because six digits is comfortable to read. That makes it a perfectly sensible default for a screen, and a poor one for a file.
Quick Check
Digits Needed to Save Floats
Quick check. A program saves float values, not doubles, and must reload them exactly. How many digits does it need to write? Pause and think. Nine. Seventeen is the figure for a double; it would still work, but it's more than a float needs. Max digits ten of float reports nine, so writing the name gets it right automatically.
Fixed Decimals
Fixing Decimal Places for Meaningful Data
Seventeen digits in every field makes a file large and hard to read, and for a lot of data, it's pointless. A price, a temperature, or a percentage has nowhere near seventeen meaningful digits. For those, fix the number of decimal places instead. With fixed and a precision of two, the file holds zero point three zero. That doesn't round-trip exactly, and that's the correct outcome. The file says what the value means, thirty paise, rather than what the machine happens to hold. And the manipulators are sticky here too. Set them once on the file stream, before the first value. A setting applied to c out doesn't apply to your file. Each stream carries its own.
Decision Guide
Matching Precision to the File's Reader
So the choice depends on who the file is for. For your own program to reload, write max digits ten, so reloading gives back the same value. For money, exactly two decimal places, or better, hold whole paise. For measurements, the instrument's precision, so the file doesn't state precision the data lacks. And for a person to read, fixed, with a few digits. Readability is the point.
Common Failure
When a Delimiter Appears Inside Data
A file holding more than one value per record needs a delimiter between them. Choosing it badly causes a specific, common failure. Here's a comma-separated file in which one field legitimately contains a comma: Pune comma M H, in quotation marks. The third line splits into four fields, because the delimiter appeared inside a value. The quotation marks mean something to a person, and nothing to a splitter that only knows about commas. And on the second line, the age arrived as space thirty-seven, with a leading space. A space after the comma is invisible to the eye, and part of the field to the program.
Comparing Options
The Cost of Each Delimiter
Every delimiter has a cost. A comma fails when a field contains a comma, which is common in names, addresses and free text. Its real advantage is that other tools universally understand it, but it needs quoting rules to be safe. A tab fails only when a field contains a tab, which is rare in typed data. A pipe is rarer still. And one field per line can't collide at all.
Safeguards
Three Ways to Protect a Delimiter
There are three ways to make a delimiter safe. Choose one the data can't contain, which removes the problem rather than managing it. Reject values containing it at the point of writing, so the fault is reported then, not discovered months later. And trim leading and trailing whitespace from every field you read.
Common Mistake
Mixing Extraction and Get Line
Two ways of reading text behave quite differently around whitespace, and mixing them produces one of the most reported puzzles in the language. The extraction operator skips leading whitespace, reads until the next whitespace, and leaves that whitespace in the stream. Get line reads everything up to the line ending, keeps the spaces, and discards the line ending. Take a file whose first line is Anya Sharma. Read with extraction alone, the name is just Anya, and the age read fails, because it tried to read Sharma as a number. Read with get line, then extraction, both work. But extraction followed by get line gives space Sharma: the rest of the same line, not the next one. The usual form is worse. When extraction reads the last item on a line, the very next get line finds the leftover line ending immediately, and returns an empty string. The program appears to skip a line.
Rules
Avoiding the Whitespace Trap
Two rules avoid it entirely. Don't mix the two on one stream. Read whole lines with get line and split them yourself, or read item by item with extraction. Choosing one and staying with it removes the problem, rather than working around it. If you must mix, discard the rest of the line after the last extraction, before calling get line. Reaching for that second rule repeatedly is a sign the first rule was the right one.
Conversion Risks
Why A T O F Hides Bad Fields
Once a line has been split, each field is text. Converting one to a number is where, quietly, a file of slightly wrong data becomes a program of slightly wrong results. Compare two functions. On forty-two point five, both give forty-two point five. On forty-two point five k g, both give forty-two point five, but S T O D also tells you how much of the text it used. On a b c, or on an empty field, S T O D throws an exception. A T O F returns zero. And zero is a perfectly ordinary value. So a corrupted field becomes a zero that flows into the rest of the program, indistinguishable from a real one. On a number too large to represent, S T O D throws. The standard promises nothing about A T O F there, and here it handed back infinity.
Safe Practice
Checking How Much S T O D Used
So convert with a check. Pass S T O D a variable to receive how many characters it used. If that isn't the whole field, something was left over, so treat it as a bad field. S T O D reports outright failure by throwing an exception. And the count answers a question the older function can't. It catches forty-two point five k g: text that converts successfully, and still isn't what the field was supposed to contain.
Key Terms
Vocabulary for Text and Binary Storage
A few key terms. Text storage stores a value as the characters that spell it. Binary storage stores its bytes exactly as they sit in memory. A round trip is writing a value out and reading it back. It's exact when the value returns unchanged. Max digits ten is the number of digits to write for an exact read-back, seventeen for a double. Digits ten is how many a type carries reliably, fifteen. A delimiter separates fields, and trimming removes whitespace around one. And a checked conversion turns text into a number by a means that reports failure.
Think About It
What Lands in the Name
Here's something to think about. One line of a file reads forty-two, then Anya Sharma. A program reads the age with extraction, then the name with get line. What ends up in the name? Pause and think. Space Anya Sharma, with a leading space. Extraction stopped right after forty-two, so get line took the rest of that same line, space included.
Key Takeaways
Summary of Safe File Practices
To summarize. Text storage is readable and portable. Binary storage is exact and compact. The default six digits loses data, so write max digits ten when your program will reload the values. Use fixed decimals when the data means a set precision. Choose a delimiter the data can't contain, and trim every field you read. Don't mix extraction and get line on one stream, and convert with S T O D, checking how much it used.
About C++ Programming at UPI Study
C++ Programming (Computer Science 242) is a self-paced online course of 84 video lessons in 11 chapters, from your first program to decisions, loops, arrays, functions, classes, files, pointers and inheritance. It carries a NCCRS credit recommendation for 3 semester credits.
Every lesson transcript is free on pages like this one, and the videos are free with a free UPI Study account. Enrolling adds a practice quiz after each lesson, the graded work and final exam that earn the credit, lifetime access, and an official transcript on completion. UPI Study has helped over 130,000 students with college credits. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Enroll now → Course details Download the syllabus Every course with PRO →
Why take it here
Why students take C++ Programming with UPI Study
Where the credit goes
Universities that work with NCCRS
C++ Programming carries a NCCRS credit recommendation. These universities work with NCCRS; some are UPI Study's signed partners. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Thomas Edison State UniversitySigned partner
University of the PeopleSigned partner
Charter Oak State CollegeSigned partner
Strayer UniversitySigned partner
Columbia Southern UniversitySigned partner
Indiana TechSigned partner
Penn StateWorks with NCCRS
Southern New Hampshire UniversityWorks with NCCRS
SUNYWorks with NCCRS
+many more cooperating universitiesFind my college →Find my college → Not listed? Ask Athena in the corner of this page, or book a 15-minute call.
FAQ
Questions students ask us
About Decimal and Text in File Streams
How do I write a double to a file in C++ so it reads back exactly?
What is the difference between text and binary storage of a double in a file?
Why does getline return an empty string after cin >> in C++?
How do I convert a string field to a double in C++ and detect bad input?
About the C++ Programming course
How many college credits is C++ Programming?
How much does C++ Programming cost and what is included?
Which universities accept UPI Study credits?
How long does C++ Programming take?
How are the exams done?
How do my credits reach my college?
Ready for the full course? Earn 3 credits in C++ Programming.
84 video lessons, a quiz after each one, and the graded work that earns the credit. Recommended for credit by NCCRS.
3 credits · NCCRSEnroll →