Longtime User

OliverA

Expert
Your program can access any file on the machine it is running on that it has rights to.

xulihang

Active Member
Longtime User
It's not what I am asking. It is a server app and I want to know how to provide a file for users to download without putting it in the static folder.

OliverA

Expert
The root (/) of the web server is the www folder. The www folder is by default in the same folder that you place the server jar file. Place a file there (or subfolder(s) within) and it should be accessible from the outside

xulihang

Active Member
Longtime User
Right. The www folder is the static file folder and is by default in the File.DirApp folder. But all files in it are accessible. I want to provide a file for download which is only accessible through an HTTP handler.

For example, a user uploads an image to the server. The server will OCR this image and save the result into a txt file and will raise a download action for the browser.

If it is in a static folder, I can use resq.sendredirect to this file. But if it is not, how to do this.

Longtime User

OliverA

Expert
If you are using sendredirect, then you are still serving a file that is in/under the www folder. My first answer is then the correct answer. Inside your handler, you can access any file on your machine, as long as you/your server application has access to it. Want to store your files in c:\temp (or /temp)? Do it. You can open that file and write it to the response object. As to
Another problem is that if I use resp.sendredirect to a txt file in jserver, it will open it instead of giving a direct download dialog.
check out https://stackoverflow.com/a/14281064. Let's say the file you want to sent to the client is "test.txt", you would then use
B4X:
resp.ContentType = "text/plain"
resp.SetHeader("Content-disposition", "attachment; filename=text.txt")
and the download dialog should open with a default name of text.txt. If you don't want to give a default name, you just can set the "Content-disposition" header to "attachment".

OliverA

Expert
Sample code. Please note that file1.txt must be in c:\temp and file2.png in c:\temp2. If on a non-windows platform, adjust path names in the fileInfo map. This is untested code, so may need some adjusting
B4X:
'Class module
Sub Class_Globals
'This map is just there to associate a given file with a location. This shows that each file
'can be located somewhere else and that location has no relationship to the www folder of the jServer
'application. This can be done any which way. Could just do one separate folder for all files. Do
'different folders for files with different extensions, etc. The sky's the limit. Could use a text file
'or database for file locations. Could use id#'s in the "GET" request and map them to file names/locations.
'And on and on
Private fileInfo As Map = CreateMap("file1.txt": "c:\temp", "file2.png": "c:\temp2")

Private contentTypes As Map = CreateMap("txt": "plain\text", "png": "image/png")
End Sub

Public Sub Initialize

End Sub

Sub Handle(req As ServletRequest, resp As ServletResponse)
If req.Method <> "GET" Then
resp.SendError(500, "method not supported.")
Return
End If

Dim fName As String = req.getParameter("filename")
'Here we are using the fileInfo map to retrieve necessary file information. This could
'be anything else as explained above.
If fileInfo.ContainsKey(fName) Then
Dim fExtension As String = GetExtension(fName)
If contentTypes.ContainsKey(fExtension) Then
resp.ContentType = contentTypes.Get(fExtension)
'If you don't want to have a default file name in the download dialog, then just do
resp.SetHeader("Content-disposition", $"attachment; filename=${fName}"$) Dim inStream As InputStream = File.OpenInput(fileInfo.Get(fName), fName) Dim outStream As OutputStream = resp.OutputStream File.Copy2(inStream, outStream) Else resp.SendError(500, "unsupported content type") End If Else resp.SendError(404, "file not found") End If End Sub 'https://www.b4x.com/android/forum/threads/detect-extension-from-mime-type.58789/#post-415466 Sub GetExtension(strFileName As String) As String If strFileName.IndexOf(".") > 0 Then Dim parts() As String = Regex.Split("\.", strFileName) Return parts(parts.Length - 1) Else Return Null End If End Sub xulihang Active Member Licensed User Longtime User B4X: resp.SetHeader("Content-disposition",$"attachment; filename=${fName}"$)

This works great!

I use the code below to directly give a txt file for download.

B4X:
Dim text As String
text="Line1"&CRLF&&"Line2"
resp.SetHeader("Content-disposition", $"attachment; filename=out.txt"$)
Dim bytes() As Byte
bytes=text.GetBytes("UTF8")
resp.OutputStream.WriteBytes(bytes,0,bytes.Length)

Replies
21
Views
2K
Replies
21
Views
9K
Replies
39
Views
31K
Replies
25
Views
27K
Replies
32
Views
23K