File access coding example
Monkey Targets Forums/HTML5/File access coding example
| ||
| I am compiling a Monkey program that imports/parses .tcx files that are embedded within my compiled program. I appreciate this might be a big ask, however, is anyone aware of an example of file locator logic which will allow a compiled Monkey program to: 1. Present a 'pick file' button within the GUI/web browser 2. Allow copy and pasting of a file locations text from windows explorer 3. Save the path to the file into a variable for use by the program when a 'import data' button is pressed. [EDIT] used code from the following thread to produce a three button file selector: http://www.monkey-x.com/Community/posts.php?topic=5698 The issue I've got at the mo is developing the syntax to detect when 3 files have been selected, then invoking the logic to run 'other' functionality (namely a data parser using the three files selected with the three buttons). Any help invoking a 'run' button gratefully appreciated..... My attempt at using a global variable that gets incremented within each of the file classes results in only one 'browse' button being displayed. I suspect this is the wrong approach....
'original code sourced from Monkey forum posting:
'http://www.monkey-x.com/Community/posts.php?topic=5698
Strict
Import mojo
#If TARGET = "html5" Then
Import dom.dom
Extern
Function log:Void(e:Event) = "window.console.log"
Function log:Void(f:FileList) = "window.console.log"
Function log:Void(f:File) = "window.console.log"
'Global file1size:Int
Class File
Field lastModified:Int
Field lastModifiedDate:String
Field name:String
Field size:Int
Field fileName:String
Field fileSize:Int
Field type:String
End Class
Class FileList Extends DOMObject
Field length:Int
Method item:File( index:Int)
End Class
Class customHTMLInputElement Extends HTMLInputElement = "HTMLInputElement"
Field files:FileList
End Class
'second file
Class File2
Field lastModified:Int
Field lastModifiedDate:String
Field name:String
Field size:Int
Field fileName:String
Field fileSize:Int
Field type:String
End Class
Class FileList2 Extends DOMObject
Field length:Int
Method item:File( index:Int)
End Class
Class customHTMLInputElement2 Extends HTMLInputElement = "HTMLInputElement"
Field files:FileList2
End Class
'third file
Class File3
Field lastModified:Int
Field lastModifiedDate:String
Field name:String
Field size:Int
Field fileName:String
Field fileSize:Int
Field type:String
End Class
Class FileList3 Extends DOMObject
Field length:Int
Method item:File( index:Int)
End Class
Class customHTMLInputElement3 Extends HTMLInputElement = "HTMLInputElement"
Field files:FileList3
End Class
'fourth file -- ideally want to change this to a button which
' is only displayed once three files have been selected
' which will in turn call a data parser by importing another Monkey application
' suspect might have to embed the data parser within this file.
'Class File4
' Field lastModified:Int
' Field lastModifiedDate:String
' Field name:String
' Field size:Int
' Field fileName:String
' Field fileSize:Int
' Field type:String
'End Class
'Class FileList4 Extends DOMObject
' Field length:Int
' Method item:File( index:Int)
'End Class
'Class customHTMLInputElement4 Extends HTMLInputElement = "HTMLInputElement"
' Field files:FileList4
'End Class
Public
Class Listener Extends EventListener
Method handleEvent:Int(e:Event)
Local target:customHTMLInputElement = customHTMLInputElement(e.target)
Select e.type
Case "change"
Local f:File = target.files.item(0)
Print "new file: "+f.name+" - "+f.size+" bytes"
End Select
Return 1
End Method
End Class
Class Listener1 Extends EventListener
Method handleEvent:Int(e:Event)
Local target:customHTMLInputElement2 = customHTMLInputElement2(e.target)
Select e.type
Case "change"
Local f:File = target.files.item(0)
Print "new file: "+f.name+" - "+f.size+" bytes"
End Select
Return 1
End Method
End Class
Class Listener2 Extends EventListener
Method handleEvent:Int(e:Event)
Local target:customHTMLInputElement3 = customHTMLInputElement3(e.target)
Select e.type
Case "change"
Local f:File = target.files.item(0)
Print "new file: "+f.name+" - "+f.size+" bytes"
End Select
Return 1
End Method
End Class
'Class Listener3 Extends EventListener
' Method handleEvent:Int(e:Event)
' Local target:customHTMLInputElement3 = customHTMLInputElement3(e.target)
' Select e.type
' Case "change"
' Local f:File = target.files.item(0)
' Print "new file: "+f.name+" - "+f.size+" bytes"
'
' End Select
' Return 1
' End Method
'End Class
Function Init:Void()
Local input:HTMLInputElement = HTMLInputElement(document.createElement("input"))
input.type = "file"
Local div:HTMLDivElement = HTMLDivElement(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
div.appendChild(input)
Local listener:EventListener = New Listener()
input.addEventListener("change",listener)
'file1size = file1size + 1
End Function
Function Init2:Void()
Local input:HTMLInputElement = HTMLInputElement(document.createElement("input"))
input.type = "file"
Local div:HTMLDivElement = HTMLDivElement(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
div.appendChild(input)
Local listener1:EventListener = New Listener1()
input.addEventListener("change",listener1)
'file1size = file1size + 1
End Function
Function Init3:Void()
Local input:HTMLInputElement = HTMLInputElement(document.createElement("input"))
input.type = "file"
Local div:HTMLDivElement = HTMLDivElement(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
div.appendChild(input)
Local listener2:EventListener = New Listener2()
input.addEventListener("change",listener2)
'file1size = file1size + 1
End Function
'Function Init4:Void()
'Local input:HTMLInputElement = HTMLInputElement(document.createElement("submit"))
'input.type = "submit"
' Local input:HTMLInputElement = HTMLInputElement(document.createElement("input"))
' input.type = "file"
' Local div:HTMLDivElement = HTMLDivElement(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
' div.appendChild(input)
' Local listener3:EventListener = New Listener3()
' input.addEventListener("change",listener3)
'End Function
#End If
Class FileApp Extends App
Method OnCreate:Int()
SetUpdateRate(30)
Init()
Init2()
Init3()
'failed attempt at adding logic to display a 4th 'run data parser' button once 3 files selected:
'If file1size=2
' Init4()
' Endif
Return 0
End Method
Method OnUpdate:Int()
Return 0
End Method
Method OnRender:Int()
Cls(0,0,0)
Return 0
End method
End Class
Function Main:Int()
New FileApp()
Return 0
End function
Thanks, BP. |
| ||
| This version may be less confusing to you. It shows how to create a button and the like. If you want something more effective for HTML5 I/O, I'd recommend my 'regal.virtualos' module. If you just want to deal with external bindings yourself, my version of the demo should get you started. For the specific streaming features 'virtualos' has, you'll need to install the other modules. Again, that's only if you're interested in a cohesive solution. You'll still have to pipe data into it, so I only recommend my module if you're looking for a file-system. EDIT: I just updated the demo to asynchronously load files, rather than just show how to use the API. The current version should be pretty much what you're looking for. Again, this isn't a file-system like 'regal.virtualos', but it'll allow you to load files. Obviously, this only allows you to load the file as a buffer, so you'd need to use the "Peek" commands or a 'DataStream' object to make any use of it. |
| ||
| I forgot to mention this, but I also wrote a target or two that execute Monkey code on demand. More specifically, it lets you execute 'Main' ('bbMain'), but you get the idea. Technically you could execute any arbitrary function given the right "glue code", either from the observation end (HTML/JS), or the self-contained end (Monkey). |
| ||
| @ImmutableOctet(SKNG) Thank you for the feedback and suggestion, trying it out now. |
| ||
| @ImmutableOctet(SKNG), very excited about your help, moving forwards ;) [EDIT] I just need to suss how to type convert the databuffer to a dataList - I was manipulating my files individually using the following code in my data parsing Monkey code:
'## Load the Red data
file = New FileLoaderClass("testerTwo.txt")
While Not file.Eof()
dataList = dataList.Resize(dataList.Length() + 1)
dataList[dataList.Length() - 1] = file.ReadLine()
numberOfLines = numberOfLines + 1
Wend
I was hoping to extract the relative path to each file, store that in a global variable, and then use the three global variables with my existing code. However, I feel a more succinct way forward is to sort through the bytes that are stored in the data buffers by hopefully loading the dataBuffers into a dataList - I'm sure that I'll see a better way forwards after some sleep.... Need rest ;) [EDIT] able to investigate your suggestion about the datastream object now, cheers for the help again. |
| ||
| Managing to do some byte by byte comparison in order to parse the data from files. Probably an easier way to achieve parsing the data, which is kind of xml in format, however the syntactical sugar eludes me for now. My plan at the mo is to search for a carriage return character then use that to populate a line_string until a successive carriage return character.
Local i:Int
'okay - need to work my logic that parses files into here maybe......
'OR how about populating the arrays I established via the following
'as the data transfer device
If (MouseHit(MOUSE_LEFT)) Then
For Local I:= 0 Until files.Length
Print("File #" + (I+1) + ":")
Print("")
'parse the data from all three files into
If I=0
'parse file 1 data
Print "Parsing file 1...."
'For i = 0 To (dataList.Length() - 1)
For i = 0 To (files[0].Length() - 1)
Print ("i is: "+i)
Print(files[I].PeekString(i))
Print ("Is Byte Number: "+(files[I].PeekByte(i)))
If files[I].PeekByte(i)=62
Print "Carriage ##### return symbol maybe detected"
Endif
If files[I].PeekByte(i)=60
Print "Lesser than <<<<< symbol detected"
Endif
'strSource = (files[i]) ' cannot convert from databuffer to string....
'Print strSource
Next
Print(files[I].PeekString(i))
Endif
If I=1
'parse file 2 data
|
| ||
| You mean, like 'ReadLine'? Because as I previously brought up, 'DataStream' and 'Stream' are great ways to make your code storage agnostic. That's what they're made for. In the example I posted you could simply write: That, or if the format is XML or XML-like, you could probably plug the data into one of the existing XML parsers. For example, Diddy has one, and SKN3 made one. In the case of a string-based input for those parsers, you could use: Or alternatively, you could still use a 'Stream' object and call the 'ReadString' method. In this particular case, that's probably unnecessary. You've got options for parsing, including doing it yourself, so you shouldn't have any problems. Just as a side note, if you ever need to compare the contents of files, I wrote this module (Installed with the main repo). Anyway, I hope those suggestions help. In general, it's best to stay within the borders of Monkey wherever possible, because that makes the code portable. Sometimes that's not realistic, but in this case, once the data is loaded, you shouldn't have any issues accessing the data from Monkey. |
| ||
| @ImmtuableOctet(SKNG) Thanks again for the additional feedback - during the week I can only squeeze in coding when I'm dog tired - your suggestion will save me a bucket load of work that I didn't need to do. I already have developed my own data parser using the following sytnax that works quite well, I was struggling to see how to implement manipulating the dataBuffer as a readline object. I look forward to trying your suggestion this evening - after I've done my daily work thing ;) This is a slice of my current data parser, where my dataList is a string object:
Field file:FileLoaderClass
Field dataList:String[]
Field numberOfLines:Int
file = New FileLoaderClass("testerTwo.txt")
While Not file.Eof()
dataList = dataList.Resize(dataList.Length() + 1)
dataList[dataList.Length() - 1] = file.ReadLine()
numberOfLines = numberOfLines + 1
Wend
For i = 0 To (dataList.Length() - 1)
count=count+1
strSource = (dataList[i])
If strSource[0 .. 16] = "<DistanceMeters>" Then
distanceOneList = distanceOneList.Resize(distanceOneList.Length() + 1)
strippedStr = strSource[16 .. 24]
'Print "DstrippedStr = "+strippedStr
distanceOneList[distanceOneList.Length() - 1] = strippedStr
End If
'Print "strSource = "+strSource
'NOTE: Sometimes the DATE is sourced as a TIME field...need to capture that
If strSource[0 .. 6] = "<Time>" Then
timeOneList = timeOneList.Resize(timeOneList.Length() + 1)
strippedStr = strSource[6 .. 26]
'Print "TstrippedStr = "+strippedStr
timeOneList[timeOneList.Length() - 1] = strippedStr
End If
If strSource[0 .. 17] = "<LatitudeDegrees>" Then
latOneList = latOneList.Resize(latOneList.Length() + 1)
strippedStr = strSource[17 .. 26]
'Print "LaTstrippedStr = "+strippedStr
latOneList[latOneList.Length() - 1] = strippedStr
End If
If strSource[0 .. 18] = "<LongitudeDegrees>" Then
longOneList = longOneList.Resize(longOneList.Length() + 1)
strippedStr = strSource[18 .. 28]
'Print "LonGstrippedStr = "+strippedStr
longOneList[longOneList.Length() - 1] = strippedStr
End If
'need logic to suss whether the BPM is over 99BPM or no (3 figs required then...
If strSource[0 .. 7] = "<Value>" Then
BPMOneList = BPMOneList.Resize(BPMOneList.Length() + 1)
strippedStr = strSource[7 .. 12]
'Print "LonGstrippedStr = "+strippedStr
BPMOneList[BPMOneList.Length() - 1] = strippedStr
End If
Next
I'll be sure to check out your version of data parsing, as you mentioned here: You've got options for parsing, including doing it yourself, so you shouldn't have any problems. Just as a side note, if you ever need to compare the contents of files, I wrote this module (Installed with the main repo). My code may not necessarily be the most succinct way to achieve my goals - but its a baby steps process for moi. I genuinely appreciate your feedback - helps me retain my coding mojo ;) Right, off to work..... |
| ||
| Sorry for my ignorance, I tried invoking the following: (interpreting the INSERT_INDEX_HERE as if I entered 0 it would use the first selected file) [EDIT] Okay, found that by simply adding Import brl.datastream (from the example within the following link) I resolved the datastream object not being identified, however, the line While (Not inputStream.Eof) Cannot be used this way....? I suspect I am failing to retrieve the file data identified within the button from the LoadFile request. https://github.com/Regal-Internet-Brothers/ioutil/blob/master/Examples/publicdatastream/TransferTo_Example.monkey [EDIT] I found a reference to filestream here, looking around for datastream.... https://github.com/Regal-Internet-Brothers/virtualos/blob/master/filestream.monkey Found a reference to 'publicdatastream' here: https://github.com/Regal-Internet-Brothers/ioutil/commit/d50c85abe53c87ae77aab057817902485ed7cd95
Method HandleEvent:Int(event:Event)
Select event.type
Case "change"
Local fileButton:= GetFileButton(event.target)
If (fileButton <> Null) Then
Local f:File = fileButton.files.item(0)
Print("New file: ~q" + f.name + "~q - " + f.size + " bytes")
' Allocate a "shell" object.
'Local buffer1:= fileButton.files.item[0]
Local buffer:= files[0]
'Local inputStream:= New DataStream(buffer1)
Local inputStream:= New DataStream(buffer)
While (Not inputStream.Eof)
' Read the current line.
Local line:= inputStream.ReadLine()
Wend
Edit, resolved not accessing the compiler not accessing the dataStream object... as stated above. However, I receive type 'DataStream' not found. Now I suspect I may need to include a reference to your DataStream module but am not sure how to go about achieving this. |
| ||
| However, I receive type 'DataStream' not found. Now I suspect I may need to include a reference to your DataStream module but am not sure how to go about achieving this. You don't have to import it unless you want a different implementation. It's separate from the official 'brl.datastream' API. You can import that module to get what you're looking for. Just for future reference, 'brl.datastream' and 'regal.ioutil.publicdatastream' are different modules ('regal' doesn't have the standard 'brl.datastream.DataStream' class). Likewise, the 'FileStream' implementation found in 'regal.virtualos' is different from the version in 'brl.filestream'. In that particular case, it's a reimplementation for the virtual file-system. If you want to pass data into the file-system via extensions, that's possible with '__OS_SaveBuffer', found in 'regal.virtualos.legend'. To do something like this, you would upload to the file-system, then use 'regal.virtualos.filestream.FileStream' to load from the file-system. It's experimental, but it works well. Just keep in mind that 'regal.virtualos.filestream' is dependent on 'regal.ioutil' and co. With that said, you don't need all of those dependencies here. If you're looking for solid behavior to manage the files, then you could use 'regal.virtualos'. However, for something this simple, it's not really needed. Useful, but not necessary. You don't seem to need to keep track of files beyond the loader, so it's not really relevant. All you really need to do is plug the buffers into 'brl.databuffer.DataStream'. You've already got the buffers, you can just start reading from there. Streams, particularly 'brl.databuffer.DataStream' is the standard way of doing this. Just to confirm, the BRL modules are already installed. They're default modules that make up the "standard library", so you can import them anywhere you want. The code you posted above should work just fine. As long as you're importing 'brl.datastream', then it should compile with no problems. If you've got any trouble from here, feel free to ask. Although, I recommend making multiple posts so I understand the intended message order. Edits are good for extra info that's not largely canonical. In regards to this question: While (Not inputStream.Eof) Cannot be used this way....? I suspect I am failing to retrieve the file data identified within the button from the LoadFile request. If the 'While' loop isn't working, try adding parentheses to it. It's a property in 'Stream', but some extending APIs just implement it as an undecorated method. You're probably loading the data just fine. It'd be a runtime error / exception if it failed, so if the compiler itself says there's an error, it's related to the code. |
| ||
| @ImmutableOctet(SKNG), thanks for the feedback, not normally up quite so early, thanks again for the prompt feedback, digesting your info now - hopefully I'll manage to work through your 'input' before work. I have tried adding extra parentheses to the While (Not inputStream.Eof) to no avail.Even tried modifying inputStream.Eof to DataStream.Eof to no avail: While (Not (DataStream.Eof)) ' Read the current line. Local line:= DataStream.ReadLine() Wend With the inputStream.Eof commented out, the following code compiles and runs fine - I'm simply using three small text files to test the code. here it is not 'codeboxed'
Strict
'original code sourced from Monkey forum posting:
'http://www.monkey-x.com/Community/posts.php?topic=5698
' Preprocessor related:
#MOJO_AUTO_SUSPEND_ENABLED = False
' Imports:
Import mojo
Import brl.databuffer
'attempts at getting inputstream.Eof to work
Import brl.datastream
Import brl.inputstream
' Check if we're using HTML5:
#If TARGET = "html5"
Import dom
Import "native/file_to_databuffer.js"
' External bindings (JavaScript):
Extern
' Functions:
' File-to-DataBuffer:
Function LoadFile:DataBuffer(F:File, B_Out:DataBuffer)="loadFile"
' DOM:
Function log:Void(e:Event) = "window.console.log"
Function log:Void(f:FileList) = "window.console.log"
Function log:Void(f:File) = "window.console.log"
'Function log:Void(o:Object) = "window.console.log"
' Classes:
Class File
' Fields:
Field lastModified:Int
Field lastModifiedDate:String
Field name:String
Field size:Int
Field fileName:String
Field fileSize:Int
Field type:String
End
Class FileList Extends DOMObject
' Fields:
Field length:Int
' Methods:
Method item:File(index:Int)
End
Class HTMLFileInputElement Extends HTMLInputElement = "HTMLInputElement"
' Fields:
Field files:FileList
End
Public
' HTML5-specific Monkey code:
' Globals
Global file1path:String="one"
Global file2path:String="two"
Global file3path:String="three"
' Classes:
Class EventRepeater Extends EventListener
' Constructor(s):
Method New(Callback:EventHandler)
Self.Callback = Callback
End
' Methods:
Method handleEvent:Int(event:Event)
Return Callback.HandleEvent(event)
End
' Fields:
Field Callback:EventHandler
End
' Functions:
Function AddFileRequester:HTMLFileInputElement(listener:EventListener, node:dom.Node)
Local input:= HTMLFileInputElement(document.createElement("input")) ' HTMLInputElement
input.type = "file"
input.addEventListener("change", listener)
node.appendChild(input)
Return input
End
Function AddButton:HTMLInputElement(name:String, listener:EventListener, node:dom.Node)
Local button:= document.createElement("input")
button.setAttribute("type", "button")
button.setAttribute("name", name)
button.setAttribute("value", name)
button.addEventListener("click", listener)
node.appendChild(button)
Return HTMLInputElement(button)
End
#Else
#Error "Please build this application with the HTML5 target."
#End
' Interfaces:
Interface EventHandler
' Methods:
Method HandleEvent:Int(event:Event)
End
' Classes:
Class FileApp Extends App Implements EventHandler
' Constant variable(s):
Const FILES_NEEDED:= 3
' Methods:
Method OnCreate:Int()
SetUpdateRate(30) ' 0 ' 60
Self.running = False
Self.filesQueued = 0
' This is a dummy object used to get around the limitations of DOM:
Self.repeater = New EventRepeater(Self)
Self.bodyNode = dom.Node(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
Self.fileButtons = New HTMLFileInputElement[FILES_NEEDED]
Self.files = New DataBuffer[FILES_NEEDED] ' Self.fileButtons.Length
For Local I:= 0 Until fileButtons.Length ' FILES_NEEDED
Self.fileButtons[I] = AddFileRequester(repeater, bodyNode)
Next
#If CONFIG = "debug"
MakeRunButton()
#End
Return 0
End
Method HandleEvent:Int(event:Event)
Select event.type
Case "change"
Local fileButton:= GetFileButton(event.target)
If (fileButton <> Null) Then
Local f:File = fileButton.files.item(0)
Print("New file: ~q" + f.name + "~q - " + f.size + " bytes")
' Allocate a "shell" object: these are my attempts to get the pointer to the
' path to obtain the data from, I suspect I am failing to access the
' path to the file, or indeed the object within the Local 'f' variable
' that refers to the file path. Suspect that could be why
' While (Not inputStream.Eof) is failing to compile
Local buffer:= New DataBuffer()
LoadFile(f, buffer)
files[filesQueued] = buffer
'Local inputStream:= New DataStream(buffer1)
Local inputStream:= New DataStream(buffer)
'suspect I may need to 'open' the inputStream
'here prior to accessing it ? Code compiles
'and runs ok with the next 4 lines commented out
'While (Not (inputStream.Eof))
' Read the current line.
' Local line:= inputStream.ReadLine()
'Wend
Local buffer1:= New DataBuffer()
Local buffer2:= New DataBuffer()
Local buffer3:= New DataBuffer()
If filesQueued = 0
LoadFile(f, buffer1)
files[filesQueued] = buffer1
Endif
If filesQueued = 1
LoadFile(f, buffer2)
files[filesQueued] = buffer2
Endif
If filesQueued = 2
LoadFile(f, buffer3)
files[filesQueued] = buffer3
Endif
filesQueued += 1
Endif
Case "click"
If (event.target = runButton) Then
'Local runButton:= Self.runButton
OnRunButtonPressed()
Endif
End Select
Return 1
End
Method OnFilesLoaded:Void()
If (runButton <> Null) Then
Return
Endif
'running = True
MakeRunButton()
Print("All files have been loaded.")
Return
End
Method OnRunButtonPressed:Void()
If (running Or Not AllFilesLoaded) Then
Return
Endif
running = True
Print("Starting the application properly.")
Print("File 1 Path is:")+file1path
Print("File 2 Path is:")+file2path
Print("File 3 Path is:")+file3path
Return
End
Method MakeRunButton:Void()
If (runButton <> Null) Then
Return
Endif
runButton = AddButton("Run", repeater, bodyNode)
Return
End
Method GetFileButton:HTMLFileInputElement(target:EventTarget)
For Local I:= 0 Until fileButtons.Length
If (fileButtons[I] = target) Then ' EventTarget(...)
Return fileButtons[I]
Endif
Next
Return Null
End
Method OnUpdate:Int()
If (Not running) Then
If (AllFilesLoaded) Then
OnFilesLoaded()
Endif
Return 0
Endif
Local strSource:String
Local i:Int
'okay - need to work my logic that parses files into here maybe......
'OR how about populating the arrays I established via the following
'as the data transfer device
If (MouseHit(MOUSE_LEFT)) Then
For Local I:= 0 Until files.Length
Print("File #" + (I+1) + ":")
Print("")
'parse the data from all three files into
If I=0
'parse file 1 data
Print "Parsing file 1...."
'For i = 0 To (dataList.Length() - 1)
For i = 0 To (files[I].Length() - 1)
'strSource = (files[i]) ' cannot convert from databuffer to string....
'Print strSource
Next
Endif
If I=1
'parse file 2 data
Print "Parsing file 2...."
Endif
If I=2
'parse file 3 data
Print "Parsing file 3...."
Endif
Print(files[I].PeekString(0))
If I=2
Print " "
Print "========== End of parsing files==========="
Print " "
Endif
Next
Endif
Return 0
End
Method OnRender:Int()
Cls()
If (Not running) Then
If (AllFilesLoaded) Then
DrawText("All files have been loaded.", 8.0, 8.0)
Else
' This basically never happens.
DrawText("Waiting for files; " + FilesCompleted + " completed.", 8.0, 8.0)
Endif
Return 0
Endif
DrawText("Running as expected, click on the screen to output all files as plain text.", 8.0, 8.0)
Return 0
End
' Properties:
Method AllFilesLoaded:Bool() Property
Return ((filesQueued = FILES_NEEDED) And FileBuffersLoaded)
End
Method FileBuffersLoaded:Bool() Property
For Local I:= 0 Until files.Length
If (files[I].Length = 0) Then
Return False
Endif
Next
Return True
End
Method FilesCompleted:Int() Property
Local count:= 0
For Local I:= 0 Until files.Length
Local file:= files[I]
If (file <> Null And file.Length <> 0) Then
count += 1
Endif
Next
Return count
End
' Fields:
Field fileButtons:HTMLFileInputElement[]
Field runButton:HTMLInputElement
Field files:DataBuffer[]
Field filesQueued:Int
Field repeater:EventRepeater
Field bodyNode:dom.Node
Field running:Bool
End
' Functions:
Function Main:Int()
New FileApp()
Return 0
End
|
| ||
| With that said, you don't need all of those dependencies here. If you're looking for solid behavior to manage the files, then you could use 'regal.virtualos'. However, for something this simple, it's not really needed. Useful, but not necessary. You don't seem to need to keep track of files beyond the loader, so it's not really relevant. Yes, I’m hoping to load the data into a format that my existing file parser can access without using code to glue the bytes back together to strings with carriage returns, which was the elongated path I was embarking upon prior to your help ;) |
| ||
I think the error in my code is within the following area specifically:
If (fileButton <> Null) Then
Local f:File = fileButton.files.item(0)
Print("New file: ~q" + f.name + "~q - " + f.size + " bytes")
' Allocate a "shell" object: these are my attempts to get the pointer to the
' path to obtain the data from, I suspect I am failing to access the
' path to the file, or indeed the object within the Local 'f' variable
' that refers to the file path. Suspect that could be why
' While (Not inputStream.Eof) is failing to compile
Local buffer:= New DataBuffer()
LoadFile(f, buffer)
files[filesQueued] = buffer
'Local inputStream:= New DataStream(buffer1)
Local inputStream:= New DataStream(buffer)
'suspect I may need to 'open' the inputStream
'here prior to accessing it ? Code compiles
'and runs ok with the next 4 lines commented out
While (Not (inputStream.Eof))
' Read the current line.
Local line:= inputStream.ReadLine()
Wend
Local buffer1:= New DataBuffer()
Local buffer2:= New DataBuffer()
Local buffer3:= New DataBuffer()
|
| ||
| Okay, I think I get what you're trying to do, but it's not quite right. I updated the example to do what you seem to be looking for. I made a change to the native JavaScript file, so you should probably download the entire thing (Click here). I hope that helps. Everything can be done in the 'ReadLoadedFiles' method. Just for reference, I meant that you should call 'Eof()', not surround it with parentheses. To be fair, that one was my fault. |
| ||
| @SKNG, Thankyou ;) Really appreciated - I'd normally be at work by now but thanks to a docs appointment I've managed to see your resolution without tired eyes for a change. I'm still cutting my teeth with Monkey, your help is going a long way to ensuring I achieve my goal - have a good day. I've even created my own little method:
Method ParseLoadedFiles:Void()
'TO DO: populate....
Return
End
[EDIT] - Oh yes, this is exactly what I was looking for, cheers again. |
| ||
| @SKNG, Thankyou ;) Really appreciated - I'd normally be at work by now but thanks to a docs appointment I've managed to see your resolution without tired eyes for a change. I'm still cutting my teeth with Monkey, your help is going a long way to ensuring I achieve my goal - have a good day. I've even created my own little method, the fog is slowly clearing on the Object Oriented study I did a (few) years ago now.....
Method ParseLoadedFiles:Void()
'TO DO: populate....
Return
End
[EDIT] - Oh yes, this is exactly what I was looking for, cheers again. |