How to write integer to text file

This was the code:

Var RequestedBaudRate as Integer

RequestedBaudRate = 13

Var b As BinaryStream
Var myFile As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”).Child( “Menu Prefs” )

if myFile = nil or not myFile.exists then

if b.Create(myFile,true) is nil then
Speak “Exist should now be false”
end
Else
b = BinaryStream.create(myFile, false)
'b.Writesingle(RequestedBaudRate)
b.WriteInt32(RequestedBaudRate)
b.flush ()
b.Close ()
End If

Ok, if creating the file with the optional parameter being true fails, there are several possible causes. Among them:
• check for permissions on the file (are you the owner or do you have write permissions?).
• check for permissions on the enclosing folder (only the parent one).
• check whether the volume is writeable (hardware, software or file system bugs/unexpected behaviours can turn a volume read-only; it happens, rarely, but it may happen)
• if your file is still open in another app, some file systems may prevent you to open it

These are the main possible causes that come to mind.

As Markus suggested, the best way to know for sure what happens is to surround the problematic line by a try/catch block. Once you get the error code, you look for its meaning (either search on the Internet or post it here) and you target the problem directly, without guessing.

Something like this:

Try
b = BinaryStream.create(myFile, true)
b.WriteInt32 10
Catch e as RuntimeException
MessageBox str(e.ErrorNumber)+" "+e.Message
End Try

The exception is 104

[quote=490779:@Clifford Coulter]This was the code:

[code]Var RequestedBaudRate as Integer

RequestedBaudRate = 13

Var b As BinaryStream
Var myFile As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”).Child( “Menu Prefs” )

if myFile = nil or not myFile.exists then

if b.Create(myFile,true) is nil then
Speak “Exist should now be false”
end
Else
b = BinaryStream.create(myFile, false)
'b.Writesingle(RequestedBaudRate)
b.WriteInt32(RequestedBaudRate)
b.flush ()
b.Close ()
End If[/code][/quote]
Ok, this code has two problems.

The one you’re encountering:
You attempt to create the file once. If it worked, you try to open it a second time. This second time will always fail: the file is already open because of the first attempt.

And another issue: if myFile happens to be nil, Create will fail. Keep in mind that a nil folderitem isn’t a file that doesn’t exist: it’s not an object at all (not an existing file, not a nonexistent file; just “nothing”, an invalid reference with no properties, no path, etc.). You can’t open/create from nil/nothing).

Try this instead:

[code]Var RequestedBaudRate as Integer

RequestedBaudRate = 13

Var b As BinaryStream
Var myFile As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”).Child( “Menu Prefs” )

if myFile <> nil and not myFile.exists then

b=BinaryStream.Create(myFile,true)
if b is nil then
Speak “Failed to create the file.”
Else
b.WriteInt32(RequestedBaudRate)
b.flush ()
b.Close ()
End If
End If[/code]

This is a Xojo error (the OS triggered the error, as another code, but Xojo translates it as 104).
The only reference I know to get a list of those error codes is the page about the deprecated FolderItem.LastErrorCode property. Let’s hope Xojo inc. will move this list somewhere else before LastErrorCode becomes unreachable.

104: The file is in use. Per my explanation earlier.

Okay, it works and also did when I removed the nil. Why are you now using Nil. I thought that was a mistake.

f myFile.exists then

[quote=490786:@Clifford Coulter]Okay, it works and also did when I removed the nil. Why are you now using Nil. I thought that was a mistake.

