Marlin Mixon · Sep 26

Modifying %Stream contents

I have a %Stream that I want to insert some text into the middle of.  I create a new stream called pNewContentStream from the original stream, then I do a MoveTo in pNewContentStream to get to the byte position I want to insert into but when I do my Write, my pNewContentStream gets obliterated with only the text that I wrote, the original content goes away and all I'm left with is my Write text.


Method AddContentTypeCode4(pContentStream As %Stream.GlobalCharacter, Output pNewContentStream As %Stream.GlobalCharacter) As %Status
Set tStatus = $$$OK
try {
Set tTemp = pContentStream.Read()
Set pNewContentStream=##class(%GlobalCharacterStream).%New()
$$$HSTRACE("New Stream")
Set tStatus = pNewContentStream.CopyFrom(pContentStream)
Do pNewContentStream.Rewind()
Set tLocatorString = "<ns2:Description>"
Set tInsertPoint = pContentStream.FindAt(1,tLocatorString,.tStr,0)
Set tInsertPoint = tInsertPoint+$LENGTH(tLocatorString)
Set tStatus = pNewContentStream.Rewind()
Set tStatus = pNewContentStream.MoveTo(tInsertPoint)
Set tStatus = pNewContentStream.Write(..ContentTypeCodeInsertable)
Do pContentStream.MoveTo(tInsertPoint)
Set tRemain = pContentStream.Read()
Do pNewContentStream.Write(tRemain)
     /// Set pNewContentStream.ContentType = tContentTypeCode 
catch ex {
Set tStatus = ex.AsStatus()

The trace labeled "AddContentTypeCode4[6]" shows tStatus = 1, pContentStream is intact and is as expected, pNewContentStream contains whatever was in  ..ContentTypeCodeInsertable

What I was hoping to happen was at least having the beginning of pContentStream, then have the contents of ..ContentTypeCodeInsertable but instead I only get the contents of ..ContentTYpeCodeInsertable.  Any suggestions?  Thanks!



Product version: HealthShare 2020.1
2 0 17 259
Log in or sign up to continue
set old = ##class(%Stream.TmpCharacter).%New()
do old.Write("This is my text")

So, now you have an old stream, "This is my text" but want to have a new stream as "This is my NEW text".

set new = ##class(%Stream.TmpCharacter).%New()
do old.Rewind()
set pos = 10 // This is my
do new.Write(old.Read(pos)), new.Write(" NEW"), new.Write(old.Read(old.Size-pos))

And now, check the resulty

do new.Rewind()
write new.Read(new.Size) --> This is my NEW text

Thanks! I will check that out.

@Marlin Mixon 
 It is just not possible the way you tried. Because: (from class docs)

Move to this position in the stream. If this suceeds then return true, else return false. Note this implementation is not efficient because it searches from the start of the stream,

This means it does a Rewind() and a Read(position) 

• method Write(data As %RawString) as %Status

Appends the string data to the stream and advances the current stream position by the number of characters in data.

Note that a write operation immediately following a read or rewind will clear out the existing data in the stream.

@Robert: Thanks.  I'll study this to get a better idea where I went wrong!

@Julius: That works.  Showing my revised code:

Method AddContentTypeCode5(pContentStream As %Stream.GlobalCharacter, Output pNewContentStream As %Stream.GlobalCharacter) As %Status
Set tStatus = $$$OK
try {
Set pNewContentStream=##class(%GlobalCharacterStream).%New()
Set tLocatorString = "<ns2:Description>"
Set tInsertPoint = pContentStream.FindAt(1,tLocatorString,.tStr,0)-1
Do pContentStream.Rewind()
Do pNewContentStream.Write(pContentStream.Read(tInsertPoint)), pNewContentStream.Write(..ContentTypeCodeInsertable), pNewContentStream.Write(pContentStream.Read(pContentStream.Size-tInsertPoint))
catch ex {
Set tStatus = ex.AsStatus()
Quit tStatus

Or so:

set tmp ##class(%IO.StringStream).%New()
do tmp.Write("This is my text")

do tmp.Seek(11)

do tmp.Write(" NEW")

do tmp.Rewind()
write tmp.Read(tmp.Size;This is my NEW text

%IO* is invisible in my local Class Reference

Is there a special trick to making %IO visible? Selecting the "Percent Classes" checkbox doesn't do it.

By default, a strictly defined list of packages/classes is displayed in IRIS for security purposes, but you can change this behavior locally.

Is the mechanism for doing this something you can share? laugh

No. I couldn't find how to do this in the documentation (probably I searched badly), so I don't publish here undocumented features anymore.
But you can easily determine this from the source code.

The "easy" options indicated by the source code do some interesting things, but showing %IO* isn't among them. I'll keep looking wink

If you create a class, you can it declare as a hidden class, see

Class My.Class Extends What.Ever [ Hidden ]

will be a hidden class.  

For your own classes you can adjust this class keyword as you like but for the system classes - there is no chance, they lie somwhere on ISC servers (and, but this is my very own opinion, not very wise. First, I would like to read the documentation for the version I have installed (and not always the latest version) and second, I would like to read the doc everywhere! For example, I have a 10 hour flight, and want to work. And in case, a server only has a  local LAN access, then you have no docu!).

and second, I would like to read the doc everywhere! For example, I have a 10 hour flight, and want to work. And in case, a server only has a local LAN access, then you have no docu!).

I fully support it.
But I'm afraid now, apart from reading the documentation in PDF format, you can forget about local documentation ("DOCBOOK" database) with normal search and navigation. It's a pity..

Hi @Jeffrey Drumm . there are  2 options

From SMP > Explorer > Classes in %SYS set filter to %IO*.cls  and Documentation

In Studio in NS %SYS load the class and show Class Documentation
and see the code. I have seen more thrilling constructs before.


Strange, the %IO class belongs to our production/development namespace.

We use 'Cache for Windows 2018.1.4'.

It's a "FEATURE" of recent IRIS to hide deprecated code  sad