# Python Microsoft Fabric - Sending and receiving files

Load files that other systems put in the lakehouse into tables, and write exports to it.

This page uses two kinds of files in the lakehouse's `Files` section - incoming files that another system writes, and export files that a service writes. The first kind is loaded into a table, the second is written from rows.

OneLake is where every lakehouse stores its tables and files. The `Files` section in the lakehouse explorer is a folder in OneLake, and the connection reads and writes there directly.

> **What you need from your Fabric admin**
>
> The workspace ID and the lakehouse ID, from the address bar when the lakehouse is open. Two folders in the lakehouse's Files section - `incoming`, for files from other systems, and `exports`, for files the service writes - created once in the lakehouse explorer with New subfolder.

## File paths {#file-paths}

Every file path starts with the lakehouse and continues into its `Files` section, for example `Operations.Lakehouse/Files/incoming/payments-2026-03.csv`. The lakehouse ID can be used in place of `Operations.Lakehouse`, and the services on this page use the ID.

## The incoming file {#the-incoming-file}

Another system writes one CSV file a month to `Files/incoming`, with the same columns as the `invoices` table:

The service lists the folder, loads each file into the table and deletes the file after the load, so no file is loaded twice.

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class LoadPaymentFiles(Service):

    def handle(self):

        workspace_id = '11111111-2222-3333-4444-555555555555'
        lakehouse_id = '66666666-7777-8888-9999-000000000000'

        conn = self.microsoft.fabric['My Fabric']

        loaded = []

        # Everything currently in the incoming folder ..
        listing = conn.onelake_list(workspace_id, f'{lakehouse_id}/Files/incoming')

        for path in listing['paths']:

            # .. skipping subfolders ..
            if path['isDirectory']:
                continue

            # .. the listing gives the full path, the load needs it relative to the lakehouse ..
            full_path = path['name']
            _, relative_path = full_path.split('/', 1)

            # .. load it into the table, adding to what is there ..
            location = conn.load_table(workspace_id, lakehouse_id, 'invoices', relative_path, mode='Append')
            conn.wait_for_operation(location)

            # .. and remove the file so the next run does not see it again.
            conn.onelake_delete(workspace_id, full_path)
            loaded.append(relative_path)

        self.response.payload = {'loaded': loaded}
```

After the run, the folder is empty and the table has a new row for each line of the file:

## The monthly export {#the-monthly-export}

The second service writes a monthly CSV file to `Files/exports`. The rows come from another system, and the service turns them into CSV and writes the file.

```python
# -*- coding: utf-8 -*-

# stdlib
import csv
import io

# Zato
from zato.server.service import Service

class WriteInvoiceExport(Service):

    def handle(self):

        workspace_id = '11111111-2222-3333-4444-555555555555'
        lakehouse_id = '66666666-7777-8888-9999-000000000000'
        month = '2026-03'

        conn = self.microsoft.fabric['My Fabric']

        # The month's totals from the source system, one dict per location.
        rows = [
            {'location': 'Riverside',   'invoiced': 2895.50},
            {'location': 'Oak Hill',    'invoiced': 1840.00},
            {'location': 'Maple Grove', 'invoiced': 415.75},
        ]

        # Turn the rows into CSV text ..
        buffer = io.StringIO()
        writer = csv.DictWriter(buffer, fieldnames=['location', 'invoiced'])
        writer.writeheader()
        writer.writerows(rows)

        text = buffer.getvalue()
        data = text.encode('utf-8')

        # .. and write the file to the exports folder.
        file_path = f'{lakehouse_id}/Files/exports/invoices-{month}.csv'
        conn.onelake_write(workspace_id, file_path, data)

        self.response.payload = {'file': file_path, 'rows': len(rows)}
```

The service writes `Files/exports/invoices-2026-03.csv`:

`onelake_write` creates the file or replaces it if it exists, so running the export twice for the same month leaves one file.

## See also {#see-also}

- [Loading data into tables](https://zato.io/docs/dev/examples/cloud/fabric/loading-tables.html) - Appending and replacing tables from rows a service already holds
- [Sending reports on a schedule](https://zato.io/docs/dev/examples/cloud/fabric/scheduled-reports.html) - A CSV delivered by SFTP and email
- [Files](https://zato.io/docs/dev/examples/cloud/fabric/api/files.html) - onelake\_list, onelake\_read, onelake\_write and onelake\_delete in detail

## Learn more {#learn-more}

- [Development documentation](https://zato.io/docs/dev/) - Everything about writing services, in one place
- [Requests and responses](https://zato.io/docs/dev/request-response/) - What a service receives, what it returns and how to shape both
- [Integration examples](https://zato.io/docs/dev/examples/) - Ready-made code for the systems you are likely to connect to
- [IDE and debugging](https://zato.io/docs/dev/ide/) - Write services in the Dashboard or in your own editor
- [Data models](https://zato.io/docs/dev/model/) - Declare inputs and outputs and have them validated for you
- [In-depth API tutorial](https://zato.io/tutorials/main/01.html) - The full platform tutorial, from installation to production patterns
