B4J Question [SOLVED} Write file to server using jRDC2?

MrKim

Well-Known Member
Licensed User
Longtime User
Edit: See post 8 for solution.

I have figured out how to read files from the server.
Now I need to write a files (jpg/bmp/pdf/etc.) to the server using jrdc2.
They will be done one at a time so PutFile seems like the way to go although maybe PostMultipart?

I can find examples of the client side, but have been unable to figure out what to do on the server side.

Thanks for any help.
 
Last edited:

EnriqueGonzalez

Expert
Licensed User
Longtime User
They will be done one at a time so PutFile seems like the way to go although maybe PostMultipart?
there are good approaches but if you want to do it in JRDC2 style. just use B4xSerializator (you are already using because it is part of jrdc2), you can convert any object to bytes and send those bytes over http. then on the other side convert again those bytes to files.
 
Upvote 0

MrKim

Well-Known Member
Licensed User
Longtime User
there are good approaches but if you want to do it in JRDC2 style. just use B4xSerializator (you are already using because it is part of jrdc2), you can convert any object to bytes and send those bytes over http. then on the other side convert again those bytes to files.
It is not that part that I am having issues with. Using PutFile I was able to send what appears to be the right amount of bytes, but PutFile also sends the path and file name and I can't figure out how to parse out the Dir, File Name, and File contents.
 
Upvote 0

EnriqueGonzalez

Expert
Licensed User
Longtime User
i just checked JRDC2 and it doesnt have any putfile method, so i maybe you are talking about okhttp library, and again no putfile method, so i guess you are talking about POSTFile method of httpJob

i also guess you are confused on how that method works. for what i can see it doesnt send the file path and name, it just uses it to retrieve the bytes and send it to the server.

if you really need the file path (i cant guess why) and the file name then as i said use B4xSerializator.

B4X:
    Dim m As Map
    m.Initialize
    m.Put("filename",fileName)
    m.Put("filepath",filePath)
    m.Put("fileBytes",fileBytes)
   
    Dim bo As B4XSerializator
    Dim data() As Byte = bo.ConvertObjectToBytes(m)
   
    j.PostBytes("/endpoint",data)

on the server side just use ConvertBytesToObjects to get a map with the info.
 
Upvote 0

MrKim

Well-Known Member
Licensed User
Longtime User
on the server side just use ConvertBytesToObjects to get a map with the info.
As I said, it is the server side I am having trouble with. PutFile is part of HttpJob on the client side.
The example I found using PutFile was something like this:
B4X:
H.PostFile($"http://${IPAddre.Text}:${PortNum}/writefile?type=file&name=${su.EncodeUrl(FilePathAndName, "UTF8")}"$ , Fdir, FN)
if you really need the file path (i cant guess why) and the file name then as i said use B4xSerializator.
The file is being written to the server at the same time it's location is being written to the database. They have to match so the file can be retrieved again later.

In any case I will try your code, See if I can figure out how to get it to work.
Thanks for your help.
 
Upvote 0

MrKim

Well-Known Member
Licensed User
Longtime User
Well, I imagine I am missing something obvious. I got it partially working, the problem is on the server side about half the time it writes a file that can't be read (.JPG) and the other half it writes about 1/3 of the file correctly and then writes - I'm not sure what. It is not random but it is not the picture either.

This is my Client side:
B4X:
        Dim m As Map
    Dim CMD As String = "DirExists"
    Dim CMD As String = "FileExists"
    'Client side file
    Dim Fdir As String = "D:\SkData\SK_Images"
    Dim FN As String = "02-321282-00.JPG"
    'Server side file
    Dim WriteToDir As String = "C:\AndroidApps\B4X\SKDBServer\SKDBServer-WriteFilesBeta"
    Dim WriteToFN As String = "Test.JPG"
    Dim H As HttpJob
    H.Initialize("H", Me)

    Dim m As Map
    m.Initialize
    m.Put("filename", WriteToFN)
    m.Put("filepath", WriteToDir)
    m.Put("fileBytes", File.ReadBytes(Fdir, FN))

    Dim su As B4XSerializator
    Dim data() As Byte = su.ConvertObjectToBytes(m)
    h.PostBytes($"http://${IPAddre.Text}:${PortNum}/writefile"$, data)

