=== Top of the Swiki === Attachments ===

Recipe: Doing Something to Each Line in a File

Problem

You want to process a text file line by line. You don't want to worry about different line end characters in different operating systems.

Solution

Use a CrLfFileStream as follows

| inputStream aLine |

inputStream := (CrLfFileStream readOnlyFileNamed: 'data.txt') ascii.

[inputStream atEnd] whileFalse: [

aLine := inputStream upTo: (Character cr).

"Do something with aLine"

]


The Cr is not part of aLine and empty lines will give an empty string in aLine.

Discussion

The CrLfFileStream does its job in a platform independent way. The CrLfFileStream>>next method makes every file look as if its lines were terminated by a Cr. Since upTo: is implemented in terms of next, you can use Cr as the universal line delimiter across all platforms.

If you want to swallow the file at once, use

(FileStream readOnlyFileNamed: 'data.txt') contentsOfEntireFile.


Wannabe Squeaker Questions:


  1. Why is all input from standard file classes character oriented? Seems like it would be useful to have a file class where you could loop through line-by-line without having to code something like the above each time.
  2. From a standard practices point-of-view, if I wanted to implement line-by-line read, would it be best to create a new file subclass and override the next method to return line stings, add a new nextLine method to a standard file class, or to create a new subclass AND a new selector?

See also

Regular Expressions in Squeak if you want to do more complicated things to each line.