f myFile.exists then[/quote]
If the “file” is nil, it means the function to access it failed.
In your code, this is the statement involved in accessing the file: SpecialFolder.Desktop.Child (“HC Prefs Folder 2”).Child( “Menu Prefs” )
With this code, several things may happen in everyday’s use, among which:
• “HC Prefs Folder 2” may not exist on the desktop. In this case, you won’t have a “Menu Prefs” file inside that non-existent item, obviously. myFile will be nil in your code.
• “Desktop” may not exist (e.g. you started from a bootable DVD or a networked volume, or your home folder is locked (e.g. by permissions) and happens to not have a “Desktop” folder in the first place (e.g. you mounted your disk in another OS and could remove this folder); all those cases may prevent MacOS from forcing to create a new, valid, desktop folder). In this case, Desktop.Child is just invalid (you try to get something inside a non-existing item) and refers to nil; since you further have “Child( “Menu Prefs” )”, it means you try to obtain “Menu Prefs” inside nil; you get a crash (unhandled NilObjectException).
The correct way to deal with this is to make sure each subfolder (starting from the desktop folder through all the subfolders) actually is not nil and exists.
A one-line statement like above is therefore a bad habit. Better to have something like this:
Var f As FolderItem

f=SpecialFolder.Desktop
if f<>nil and f.exists then
f=f.Child(“HC Prefs Folder 2”)
if f<>nil and f.exists then
f=f.Child(“Menu Prefs”)
if f<>nil then
f is a valid object. You can now check whether f.exists is true, for instance, to know whether the file actually exists.
end if
end if
end if
• “Menu Prefs” may have permissions that prevent you from reading/writing it. In this case, you’ll get a valid folderitem for myFile, but the BinaryStream.Create function will fail, triggering an exception.
• The desktop folder or “HC Prefs Folder 2” may not allow you to list its content. The block above takes care of this.
• Other file system issues may unexpectedly happen (race conditions, corrupted file system, aliases instead of a regular file, planets misalignment, etc.…). Handling the exception around the BinaryStream.Create function (or in the app.UnhandledException event) is mandatory to take into account most, if not all, possible conditions.

Over top information for me and I will study the pitfalls and problems that can be encountered as you posted. You more than solve the problem. Your time spent helping me on this will not be forgotten. This was my third day working on this issue. I know I have a lot to learn.

This was the final code that worked but realize if the folder or file is missing that would need to be addressed in the code.

[code]Var b As BinaryStream
Var myFile As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”).Child( “Menu Prefs” )

Var f As FolderItem

f=SpecialFolder.Desktop
if f<>nil and f.exists then
f=f.Child(“HC Prefs Folder 2”)
if f<>nil and f.exists then
f=f.Child(“Menu Prefs”)
if f<>nil then
b=BinaryStream.Create(myFile,true) Rem Remakes File
end if
end if
end

b.WriteInt32(index)
b.flush ()
b.Close ()

[/code]

Darn, I’m back to where I first started. I entered the code into my program and “Menu Prefs” text file is still not showing any data. No errors. I thought I could enter integers or strings although they would be seen in a text editor as binary info. I see nothing.

[code]Var b As BinaryStream
Var myFile As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”).Child( “Menu Prefs” )

Var f As FolderItem

f=SpecialFolder.Desktop
if f<>nil and f.exists then
f=f.Child(“HC Prefs Folder 2”)
if f<>nil and f.exists then
f=f.Child(“Menu Prefs”)
if f<>nil then
b=BinaryStream.Create(myFile,true) Rem Remakes File
end if
end if
end

b.WriteInt32(index)
b.flush ()
b.Close ()

if index = 8 then
BaudRateIndexed(8).HasCheckMark=True
BaudRateIndexed(13).HasCheckMark=False
else
BaudRateIndexed(8).HasCheckMark=False
BaudRateIndexed(13).HasCheckMark=true
end[/code]

When I used TextStream I was able to write to the same “Menu Prefs” file so I would think it’s a writable file.

Would anyone be willing to place this in XOJO and add a file “Menu Prefs” in a folder “HC Prefs Folder 2” on the desktop and see if you can write binary data to the text file? I need a verify that this works or not. When I look at the file with a text editor on my iMac I see no data in any form.

[code]Var b As BinaryStream
Var myFile As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”).Child( “Menu Prefs” )

