# qicore.File ¶

Import:

import qi

app = qi.Application()       # qi.Application must be instantiated first
qicore = qi.module("qicore") # Load and import the qicore module

See qi.Module API and qi.Application API documentation for more details about importing modules.

Note: In the following code examples, this previous import code sample is assumed to prefix the example code. For a complete working example, see Complete example : Alice’s Image Store Service .

## Summary ¶

File provides a way to open a file in read-only mode on the local file system and share the content of this file with potentially remote services.

We provide algorithms to copy a remote file’s content to make a local copy of it, using the copyToLocal function or FileCopyToLocal type.

## Reference ¶

See qi::File C++ API for complete API reference.

## Detailed Usage Description ¶

The following examples are partial for clarity. For a complete working example , see section Complete example : Alice’s Image Store Service .

### Opening a file in read-only mode for sharing access ¶

Once qicore module is loaded , use openLocalFile to open the file in sharing read-only mode:

file = qicore.openLocalFile("valid/path/to/file.ext")

In this example, the file object can be passed to a service API requesting a File , making the content of the file available to the service even if remote.

If the file does not exist, an exception will be thrown.

The lifetime of the file access is extended by the shared ownership between all the File , even if the instance is remote.

The File object is kept alive and the file access open by default until all File objects referring owning it are destroyed. The file access is automatically closed when File is destroyed.

Once you don’t need it anymore and want to explicitly stop owning the access, you can stop referencing the file access. The file access will be closed if there is no other owner still using it.

def someServiceOperation(file):
# Do some work  with file...

# No need to work with the file anymore.
del file # From now on, file is not usable anymore.
# If we were the only one accessing this file,

A service can request read-only access to the content of a file by using File as argument.

Similarly, a service can provide read-only access to a file by having a function return a File .

class MyService:
#...

# Store a copy of the provided file, associated with the provided name.
def storeFile(fileToStore, name):
#...

def getFile(name):
#...

#...

(This is a partial example, see Complete example : Alice’s Image Store Service for complete working examples.)

In this example, the user of the service can provide access to a file this way:

def backup(name, pathFileToStore):
service = app.session.service('MyService')
file = qicore.openLocalFile(pathFileToStore)
service.storeFile(file, name)
# At this point, the service have a copy of the file and can start to work with it.

and acquire access to a file content provided by the service this way:

def restore(name): # service is a MyService instance
service = app.session.service('MyService')
file = service.getFile(name)

if file:
# Then work with the file content.
# ...

### Make a local copy of a provided file ¶

We can use the copyToLocal function to make a local copy of the file provided through a File . The copyToLocal function will transfer a copy of the content of the file to the local file system, even if the original file is on a remote file system.

For example, if we want a service function to make a full copy of a provided file, in a local temporary location, before doing any more work (after loading qicore module ):

class MyService:
#...

def storeFile(fileToStore, name): # fileToStore is a qicore.File instance

# First, make a local copy in a temporary files directory:
tempFilePath = generateTemporaryFilePath()
qicore.copyToLocal(fileToStore, tempFilePath) # This call wait for the end of the copy.

# We now have a local copy of the remote file,
# we don't need the remote access anymore.
fileToStore = None

# Now we can work with the local copy of the file:
storeFileInDatabase(name, tempFilePath)

In the same way, we can provide access to the data of the file by returning a File :

class MyService:
#...

def getFile(name):

fileLocation = findFileLocation(name)

if os.path.isfile(fileLocation):
# Now we can open it and provide it to the user for reading.
return qicore.openLocalFile(fileLocation)

# We didn't find the file!
return None

Then the user can retrieve a copy of the file and work with it:

def restore(service, name, fileLocation):

file = service.getFile(name)

if file: # The file was found.
# We want to make a local copy before working on the file.
qicore.copyToLocal(file, fileLocation)

# We don't need the remote access anymore.
del file

# Now work on the file located at fileLocation.
workOnFile(fileLocation)

### Observe the progression of a file copy, transfer or other long operations ¶

Potentially long file operations like copyToLocal block until the end of the operation except if it is called with _async=True as parameter which will make the function return a qi.Future .

To wait for the end of the operation, we just wait for the future to be set (after loading qicore module ):

