How to read and write a simple file

We’ll use a couple of simple scripts from the Python Samples folder as examples - we’ll dissect these to see how they work.

Here is the import-points.py script

# Import points from a text file
import rhinoscriptsyntax as rs

def ImportPoints():
#prompt the user for a file to import
filter = "Text file (*.txt)|*.txt|All Files (*.*)|*.*||"
filename = rs.OpenFileName("Open Point File", filter)
if not filename: return

#read each line from the file
file = open(filename, "r")
file.close()

# local helper function
def __point_from_string(text):
items = text.strip("()\n").split(",")
x = float(items)
y = float(items)
z = float(items)
return x, y, z

contents = [__point_from_string(line) for line in contents]

##########################################################################
# Check to see if this file is being executed as the "main" python
# script instead of being used as a module by some other python script
# This allows us to use the module which ever way we want.
if( __name__ == "__main__" ):
ImportPoints()


We’ve put the action inside a function in this script, the

def ImportPoints()


section. This allows the code to be re-used and simplifies error checking. The first part uses the rs function

rs.OpenFileName()


to allow the user to specify a file to open, and sets a variable ‘filename’ to hold this information:

filename = rs.OpenFileName("Open Point File", filter)


with a filter for text files.

If for some reason the user does not specify a file, say with a Cancel, then the line

if not filename: return


ensures that the rest of the code inside this particular function will not be run, since there is nothing that can be done without a file name, and executing the next lines in the script will result in error messages without it. Since there is only the one function in this script, a cancel means the script will stop.

Next a variable is set to the open file for reading:

file = open(filename, "r")


and a variable is set to the contents of the file which is then held in memory as a list with one item per line:

contents = file.readlines()


The file is then closed:

python file.close()


At this point in the script, a new function is added, called __point_from_string(text) , inside the main function, that parses text in the expected format and converts the text into three numbers and returns those as the xy,z coordinates of a point.

The list of lines from the orignal text file is fed into this function, line by line to create a list of points, by calling that function:

contents = [__point_from_string(line) for line in contents]


Lastly, the points in the list are added to the Rhino document as point objects:

rs.AddPoints(contents)


Note all if this code will not actually run unless the function is called - this is done from the very last line of the script:

if( __name__ == "__main__" ):
ImportPoints()


## Writing a file

Writing a file is similar to reading, but the order in which things are done is different. This time we’ll look at the ExportPoints.py sample file.

import rhinoscriptsyntax as rs

#Get the points to export
objectIds = rs.GetObjects("Select Points",1+2, True, True)
if( objectIds==None ): return

#Get the filename to create
filter = "Text File (*.txt)|*.txt|All Files (*.*)|*.*||"
filename = rs.SaveFileName("Save point coordinates as", filter)
if( filename==None ): return

with open(filename, "w") as file:
# treat the objects differently depending on whether they are points or point clouds
for id in objectIds:
#process point clouds
if( rs.IsPointCloud(id) ):
points = rs.PointCloudPoints(id)
for pt in points:
file.write(str(pt)+"\n")
elif( rs.IsPoint(id) ):
point = rs.PointCoordinates(id)
file.write(str(point) + "\n")



There are a couple of things to notice, compared to the previous example. We need some points to export, so we’ll let the user select some point objects and point clouds. There is a filter applied to the selection, the 1+2. 1 filters for point objects and 2 filters for point clouds - we can add the filters together to make combinations such as we have here - 1+2 or, we could have written just 3, that would work as well, it is just harder to parse when reviewing or modifying the code:

objectIds = rs.GetObjects("Select Points", 1+2, True, True)


As before we check to make sure that the user has in fact selected the things we’re looking for.

if( objectIds==None ): return


Next we’ll get a file name as in the first example:

#Get the filename to create
filter = "Text File (*.txt)|*.txt|All Files (*.*)|*.*||"
filename = rs.SaveFileName("Save point coordinates as", filter)
if( filename==None ): return


When writing to a file it must first be opened. While it is open, the information can be written to the file. After writing all the information, the file must be closed. In the first example we explicitly opened, read and then closed the file. This time we’ve used the with statement to open the file - with is convenient because it takes care of closing the file and cleaning up when the script leaves the indented with section.

with open(filename, "w") as file:
# treat the objects differently depending on whether they are points or point clouds
for id in objectIds:
#process point clouds
if( rs.IsPointCloud(id) ):
points = rs.PointCloudPoints(id)
for pt in points:
file.write(str(pt)+"\n")
#process point objects
elif( rs.IsPoint(id) ):
point = rs.PointCoordinates(id)
file.write(str(point) + "\n")
​

Keep in mind that 'points' in the script are not the same as 'point objects' in the Rhino file. Points are a list of x,y,z coordinates and point objects are objects in the Rhino file that have, among other properties like display color or layer, a location - the point coordinates.  As you can see in the above, the script iterates a list of IDs -those of the selected point objects or point clouds, and extracts the x,y,z coordinates to write to the file. The exported points are only the x,y,z coordinates of the point objects.

For more information on reading and writing from Python, see the [Python Methods in File Objects documentation](https://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects)

`
{"ft_lang_label":"__label__en","ft_lang_prob":0.80404675,"math_prob":0.7042033,"size":6316,"snap":"2023-40-2023-50","text_gpt3_token_len":1466,"char_repetition_ratio":0.14401141,"word_repetition_ratio":0.13273454,"special_character_ratio":0.25459152,"punctuation_ratio":0.12601626,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.95077026,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2023-10-05T03:48:46Z\",\"WARC-Record-ID\":\"<urn:uuid:e83be7af-cbf6-4fa7-ab3e-80df7b911398>\",\"Content-Length\":\"33374\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:99706028-e733-4584-ab84-0f02f24ca19a>\",\"WARC-Concurrent-To\":\"<urn:uuid:011e0bf9-957c-4a2f-9c6c-a6614531270b>\",\"WARC-IP-Address\":\"18.165.98.124\",\"WARC-Target-URI\":\"https://developer.rhino3d.com/guides/rhinopython/python-reading-writing/\",\"WARC-Payload-Digest\":\"sha1:T4LYR7QTXMLLT7BFLXENRGQV5LWVEJCA\",\"WARC-Block-Digest\":\"sha1:SEQHDH4JKDUQ6CWTMOQL7W6KMHKVE63C\",\"WARC-Identified-Payload-Type\":\"application/xhtml+xml\",\"warc_filename\":\"/cc_download/warc_2023/CC-MAIN-2023-40/CC-MAIN-2023-40_segments_1695233511717.69_warc_CC-MAIN-20231005012006-20231005042006-00045.warc.gz\"}"}