Var f As FolderItem

f=SpecialFolder.Desktop
if f<>nil and f.exists then
f=f.Child(“HC Prefs Folder 2”)
if f<>nil and f.exists then
f=f.Child(“Menu Prefs”)
if f<>nil then
b=BinaryStream.Create(myFile,true)
end if
end if
end

b.WriteInt32(123456789)
b.flush ()
b.Close ()
[/code]

Are you viewing the file in hex? What is the file length?

Can that be changed in the apple text editor? If they are loaded back in with the BinaryStream and displayed in a MsgBox, 123456789 is not there. I also tried to do this with a variant.

This was the data in: b.WriteInt32(123456789)
I take it you did not try it.

the save

[code]'https://hexed.it/

Var value As Integer = 123456789

Var path As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”)

If path.Exists = False Then path.CreateFolder

Var file As FolderItem = path.Child( “Menu Prefs.bin” )

Var b As BinaryStream = BinaryStream.Create(file,True) 'Big Endian by default

b.WriteInt32(value)

b.Close
[/code]

the load

[code]'https://hexed.it/

Var value As Integer = 123 'Default

Var path As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”)

If path.Exists = False Then path.CreateFolder

Var file As FolderItem = path.Child( “Menu Prefs.bin” )

If file.Exists = False Then Return False 'no file here

Var b As BinaryStream = BinaryStream.Open(file) 'Big Endian by default

value = b.ReadInt32

b.Close

System.DebugLog value.ToString

Return True
[/code]

  • you need try catch if file is i use or something else
    if file is in use you need log out or reboot or end the task that opened it.

[quote=490797:@Clifford Coulter]

[code]Var b As BinaryStream
Var myFile As FolderItem = SpecialFolder.Desktop.Child (“HC Prefs Folder 2”).Child( “Menu Prefs” )

Var f As FolderItem

f=SpecialFolder.Desktop
if f<>nil and f.exists then
f=f.Child(“HC Prefs Folder 2”)
if f<>nil and f.exists then
f=f.Child(“Menu Prefs”)
if f<>nil then
b=BinaryStream.Create(myFile,true)
end if
end if
end

b.WriteInt32(123456789)
b.flush ()
b.Close ()
[/code][/quote]

You’re not checking that b is not Nil and if any of your if steps fails, then you just go ahead and write anyway. Have you stepped through this with the debugger to verify that each test passes and then you do the create successfully?

it would only be nil if the folder not exists, i wrote it different in my example above that the folder is created first.

[quote=490794:@Clifford Coulter]Darn, I’m back to where I first started. I entered the code into my program and “Menu Prefs” text file is still not showing any data. No errors. I thought I could enter integers or strings although they would be seen in a text editor as binary info. I see nothing.
When I used TextStream I was able to write to the same “Menu Prefs” file so I would think it’s a writable file.[/quote]
This is the main difference between a TextInput/TextOutput stream and a BinaryStream: the Text version, as its name implies, writes everything as text data to the file (meaning, “1234” will be “1234” as text; specifically, your “text” file would be made of 4 bytes: 49, 50, 51, 52 (with a decimal view). 49 is the “ascii” number for the text “1”, etc.). So, when your text editor opens the file with those 4 bytes, it “converts” 49, 50, 51 and 52 as characters (resulting in “1234”).

On the other hand, the BinaryStream uses no conversion, it just writes the bytes/numbers, etc. you told it. If you write the same “value” (1234) using b.WriteInt32 1234, you don’t write characters (1234 is a number here, not a string), you write 1234 as an int32 (which means an integer of 4 bytes (4x8=32)). Therefore, your file, with only 1234 written as an int32, would have these bytes (as little endian; disregard this information for now if you don’t know what it means): 0 0 4 210 (still viewed in decimal). If you do the math, you have 21016^0+416^1+016^2+016^3=1234. The first two 0 are here for padding (remember: an int32 is 4 bytes, always).

If you compare the bytes (e.g. with HexEdit) of both versions (“1234” using a TextOutputStream and 1234 as an int32 using a BinaryStream), you’d see this (I’m converting as decimal here to stay with the remaining of my explanation, although HexEdit would show you hex values):
Binary (1234): 0 0 4 210 (in hex: 00 00 04 D2)
Text (“1234”): 49 50 51 52 (in hex: 31 32 33 34)

What it means is that those streams are used for very different purposes. The TextOutputStream writes text files that can be viewed directly by the user. You can only write text there, but they will always consist of text.
The BinaryStream writes whatever kind of data you pass to it, sequentially. If you WriteInt32, you append 4 bytes; if you WriteBoolean, you append 1 bit, etc. All write methods of the BinaryStream, except the plain “write” have fixed lengths: to read the file back, you read the same sequences (e.g. ReadInt32 would read 4 bytes and return the resulting integer).
If you want to write some strings sequentially in your BinaryStream, you can either use b.WritePString (limited to 255 characters, the first byte being the length of the actual text; additional characters would be truncated) or use b.WriteInt32 (length)+b.Write (Text). To read back, you’d use either b.ReadPString or b.Read(b.ReadInt32) for longer strings.
BinaryStreams are usually not intended to be viewed by users (except programmers who can use a hex editor and, carefully, make some changes to the data).
For example, you can open a picture file using a BinaryStream and read its format, chunk by chunk (reading the headers, parameters, etc.). The same reading with a TextInputStream would just return the data as a string (often in a human unreadable form).

Now, the BinaryStream can also write plain string (“text files without default encoding”), using the b.Write method. In this case, you lose the sequential behaviour.
BinaryStreams can do way much than Text streams can, suitable for all files. On the other hand, Text streams are good for plain text files: you can specify a delimiter (e.g. an end of line) and use WriteLine to write your text+the delimiter; writing things like boolean, colors, or numbers, however, require conversions to/from strings, unlike the BinaryStream way.

Again a lot of information; those streams can be fascinating ?.

[quote=490819:@Arnaud Nicolet]If you compare the bytes (e.g. with HexEdit) of both versions (“1234” using a TextOutputStream and 1234 as an int32 using a BinaryStream), you’d see this (I’m converting as decimal here to stay with the remaining of my explanation, although HexEdit would show you hex values):
Binary (1234): 0 0 4 210 (in hex: 00 00 04 D2)
Text (“1234”): 49 50 51 52 (in hex: 31 32 33 34)
[/quote]
But “1234” and 1234 are not the same. The former is a 4-byte string and the latter is a number, could be 2, 4, or 8 bytes long, so I’d expect them to be different on disk, whether I write them with TextOutputStream or BinaryStream.

Yes, that’s actually what I’m saying; this is why both values are different in the last two lines you quoted.
However, if you use TextOutputStream.Write “1234” or BinaryStream.Write “1234”, you get the same result (assuming the endianness of the BinaryStream is unchanged).

[quote=490825:@Arnaud Nicolet]Yes, that’s actually what I’m saying; this is why both values are different in the last two lines you quoted.
However, if you use TextOutputStream.Write “1234” or BinaryStream.Write “1234”, you get the same result (assuming the endianness of the BinaryStream is unchanged).[/quote]

Again, those are both strings (the .Write method can only write a string or a memoryblock). Really, AFAICS, the difference between what a TextOutputStream and a BinaryStream can send to disk seems to be limited by the methods that Xojo provides rather than that one deals with text and the other with binary data. Looking at https://documentation.xojo.com/api/language/writeable.html, means I can use .Write with either.

Well, TextOutputStream.Write “1234” or BinaryStream.Write “1234” both write strings, that’s true.
My point is, if you use BinaryStream.WriteBoolean (for example), you can hardly consider it wrote a string.