· May 17

How are Stream saved?

Hi, I was working with %sStream.FileBynary and following the doc when I find an info that I'm not sure of.
In the part of the doc where it talks about saving streams, it does not precise where it is saved.
I tried to fill my stream, then rewind, then set the file and finally saved.
And it puts in my default directory with the temporary name.
If I do a zwrite of my stream, I get these properties about the file and directory.
(StoreFile) = ""
(NormalizedDirectory) = "C:\InterSystems\Community\mgr\user\stream\"

I figured it was maybe because I used a relative path while using LinkToFile. Tried a full path and it changed the property of the Stream but the save doesn't seem to work.

With zw I can see those two properties.

(StoreFile) = "test.cms"

(TempFile) = "test.cms"

Do I need to remove the tempFile? Am I missing something?

Discussion (6)3
Log in or sign up to continue

Here is a sample code

$$$ThrowOnError(tUtils.CreateCMSStream(tContent,tCertFileName, tKeyFileName, tPassPhrase, .tStream)) //the stream is initialized in CreateCMSStream
     zwrite tStream
     set tStream.Filename = "C:\Users\sdevin\Documents\DEV\iris-pkcs7-util\misc\out\test.cms"
     set tsc = tStream.%Save()
     zw tsc
     zw tsc2
     zwrite tStream

And here is where I create the stream

Method ConvertStringToStream(pString, Output pStream As %Stream.FileBinary) As %Status
     set pStream = ##class(%Stream.FileBinary).%New()
     do pStream.Write(pString)
     do pStream.Rewind()
     return pStream

convertStreamToString is the last instruction of CreateCMSStream

In %Stream.* classes setting the Filename property corresponds to calling the LinkToFile() method (see FilenameSet() method).
From LinkToFile() documentation:

The method as its name suggests creates a LINK to an EXISTING file.
Also note that if there is currently some temporary data in the old stream when the LinkToFile is called this temporary data will be removed before the stream is linked to this filename.

I think you have two options:

  1. set Filename BEFORE writing to the stream
  2. when you need to save a stream to a specific file, create a new file stream and use CopyFrom() method to copy existing data

For option 2 here is a sample (using %Stream.TmpBinary for the temporary stream):

set tStream = ##class(%Stream.TmpBinary).%New()
do tStream.Write("whatever stream contains")
set finalStream = ##class(%Stream.FileBinary).%New()
set finalStream.Filename="c:\temp\streamtest.txt"
do finalStream.CopyFrom(tStream)
write finalStream.%Save(),!

The documentation is not quite clear on all this.

If you have written data to a temporary file before first calling the LinkToFile(filename) method then the previously written temporary file disappears and future Read and Write method calls go to the new filename.  If you later do a LinkToFile to a different filename then you will detach from the previous filename and attach to the new filename.  But the previous file data is still available if you later attach back to the old filename.

When you do a LinkToFile(filename) when there is no existing file with that filename then a new file is created.  If your filename describes an existing file then your %Stream.FileBinary is attached to the existing file.  If the first thing you do after LinkToFile(filename) are Read() method calls (or a Rewind() followed by Read() method calls) then you will Read the existing contents of the file.  If after the LinkToFile, you instead do a MoveToEnd() method call followed by Write() method calls, then you keep the current file contents and your data is appended to the end of the existing file.  If you do a Write() immediately after a LinkToFile() (or immediately after either a Rewind() or a Read()) then existing file data is deleted and you Write() to the beginning of the existing file.  It is possible to Read() data from an existing file by avoiding Write() method calls before you Read() the data.  it is possible to append new data to an existing file by using MoveToEnd() followed by Write() method calls.