File Sharing
In addition to messages and signals, PubNub also allows users to send files.
The most common scenarios where you may need to share files are in social apps to share images or in medical apps to share medical records. You can send videos, images, or documents of up to 5 MB in size each.
Configuration
Enable and configure File Sharing for your app's keyset in the Admin Portal.
Public Admin Portal demo
Want to browse through the Admin Portal without creating an account? Explore it through the Public Demo that shows examples of most PubNub features for transport and logistics use case.
By default, Admin Portal prompts you to enable File Sharing on every newly created keyset (unless you select Choose later for Region during keyset creation).
Testing keysets default to the US East
region and 7 days
retention, which determines how long files remain in storage before deletion.
Option | Description |
---|---|
Bucket Region | Geographical region where your files are stored and managed. Align the file retention period with your Message Persistence settings. This stores messages and files for the same duration. |
Retention | How long you'd like to save your files for. For free accounts, you can set it to 1 day or 7 days. Limits are higher for paid accounts. |
Send files
Sending a file is similar to publishing a message: specify the channel and provide the file. Optionally include a text caption.
You can also encrypt files using AES-256 Encryption (see Data Security). To send encrypted files, define a cipher key in your initial client configuration or pass a cipher key per request. Downloading clients must provide the same key to decrypt the file content.
The code below sends the file cat_picture.jpg
of the custom type file-message
on the channel my_channel
.
Custom message types
Not all SDKs support sending messages with a custom message type. For details, see Message Types.
- JavaScript
- C#
- Go
- Objective-C
- Java
- Python
- PHP
- Swift
- Dart
// web
const input = document.querySelector('input[file]');
input.addEventListener('change', async () => {
const file = input.files[0];
const result = await pubnub.sendFile({
channel: 'my_channel',
file: file,
customMessageType: 'file-message'
});
});
// Node.js
import fs from 'fs';
show all 36 linesPNResult<PNFileUploadResult> fileUploadResponse = await pubnub.SendFile()
.Channel("my_channel")
.File("cat_picture.jpg") // checks the bin folder if no path is provided
.Message("Look at this photo!")
.ExecuteAsync();
PNFileUploadResult fileUploadResult = fileUploadResponse.Result;
PNStatus fileUploadStatus = fileUploadResponse.Status; // contains troubleshooting info
if (!fileUploadStatus.Error && fileUploadResult != null) // checks if successful
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileUploadResult));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileUploadStatus));
}
file, err := os.Open("cat_picture.jpg")
defer file.Close()
if err != nil {
panic(err)
}
resSendFile, statusSendFile, errSendFile := pn.SendFile().
Channel("my_channel").
Message("Look at this photo!").
Name("cat_picture.jpg").
File(file).Execute()
fmt.Println(resSendFile, statusSendFile, errSendFile)
fmt.Println(resSendFile.Data.ID)
NSURL *localFileURL = ...;
PNSendFileRequest *request = [PNSendFileRequest requestWithChannel:@"my_channel"
fileURL:localFileURL];
request.customMessageType = @"file-message";
[self.client sendFileWithRequest:request completion:^(PNSendFileStatus *status) {
if (!status.isError) {
/**
* File upload successfully completed.
* Uploaded file information is available here:
* status.data.fileIdentifier is the unique file identifier
* status.data.fileName is the name used to store the file
*/
} else {
/**
show all 23 linespubnub.sendFile()
.channel("my_channel")
.fileName("cat_picture.jpg")
.customMessageType("file-message")
.inputStream(inputStream)
.message("Look at this photo!")
.async(result -> {
result.onSuccess(res -> {
System.out.println("send timetoken: " + res.getTimetoken());
System.out.println("send status: " + res.getStatus());
System.out.println("send fileId: " + res.getFile().getId());
System.out.println("send fileName: " + res.getFile().getName());
}).onFailure(exception -> {
exception.printStackTrace();
});
show all 16 lines# synchronous
with open("cat_picture.jpg", "rb") as fd:
envelope = pubnub.send_file() \
.channel("my_channel") \
.file_name("cat_picture.jpg") \
.message({"test_message": "test"}) \
.custom_message_type('file-message') \
.should_store(True) \
.ttl(222) \
.file_object(fd) \
.cipher_key("secret") \
.sync()
# multithreaded asynchronous
def callback(response, status):
show all 28 linespubnub.sendFile()
->message("Hey, this is the requested file.")
->channel("channel_1")
->fileId("p1n4ppl3p1zz4")
->fileName("pinapplePizza.jpg")
->customMessageType("file-message")
->sync();
pubnub.send(
.file(url: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("cat_picture.jpg")),
channel: "my_channel",
remoteFilename: "cat_picture.jpg",
publishRequest: .init(additionalMessage: ["text": "Look at this photo!"], customMessageType: "file-message")
) { (fileTask) in
print("The task \(fileTask.urlSessionTask.taskIdentifier) has started uploading; no need to call `resume()`")
print("If needed, the `URLSessionUploadTask` can be accessed with `fileTask.urlSessionTask`")
print("You can use `fileTask.progress` to populate a `UIProgressView`/`ProgressView` ")
} completion: { (result) in
switch result {
case let .success((task, file, publishedAt)):
print("The file with an ID of \(file.fileId) was uploaded at \(publishedAt) timetoken) ")
case let .failure(error):
print("An error occurred while uploading the file: \(error.localizedDescription)")
show all 17 linesimport 'dart:io';
import 'package:pubnub/pubnub.dart';
void main() async {
var pubnub = PubNub(
defaultKeyset: Keyset(
subscribeKey: 'sub-c-abc-123', // Replace with your subscribe key
publishKey: 'pub-c-def-456' // Replace with your publish key
),
);
var inputFile = File('cat_picture.jpg').readAsBytesSync();
try {
var result = await pubnub.files.sendFile(
show all 27 linesEven though the client sends files, the storage service stores and manages the actual files for each key.
After the file is uploaded to the storage service, subscribers to the channel receive a file message. The file message includes a description, filename, and file ID. Use SDK methods to generate a URL to display the file or download it. Refer to Retrieve Files for details.
Enable the feature
File Sharing is an optional feature that you must enable by turning on the feature for your keys in the Admin Portal.
File operations
Beyond sending files, you can list files sent to a channel or delete previously uploaded files. If you enabled Message Persistence on your keyset, you can also search historical file messages using the Message Persistence API. The returned information allows you to display files in the browser or download them.
Refer to the File Sharing section in the SDK documentation to learn more about operations on files.
Receive files
To receive a file, the client must listen to an event of type file
, and subscribe to the channel where the file is sent. No special subscription is required.
Retrieve files
Retrieving files is a two-step process using the Message Persistence API and File Sharing-related SDK methods. To retrieve a file:
- Get the file message using the Message Persistence API or the
listFiles
method. - Display or download the file using dedicated SDK methods based on the obtained file information.
File URLs
Neither the Message Persistence API nor the listFiles
method returns file URLs. They return file-specific information like the file's name and ID that you need to display or download the file.
When you fetch file messages using the Message Persistence API, the response includes the file details (ID and filename) and a message type of 4
, which indicates a file message. You can use this information to display or download the file.
Display and download files
Apart from the optional description, a file message contains the ID and name of the file.
As a file message does not contain the file URL, you must use one of the available SDK methods to construct the file URL to either display the file or download it.
The following code returns the URL of the cat_picture.jpg
file sent to channel my_channel
:
- JavaScript
- C#
- Go
- Objective-C
- Java
- Python
- Swift
- Dart
const result = pubnub.getFileUrl({ channel: 'my_channel', id: 'd9515cb7-48a7-41a4-9284-f4bf331bc770', name: 'cat_picture.jpg' });
PNResult<PNFileUrlResult> getFileUrlResponse = await pubnub.GetFileUrl()
.Channel("my_channel")
.FileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.FileName("cat_picture.jpg")
.ExecuteAsync();
PNFileUrlResult getFileUrlResult = getFileUrlResponse.Result;
PNStatus getFileUrlStatus = getFileUrlResponse.Status;
if (getFileUrlResult != null)
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(getFileUrlResult));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(getFileUrlStatus));
}
resGetFile, statusGetFile, errGetFile := pn.GetFileURL().
Channel("my_channel").
ID("d9515cb7-48a7-41a4-9284-f4bf331bc770").
Name("cat_picture.jpg").Execute()
fmt.Println(resGetFile, statusGetFile, errGetFile)
fmt.Println(resGetFile.URL)
NSURL *url = [self.client downloadURLForFileWithName:@"cat_picture.jpg"
identifier:@"<file-identifier>"
inChannel:@"my_channel"];
pubnub.getFileUrl()
.channel("my_channel")
.fileName("cat_picture.jpg")
.fileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.async(result -> {
result.onSuccess(res -> {
System.out.println("getUrl fileUrl: " + res.getUrl());
}).onFailure(exception -> {
exception.printStackTrace();
});
});
# Synchronous:
envelope = pubnub.get_file_url().
channel("my_channel").
file_id("fileID").
file_name("cat_picture.jpg").sync()
# Multithreaded asynchronous:
def callback(response, status):
pass
pubnub.get_file_url().
channel("my_channel").
file_id("fileID").
file_name("cat_picture.jpg").sync()
do {
let downloadURL = try pubnub.generateFileDownloadURL(channel: "my_channel", fileId: "fileID", filename: "cat_picture.jpg")
} catch {
print("An error occurred generating the URL: \(error.localizedDescription)")
}
import 'package:pubnub/pubnub.dart';
void main() async {
var pubnub = PubNub(
defaultKeyset: Keyset(
subscribeKey: 'sub-c-abc-123', // Replace with your subscribe key
publishKey: 'pub-c-def-456' // Replace with your publish key
),
);
var fileUrl = pubnub.files.getFileUrl(
'my_channel',
'd9515cb7-48a7-41a4-9284-f4bf331bc770',
'cat_picture.jpg'
);
show all 18 linesThe response to this call is the file URL which you can use to display the file in the browser.
You need the same set of file information to download the file. The following code downloads the file cat_picture.jpg
sent to the channel my_channel
:
- JavaScript
- C#
- Go
- Objective-C
- Java
- Python
- Swift
- Dart
// web
const file = await pubnub.downloadFile({
channel: 'my_channel',
id: '...',
name: 'cat_picture.jpg',
});
const myImageTag = document.createElement('img');
myImageTag.src = URL.createObjectURL(await file.toFile());
document.body.appendChild(myImageTag);
// Node.js using streams
import fs from 'fs'
show all 38 linesPNResult<PNDownloadFileResult> fileDownloadResponse = await pubnub.DownloadFile()
.Channel("my_channel")
.FileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.FileName("cat_picture.jpg")
.ExecuteAsync();
PNDownloadFileResult fileDownloadResult = fileDownloadResponse.Result;
PNStatus fileDownloadStatus = fileDownloadResponse.Status;
if (fileDownloadResult != null)
{
fileDownloadResult.SaveFileToLocal(downloadUrlFileName); // saves to bin folder if no path is provided
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileDownloadResult.FileName));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(fileDownloadStatus));
show all 16 linesresDLFile, statusDLFile, errDLFile := pn.DownloadFile().
Channel("my_channel").
ID("d9515cb7-48a7-41a4-9284-f4bf331bc770").
Name("cat_picture.jpg").Execute()
if resDLFile != nil {
filepathOutput := "cat_picture.jpg"
out, _ := os.Create(filepathOutput)
_, err := io.Copy(out, resDLFile.File)
if err != nil {
fmt.Println(err)
}
}
PNDownloadFileRequest *request = [PNDownloadFileRequest requestWithChannel:@"my_channel"
identifier:@"<file-identifier>"
name:@"cat_picture.jpg"];
request.targetURL = ...;
[self.client downloadFileWithRequest:request
completion:^(PNDownloadFileResult *result, PNErrorStatus *status) {
if (!status.isError) {
/**
* File successfully has been downloaded.
* status.data.location - location where downloaded file can be found
* status.data.temporary - whether file has been downloaded to temporary storage and
* will be removed on completion block return.
*/
} else {
show all 23 linespubnub.downloadFile()
.channel("my_channel")
.fileName("cat_picture.jpg")
.fileId("d9515cb7-48a7-41a4-9284-f4bf331bc770")
.async(result -> {
result.onSuccess(res -> {
System.out.println("getFile fileName: " + res.getFileName());
System.out.println("getFile byteStream: " + res.getByteStream());
}).onFailure(exception -> {
exception.printStackTrace();
});
});
# synchronous:
download_envelope = pubnub.download_file().
channel("my_channel").
file_id("fileId").
file_name("cat_picture.jpg").sync()
# Multithreaded asynchronous:
def callback(response, status):
pass
pubnub.download_file().
channel("my_channel").
file_id("fileID").
file_name("cat_picture.jpg").pn_async(callback)
let requestFile = PubNubLocalFileBase(
fileURL: URL(fileURLWithPath: "cat_picture.jpg"),
channel: "my_channel",
fileId: "fileId",
remoteFilename: "cat_picture.jpg"
)
pubnub.download(
file: requestFile, toFileURL: requestFile.fileURL
) { (fileTask: HTTPFileDownloadTask) in
print("The task \(fileTask.taskIdentifier) has started downloading; no need to call `resume()`")
print("If needed, the `URLSessionUploadTask` can be accessed with `fileTask.urlSessionTask`")
print("You can use `fileTask.progress` to populate a `UIProgressView`/`ProgressView` ")
show all 25 linesimport 'dart:io';
import 'package:pubnub/pubnub.dart';
void main() async {
var pubnub = PubNub(
defaultKeyset: Keyset(
subscribeKey: 'sub-c-abc-123', // Replace with your subscribe key
publishKey: 'pub-c-def-456' // Replace with your publish key
),
);
try {
var result = await pubnub.files.downloadFile(
'my_channel',
'd9515cb7-48a7-41a4-9284-f4bf331bc770',
show all 25 linesList files
If you're only interested in the actual files and not the file messages (which include the optional description of the uploaded file) that were sent, you can list up to 100 files sent to a particular channel. However, if there are more than 100 files to be returned, the more
flag will be present in the response.
The code below returns the name, ID, size, and created timestamp for up to 100 files sent to the channel my_channel
:
- JavaScript
- C#
- Go
- Objective-C
- Java
- Python
- Swift
- Dart
const result = await pubnub.listFiles({ channel: 'my_channel' });
PNResult<PNListFilesResult> listFilesResponse = await pubnub.ListFiles()
.Channel("my_channel")
.ExecuteAsync();
PNListFilesResult listFilesResult = listFilesResponse.Result;
PNStatus listFilesStatus = listFilesResponse.Status;
if (listFilesResult != null)
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(listFilesResult));
}
else
{
Console.WriteLine(pubnub.JsonPluggableLibrary.SerializeToJsonString(listFilesStatus));
}
resListFile, statusListFile, errListFile := pn.ListFiles().
Channel("my_channel").Execute()
fmt.Println(resListFile, statusListFile, errListFile)
if resListFile != nil {
for _, m := range resListFile.Data {
fmt.Println(m.ID, m.Created, m.Name, m.Size)
}
}
PNListFilesRequest *request = [PNListFilesRequest requestWithChannel:@"my_channel"];
request.limit = 100;
request.next = ...;
[self.client listFilesWithRequest:request
completion:^(PNListFilesResult *result, PNErrorStatus *status) {
if (!status.isError) {
/**
* Uploaded files list successfully fetched.
* result.data.files - List of uploaded files (information).
* result.data.next - Random string returned from the server, indicating a specific position in a data set. Used for forward pagination, it fetches the next page, allowing you to continue from where you left off.
* result.data.count - Total number of files uploaded to channel.
*/
} else {
/**
show all 22 linespubnub.listFiles()
.channel("my_channel")
.async(result -> {
result.onSuccess(res -> {
System.out.println("files status: " + res.getStatus());
System.out.println("files status: " + res.getNext());
System.out.println("files status: " + res.getCount());
System.out.println("files status: " + res.getCount());
for (PNUploadedFile file : res.getData()) {
System.out.println("files fileId: " + file.getId());
System.out.println("files fileName: " + file.getName());
System.out.println("files fileSize: " + file.getSize());
System.out.println("files fileCreated: " + file.getCreated());
}
}).onFailure(exception -> {
show all 18 lines# synchronous
pubnub.list_files().channel("my_channel").sync()
# multithreaded asynchronous
def callback(response, status):
pass
pubnub.list_files().channel("my_channel").pn_async(callback)
pubnub.listFiles(
channel: "my_channel"
) { result in
case let .success(response):
print("There are \(response.files.count) file(s) found")
if let nextPage = response.next {
print("The next page used for pagination: \(nextPage)")
}
case let .failure(error):
print("An error occurred while fetching the file list: \(error.localizedDescription)")
}
import 'package:pubnub/pubnub.dart';
void main() async {
var pubnub = PubNub(
defaultKeyset: Keyset(
subscribeKey: 'sub-c-abc-123', // Replace with your subscribe key
publishKey: 'pub-c-def-456' // Replace with your publish key
),
);
try {
var files = await pubnub.files.listFiles('my_channel');
print('Number of files uploaded: ${files.count}');
for (var file in files.filesDetail) {
show all 21 lines