def printFinished():
printf("File Transfer Finished!")

def fetchFile(file): # file is a qicore.File instance

temporaryFilePath = qi.makeTemporaryFilePath()

# We copy the file on a temporary work location on the local filesystem,
# but we don't wait for the transfer to end.
transfer = qicore.copyToLocal(file, temporaryFilePath) # transfer is a qi.Future

# We want to log the end of the transfer:
transfer.then(printFinished)

# Do some additional work while the file is transfered.

# Now we wait until the end of the operation if it's not finished yet.
transfer.wait() # Don't wait for futures in real code, you should use .then() instead.
del file
del transfer

workOnFile(temporaryFilePath)

(This is a partial example, see Complete example : Alice’s Image Store Service for complete working examples.)

In this example we want to be notified about the end of the operation, so we can connect a callback to the future. However, using only a future, we cannot get progress information about the transfer.

To get progress information and be able to connect callbacks to the different steps of the operation before the operation starts, we can use the FileCopyToLocal type instead of copyToLocal function:

def printStatus(status): # see C++ API qi.FileOperation.Status for values
if status == 2:                        # Status_Finished
qi.info("File Transfer Finished!")
elif status == 3:                      # Status_Failed
qi.info("File Transfer Failed!")
elif status == 4:                      # Status_Canceled
qi.info("File Transfer Canceled!")

# We ignore the other status.

def printProgress(progress):
qi.info("#### File Transfer Progress = {0}%".format(progressValue * 100) )

def fetchFile(file): # file is a qicore.File instance
temporaryFilePath = makeTemporaryFilePath()

# Instead of launching the copy immediately, we prepare it by setting up
# the object which represent that operation.
fileCopy = qicore.FileCopyToLocal(file, temporaryFilePath)

# We extract the progress notifier associated with the operation.
notifier = fileCopy.notifier()

# We want to log the state changes of the transfer.
notifier.status.connect(printStatus)

# We also to log the progress of the transfer.
notifier.progress.connect(printProgress)

# We are ready to launch the copy now.
ft = fileCopy.start()

# Do some additional work while the file is transfered.

# Now we wait until the end of the operation if it's not finished yet.
ft.wait() # Don't wait for futures in real code, you should .connect()

# We don't need the file access anymore.
del file

workOnFile(temporaryFilePath)

The FileCopyToLocal type is an implementation of FileOperation which represents the copy/transfer operation which is not started upon creation. As this example demonstrates, the user can then plug callbacks to signals and properties provided by ProgressNotifier which is provided by the FileOperation.notifier() member function. The user can then start the copy operation by calling the FileOperation.start() member function.

Similarly, the side of the code which opened the file and provided access to it can also follow the progression of the on-going operations on the file by using the File.operationProgress() member function. This function provides access to a ProgressNotifier which is updated by the current file operation on the file.

def printStatus(status) # as before
def printProgress(progress) # as before

def storeFile(service, name, pathToFileToStore):
file = qicore.openLocalFile(pathToFileToStore)

# Before sending the access to the file, connect progress logging callbacks.
copyProgress = file.operationProgress()
copyProgress.status.connect(printStatus)
copyProgress.progress.connect(printProgress)

service.storeFile(file, name)

# At this point, the service have a copy of the file and can start to work with it.

## Complete example : Alice’s Image Store Service ¶

The following code samples are extracted from the complete example project located in the worktree at sdk/libqicore/libqicore/example/file/

In this example, Alice designs a service which provides storage for image files. Then Bob writes an application which accesses Alice’s image storage service and works with it.

### ImageStore ¶

Alice’s ImageStore service is simple and straightforward. It is very similar to the example code in previous sections.

In particular:

Note the File usage which allows the user to provide access to a file, or to acquire a stored file access. See api-py-file-import for importing qicore module.

To implement the store_image function, Alice first acquires and copies the user file in a temporary location, then does some work to register it in the store’s database.

This is of course a simpler implementation, similar to the get_image() function implementation.

### ImageStore User Code ¶

Meanwhile, Bob wrote his application to acquire Alice’s ImageStore instance, then do some basic work with it.

imagestore.py:

file_example.py: