Advanced File I/O: Text Files, Binary Files, and Configuration FilesYou've already seen from Chapter 9, "Exploring Strings and File I/O," the most common file I/O functions LabVIEW has to offer. You've seen how to read and write dynamic data types, spreadsheet data, text files, and binary files. You will now learn how to operate on files by reference, performing a sequence of operation and introspection steps, rather than simply reading or writing the file in one fell swoop. This will allow you to achieve some more complex and high-performance use cases. Opening and Closing File ReferencesA file is a set of ordered bytes on your computer disksimilar to the way a string is a set of ordered characters or an array is a set of ordered elements. Because files can be very big, it is often desirable to not read the entire contents of a file into memory all at once, but rather, only read small portions of it (maybe one line at a time) and perform operations based on the data that is read. Most of the functions for writing and reading data to and from files use a refnum (short for "reference number") as a handle to a file that has been opened for writing or reading. By handle, we mean that we are not passing around the data of the file, but rather, something that refers to the open file. You can think of a file refnum like a path to an open fileit is not the data of the file, but something that helps us know where to find the data. The file read and write functions in LabVIEW are polymorphic. You can use them with either file path inputs OR file refnum inputs. In this section, we'll learn how they work if we are using file refnums. To open a refnum to a file, we use the Open/Create/Replace File function (see Figure 14.6). The refnum will be passed out via the refnum out terminal. When we are done writing or reading the file, we will pass the file refnum to the Close File function (see Figure 14.7), to tell LabVIEW that we no longer need access to the file. Figure 14.6. Open/Create/Replace File Figure 14.7. Close File Now that we know how to open and close a file, let's take a look at how to write and read data. Advanced File FunctionsSometimes you'll need to do specific file tasks, such as create directories, change the permissions on a specific file, or delete a file. LabVIEW gives you many more file I/O functions in the Programming>>File I/O>>Advanced File Functions subpalette, shown in Figure 14.8. Figure 14.8. Advanced File Functions palette![]() We won't cover every one of these functions in this chapter, but we'll discuss a few of them next. File PositionThe file marker is a number that tells us the byte offset where you are currently working in a file. The end of file is the offset past (just beyond) the last byte in the file (meaning the end of the file)the end of file is also the file size. When you first open a file, the file marker is set to an initial value of 0, and as you write or read to the file, the marker is moved forward each time by the number of bytes written or read. The file marker helps you by keeping track of where you are in the filethere is no need for you to explicitly specify the position where you want to write or read data (although you can specify the position to read or write, if you wish). Generally, you will start at the beginning of a file and keep writing or reading data contiguously until you reach the end of the filethis is typically referred to as sequential access, as compared to random access (explicitly specifying the position of each read and write operation). For example, if you open a file, the file marker is initialized to 0. Now, if you write 100 characters to the file, the write operation will start at byte 0, and after the write operation, the new value of the file marker will be 100. Then, if you write 50 more characters to the file, the write operation will start at 100 (the current file marker value) and when you are done, the new file marker value will be 150. Pretty easy, isn't it? So, LabVIEW automatically adjusts the file marker as you write or read the file, but if you wish, you can also move the file marker explicitly to any value you like (so that read and write operations will occur in this new location), using the Set File Position function, shown in Figure 14.9. Use the offset input to define the marker position, and the from input to specify whether the offset value is relative to the start of the file, end of the file, or the current file marker position. Use the Get File Position function, shown in Figure 14.10, to get the current value of the file marker. Figure 14.9. Set File Position Figure 14.10. Get File Position You can use data files on disk, in a similar way to how you might use data arrays in memorythis is a useful fact because data files can be very large compared to the amount of data you can keep in memory (RAM). For example, when you build an array, you append elementswhen you build a file, you append data. You can replace array elements by specifying an index and writing the new elementsyou can replace data in a file by specifying the offset and writing the data (which overwrites the existing data). You can read array elements by specifying their indexyou can read data from a file by specifying the offset to the data. So, if you need to operate on HUGE data sets, consider using binary files without loading the whole thing into memoryjust read and write the portions you need at a given time. Normally you don't need to manually move the file marker around, but it's good to know you have that option if you are doing some specialized or low-level file I/O. End of FileThe end of file is the offset past the last byte in the filenamely, the file size. Use the Set File Size and Get File Size functions, shown in Figure 14.11 and Figure 14.12, to set and get the end of file (respectively). Figure 14.11. Set File Size Figure 14.12. Get File Size As you write data to a file, the end of file is automatically adjusted if the write operation would move the file marker past the end of file (meaning that the file will grow in size). Increasing the file size using the Set File Size function will cause the file to grow, and be padded with null data (zeros). Conversely, if the file size is reduced by setting the end of file to a value smaller than its current value, the data between the new end of file and the original end of file will be clipped (deleted). Moving, Copying, and Deleting Files and FoldersThe following functions allow you to move, copy, and delete both files and folders. Move will move a file from the source path to the target path (see Figure 14.13). Figure 14.13. Move Copy copies a file from the source path to the target path (see Figure 14.14). Figure 14.14. Copy Delete deletes a file or directory (see Figure 14.15). WARNING!!! Be very careful using this function. It can delete files or whole directories without any prompting!!! That reminds us, when was the last time we backed up our data? Figure 14.15. Delete Creating Folders and Listing Folder ContentsThe following functions allow you to create folders and list the files and subfolders contained in folders. Create Folder will create a directory specified by the path (see Figure 14.16). Note that this function will create multiple parent directories, if they do not already exist. For example, if "C:\Data" does not exist and you attempt to create the directory "C:\Data\Run01," this function will first create "C:\Data" and then "C:\Data\Run01." Figure 14.16. Create Folder List Folder returns the contents of a directory specified by path (see Figure 14.17). You can also optionally specify a file pattern to filter the results. Figure 14.17. List Folder Activity 14-1: Reading a Text FileYou will create a VI that reads the entire contents of a text file. It will display the file's contents in a string indicator and the file's size in a numeric indicator.
Open/Create/Replace File Function Open/Create/Replace File function (Programming>>File I/O palette) opens the file and returns a refnum that will be used by the other File I/O VIs. Get File Size Function Get File Size function (Programming>>File I/O>>Advanced File Functions palette) returns the size of the file, which will be used for specifying the number of characters to read. Read from Text File Function Read from Text File function (Programming>>File I/O palette) returns the number of characters from a file specified by the count input, starting at the current file position (which is zero, in our case). Note that this function is polymorphic. You can wire either a file refnum as we are doing here, OR a file path as we did in Chapter 9, "Exploring Strings and File I/O." If you wire a path and do not wire refnum out, the file reference will be automatically closed. Close File Function Close File function (Programming>>File I/O palette) closes the file refnum that was created by Open/Create/Replace File. Simple Error Handler.vi Simple Error Handler.vi (Programming>>Dialog & User Interface palette) displays a dialog if there is an error in one of the file I/O functions.
Activity 14-2: Writing and Reading Binary FilesIn this activity, you'll use the file I/O functions to write a binary file, and then read back that file at arbitrary points in the file.
If you come back to this assignment after reading about the Type Cast function later in this chapter, you may want to change this diagram to programmatically calculate the size of the data element (a DBL, in this case) instead of using a numeric constant in multiple locations. You can use the String Length function to determine the number of bytes in the flattened data (output by Type Cast) of the data element type, as shown in Figure 14.24. Figure 14.24. Type casting a DBL numeric to a string and checking the length (number of bytes) This might not seem to be as easy as just wiring a numeric constant to each location that requires the data length value, but if we ever change the data type of our binary file (for example, from a DBL to a EXT), then we will have to update each of those constants. We might forget about this, and so each of those constants is a potential bug, and thus, a liability. It might seem that this trick would make the code slower (due to the extra processing steps), but LabVIEW's compiler can determine whether a deterministic calculation is being performed from a constant and replace the calculation with the derived constant (in the compiled code)in this case, an I32 constant equal to 8. This feature is referred to as "constant folding" and is common to most modern compilers. |