F Sharp Programming/Input and Output
F# : Basic I/O |
Input and output, also called I/O, refers to any kind of communication between two hardware devices or between the user and the computer. This includes printing text out to the console, reading and writing files to disk, sending data over a socket, sending data to the printer, and a wide variety of other common tasks.
This page is not intended to provide an exhaustive look at .NET's I/O methods (readers seeking exhaustive references are encouraged to review the excellent documentation on the System.IO namespace on MSDN). This page will provide a cursory overview of some of the basic methods available to F# programmers for printing and working with files.
Working with the Console
[edit | edit source]With F#
[edit | edit source]By now, you're probably familiar with the printf
, printfn
, sprintf
and its variants in the Printf module. However, just to describe these methods more formally, these methods are used for printf-style printing and formatting using %
markers as placeholders:
Print methods take a format string and a series of arguments, for example:
> sprintf "Hi, I'm %s and I'm a %s" "Juliet" "Scorpio";;
val it : string = "Hi, I'm Juliet and I'm a Scorpio"
Methods in the Printf
module are type-safe. For example, attempting to use substitute an int
placeholder with a string results in a compilation error:
> sprintf "I'm %i years old" "kitty";;
sprintf "I'm %i years old" "kitty";;
---------------------------^^^^^^^^
stdin(17,28): error FS0001: The type 'string' is not compatible with any of the types
byte,int16,int32,int64,sbyte,uint16,uint32,uint64,nativeint,unativeint, arising from
the use of a printf-style format string.
According to the F# documentation, %
placeholders consist of the following:
%[flags][width][.precision][type]
[flags] (optional)
Valid flags are:
- 0: add zeros instead of spaces to make up the required width
- '-': left justify the result within the width specified
- '+': add a '+' character if the number is positive (to match a '-' sign for negatives)
- ' ': add an extra space if the number is positive (to match a '-' sign for negatives)
[width] (optional)
The optional width is an integer indicating the minimal width of the result. For instance, %6d prints an integer, prefixing it with spaces to fill at least 6 characters. If width is '*', then an extra integer argument is taken to specify the corresponding width.
- any number
- '*':
[.precision] (optional)
Represents the number of digits after a floating point number.
> sprintf "%.2f" 12345.67890;;
val it : string = "12345.68"
> sprintf "%.7f" 12345.67890;;
val it : string = "12345.6789000"
[type] (required)
The following placeholder types are interpreted as follows:
%b: bool, formatted as "true" or "false" %s: string, formatted as its unescaped contents %d, %i: any basic integer type formatted as a decimal integer, signed if the basic integer type is signed. %u: any basic integer type formatted as an unsigned decimal integer %x, %X, %o: any basic integer type formatted as an unsigned hexadecimal (a-f)/Hexadecimal (A-F)/Octal integer %e, %E, %f, %F, %g, %G: any basic floating point type (float,float32) formatted using a C-style floating point format specifications, i.e %e, %E: Signed value having the form [-]d.dddde[sign]ddd where d is a single decimal digit, dddd is one or more decimal digits, ddd is exactly three decimal digits, and sign is + or - %f: Signed value having the form [-]dddd.dddd, where dddd is one or more decimal digits. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision. %g, %G: Signed value printed in f or e format, whichever is more compact for the given value and precision. %M: System.Decimal value %O: Any value, printed by boxing the object and using it's ToString method(s) %A: Any value, printed by using Microsoft.FSharp.Text.StructuredFormat.Display.any_to_string with the default layout settings %a: A general format specifier, requires two arguments: (1) a function which accepts two arguments: (a) a context parameter of the appropriate type for the given formatting function (e.g. an #System.IO.TextWriter) (b) a value to print and which either outputs or returns appropriate text. (2) the particular value to print %t: A general format specifier, requires one argument: (1) a function which accepts a context parameter of the appropriate type for the given formatting function (e.g. an #System.IO.TextWriter)and which either outputs or returns appropriate text. Basic integer types are: byte,sbyte,int16,uint16,int32,uint32,int64,uint64,nativeint,unativeint Basic floating point types are: float, float32
Programmers can print to the console using the printf
method, however F# recommends reading console input using the System.Console.ReadLine()
method.
With .NET
[edit | edit source].NET includes its own notation for format specifiers. .NET format strings are untyped. Additionally, .NET's format strings are designed to be extensible, meaning that a programmer can implement their own custom format strings. Format placeholders have the following form:
{index[, length][:formatString]}
For example, using the String.Format
method in fsi:
> System.String.Format("Hi, my name is {0} and I'm a {1}", "Juliet", "Scorpio");;
val it : string = "Hi, my name is Juliet and I'm a Scorpio"
> System.String.Format("|{0,-50}|", "Left justified");;
val it : string = "|Left justified |"
> System.String.Format("|{0,50}|", "Right justified");;
val it : string = "| Right justified|"
> System.String.Format("|{0:yyyy-MMM-dd}|", System.DateTime.Now);;
val it : string = "|2009-Apr-06|"
See Number Format Strings, Date and Time Format Strings, and Enum Format Strings for a comprehensive reference on format specifiers for .NET.
Programmers can read and write to the console using the System.Console class:
open System
let main() =
Console.Write("What's your name? ")
let name = Console.ReadLine()
Console.Write("Hello, {0}", name)
main()
System.IO Namespace
[edit | edit source]The System.IO namespace contains a variety of useful classes for performing basic I/O.
Files and Directories
[edit | edit source]The following classes are useful for interrogating the host filesystem:
- The System.IO.File class exposes several useful members for creating, appending, and deleting files.
- System.IO.Directory exposes methods for creating, moving, and deleting directories.
- System.IO.Path performs operations on strings which represent file paths.
- System.IO.FileSystemWatcher which allows users to listen to a directory for changes.
Streams
[edit | edit source]A stream is a sequence of bytes. .NET provides some classes which allow programmers to work with streams including:
- System.IO.StreamReader which is used to read characters from a stream.
- System.IO.StreamWriter which is used to write characters to a stream.
- System.IO.MemoryStream which creates an in-memory stream of bytes.