And this is the server side:

B4X:
Sub Class_Globals
    Dim su As B4XSerializator

End Sub

Public Sub Initialize
   
End Sub

Sub Handle(req As ServletRequest, resp As ServletResponse)
    Dim in As InputStream = req.InputStream
    Dim buffer(req.ContentLength) As Byte
    in.ReadBytes(buffer, 0, buffer.length)
    Dim M As Map = su.ConvertBytesToObject(buffer)
    If File.Exists(M.Get("filepath"), M.Get("filename")) Then
        File.Delete(M.Get("filepath"), M.Get("filename"))
    End If
    File.WriteBytes(M.Get("filepath"), M.Get("filename"), M.Get("fileBytes"))
End Sub

I know the data is correct when it goes because I converted it back to a map on the client side and wrote the file and it worked fine:
B4X:
'        m = su.ConvertBytesToObject(data)
'        File.WriteBytes(Fdir, $"000000Test2.jpg"$, m.Get("fileBytes"))

My test file is only about 23k and the interesting thing is it contains the correct number bytes in M.Get("fileBytes"), it just doesn't write it correctly.

I have included the correct file and the test file below (when it isn't corrupt). The test file displays differently here - when I open it the brown pattern is all the way down, there is no white as there is here.

As always, thanks for any help.
 

Attachments

  • 02-321282-00.JPG
    02-321282-00.JPG
    22.6 KB · Views: 153
  • Test.JPG
    Test.JPG
    22.6 KB · Views: 145
Upvote 0

EnriqueGonzalez

Expert
Licensed User
Longtime User
This is how i do it.

B4X:
Dim paypload() As Byte = Bit.InputStreamToBytes(req.InputStream)
Dim raf As B4XSerializator
Dim data As Map = raf.ConvertBytesToObject(paypload)
 
Upvote 0

MrKim

Well-Known Member
Licensed User
Longtime User

EnriqueGonzalez

That did it! thank you! One of the things I tired last night was similar code using Bit.InputStreamToBytes but it threw an error, probably because set the size of the buffer. Every time I go to do something new I feel like there is a manual I missed somewhere ?.

For anyone wanting to do something similar below is the basic code:
Client side:
B4X:
    'Local File to send
    Dim Fdir As String = "D:\SkData\SK_Images"
    Dim FN As String = "02-321282-00.JPG"
    'Server Side File To write
    Dim WriteToDir As String = "C:\AndroidApps\B4X\SKDBServer\SKDBServer-WriteFilesBeta"
    Dim WriteToFN As String = "Test.JPG"
    Dim H As HttpJob
    H.Initialize("H", Me)

    Dim m As Map
    m.Initialize
    m.Put("filename", WriteToFN)
    m.Put("filepath", WriteToDir)
    m.Put("fileBytes", File.ReadBytes(Fdir, FN))
    Dim su As B4XSerializator
    Dim data() As Byte = su.ConvertObjectToBytes(m)
    h.PostBytes($"http://${IPAddre.Text}:${PortNum}/writefile"$, data)
This is the server side handler:
B4X:
'Handler class
Sub Class_Globals

End Sub

Public Sub Initialize
 
End Sub

Sub Handle(req As ServletRequest, resp As ServletResponse)

   Dim buffer() As Byte = Bit.InputStreamToBytes(req.InputStream)
    Dim su As B4XSerializator
    Dim M As Map = su.ConvertBytesToObject(buffer)
    If File.Exists(M.Get("filepath"), M.Get("filename")) Then
        Log("Deleteing File")
        File.Delete(M.Get("filepath"), M.Get("filename"))
    End If
    File.WriteBytes(M.Get("filepath"), M.Get("filename"), M.Get("fileBytes"))
End Sub

And add the following to the Server - Main - Appstart:

B4X:
    srvr.AddHandler("/writefile", "FileWriter", False)
 
Last edited:
Upvote 0
Top