FileStream

(Engine-Level Function)

Description: Returns a stream attached to a disk file or printer, and is suitable for use in SWrite.
Returns: Stream
Usage: Script Only.
Function Groups: File I/O,  Stream and Socket
Related to: BlockWrite | BuffStream | ClientSocket | CloseStream | GetStreamLength | PipeStream | PrintDialogBox | ServerSocket | SRead | StreamEnd | SWrite
Format: FileStream(FileName [, PrintFlag, CompletionVar, Flags])
Parameters:  
FileName  
Required. Any text specification for a file or printer SWrite. A known path alias may be provided in the form, :{KnownPathAlias}.
PrintFlag
An optional parameter that is any logical expression and must be set to true (non-0) if the stream is printer-based so that special handling and error checking for printer output will be provided.

If this parameter is omitted, the default value of false (0) is used (i.e. a file-based stream is assumed).
CompletionVar
An optional variable that will be initially set Invalid. When the stream is closed it will be incrementally set to an integer in the range 0 to 100. This integer indicates the percentage completion of writing the session-aware stream contents to the VIC.

When the value of this variable is set to exactly 100, the stream has been completely written to the VIC file system. This can be used by the programmer to indicate the progress in writing large files to a VIC over a relatively slow communication link.

This variable can also be provided on non-session-aware FileStreams, where it will remain untouched by any file operations. Its presence does not mark the FileStream as being session-aware.
Flags
An optional parameter that may take one of three values.
If absent or Invalid, the FileStream will not be session-aware (i.e. all operations will be on the local file system.
If valid, the FileStream is session-aware, and if the file does not exist on the VIC file system, a zero-length file will be created and opened for read-write access.
If the file on the VIC exists, setting this parameter to zero will cause it to be initially opened for read-only access. Read-write access is only obtained when you make the first write to the stream.
If the file exists on the VIC, setting Flags to 1 will cause the file to be opened for read-write access, and truncated to zero length.
Comments: If the file designated by FileName does not exist, it will be created when it is written to (by SWrite/BlockWrite for example). The file pointer returned by the function will still be valid. If the file exists but has its read-only attribute set, the stream may only be read from, not written to.
If you want to be certain that the file exists, then manually use FWrite(File, 2, 0, ""); before opening the stream with FileStream.
If the PrintFlag parameter is set, even though a printer is not being used (i.e. FileName indicates a certain file), it will not have any effect overall except that it may impose a slight performance penalty.
Session-aware Streams:

Session-aware streams can be defined simply as streams opened or created by a FileStream statement that can refer to files system resources on the server, or on a VIC. In the latter case, the stream is referred to as a "remote" stream. Not all FileStream statements are session-aware. As the programmer, you must decide whether to make a FileStream session-aware.
To make a FileStream session-aware, you supply the additional, optional parameters, CompletionVar and Flags, to indicate that the stream is a session-aware stream. Without these additional parameters (or with the additional parameters set to certain values), the FileStream is treated just as a regular FileStream.
Having marked a FileStream statement as session-aware, the FileStream will be a remote stream only if it is running in the context of a VIC session. In other words, the module instance running the FileStream statement has an ultimate caller module instance that is the root instance for a VIC session.

 A VIC session differs from a DisplayManager session. A DisplayManager session may be running in the singleton server session, or it may be running in one of N VIC sessions. The concept of VIC session is something that the VTScada engine understands, whereas the concept of a DisplayManager session is something that the VTScada layer understands.

When a FileStream is remote, the FileName parameter is provided relative to the VIC. For example, "C:\Temp\XX.txt" refers to a file on the C drive of the VIC. The FileDialogBox statement may be used to allow the VIC user to identify a resource accessible to the VIC, and provide a suitable text string to pump into FileStream's FileName parameter.

If used in an Anywhere Client, calling FileStream with the Flags set so as to be session-aware causes FileStream to do nothing and return Invalid.

Blocking: It is necessary to block the execution of VTScada script code at clearly defined points when using a remote FileStream. Blocking script execution blocks only the executing interpreter thread (i.e. it does not cause VTScada to stop executing statements in other threads).
The points at which VTScada script code execution will be blocked are...
  • During execution of a FileStream statement that refers to a remote stream. Execution will block until the VIC can tell the server whether the specified FileName parameter is legal, and if it is, the size of the file. This allows a GetStreamLength statement immediately following the FileStream statement to return the size without blocking. It also allows the engine to initialize a cache for the remote stream.
  • On the first write to the remote stream, if the remote stream is open as read-only. This can be a result of a number of statements, such as BlockWrite or SWrite. The block is obtained simply to learn whether read-write access can be obtained, and get a "write-lock" on the remote stream. This lock prevents other processes from accessing the stream content until VTScada closes it.
  • On all writes to a remote stream when the write overwrites the content in the remote stream, and the remote stream content for that file offset is not cached locally on the server. This is not strictly necessary, and is a product of the current caching algorithm that operates on fixed size blocks. If this becomes restrictive, a smarter caching algorithm can avoid this block.
  • On all reads to a remote stream when the content for the specified file offset is not cached locally on the server.
File Content Transfer: Remote stream content is cached on the server in fixed size blocks. Only those blocks that have been read or written are held on the server. Any changed blocks are only written to the remote stream when the stream is closed, either explicitly with a CloseStream statement, or implicitly by invalidating the last reference to the remote stream.
The engine does not block interpreter threads while this operation is performed.
All transfer to the VIC is performed on the "low-priority" channel within the VIC connection to the server. Graphics, user-input and control actions are all performed using the "high-priority" channel. Presently the only other transfer that takes place over the low-priority channel is image transfer. This means that operator actions and graphical representations are largely unaffected by stream transfer operations. Because only one channel is used for stream transfer, all stream transactions are serialized within that channel, meaning that an attempt to open a stream that the server has just closed will be queued behind the last write to the stream, ensuring that you cannot read stale data from the remote stream.
The CompletionVar parameter to the session-aware FileStream statement may be used to monitor the progress of large transfers, and provide operator feedback. It is important to remember that because graphics use a higher priority channel than the stream, the operator will be able to see any progress notification that you display.
Caching Considerations: The present implementation of remote streams uses a fixed block size cache (4 kb) on the server. If an attempt is made either to write a partial file block that is not in the server cache, but is existent in the remote stream. Or, to read from a block that is not in the server cache but is existent in the remote stream, the calling script code will be blocked until the server has recovered the stream data for that block from the VIC. Dependent upon the connection speed and quality, this may take a long time (in computer terms).
Writes of an entire block that is not cached does not cause the server to read data from the VIC.
After a block has been cached on the server, it is not re-read from the VIC.
This algorithm provides a balance between complexity and performance, principally designed to give good performance when creating a file from scratch and writing it to the VIC, while providing some caching benefit for random access use of the remote stream.

Example:

  If ! Valid(stream);
  [
    Stream = FileStream("C:\Recipe\Glue.DAT"); 
  ]

This statement will set Stream to the stream of the file indicated.

  If MatchKeys(1, "p");
  [
    PrintStream = FileStream("\\ServerName\PName", 1); 
  ]  

This will cause PrintStream to be created as a printer based stream pointing to the printer called PName on the server called ServerName.