Download a node (and its associated files as a zip archive)
I put together a proof of concept module real quick, which exports files based on assumptions about field_type (image, file and media).

To test it out, put the following code in a custom module, then go to /export-entity/node/nid to export a node.

&lt;?php

/**
 * Implements hook_menu().
 */
function export_entity_menu() {
  $items['export-entity/%/%entity_object'] = array(
    'page callback' =&gt; 'export_entity_page_callback',
    'page arguments' =&gt; array(2, 1),
    'load arguments' =&gt; array(1),
    'access arguments' =&gt; array('access administration pages'),
  );

  return $items;
}

/**
 * Export entity page callback.
 *
 * @param object $entity
 * @param string $entity_type
 *
 * @throws EntityMalformedException
 * @throws EntityMetadataWrapperException
 * @throws Exception
 */
function export_entity_page_callback($entity, $entity_type) {

  $wrapper = entity_metadata_wrapper($entity_type, $entity);
  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);

  $file_fields = field_read_fields(array(
    'entity_type' =&gt; $entity_type,
    'bundle' =&gt; $bundle,
    'type' =&gt; array('image', 'file', 'media'),
  ));

  $field_files = array();
  foreach ($file_fields as $field_name =&gt; $field_config) {
    $files = $wrapper-&gt;{$field_name}-&gt;value();
    if ((int) $field_config['cardinality'] === 1) {
      $files = array($files);
    }
    foreach ($files as $file) {
      $field_files[$file['fid']][] = $field_name;
    }
  }

  $export_filename = drupal_tempnam(file_directory_temp(), 'entityexport_');

  $zip = new ZipArchive();
  if (!($zip-&gt;open($export_filename, ZipArchive::CREATE))) {
    throw new Exception(t('Unable to create zip archive'));
  }

  $entity_data = entity_var_json_export($wrapper-&gt;raw());
  $zip-&gt;addFromString(sprintf('%s_%d.json', $entity_type, $id), entity_var_json_export($entity_data));

  // Load and attach all files/file entities
  $files = file_load_multiple(array_keys($field_files));
  foreach ($files as $file) {
    $folder = reset($field_files[$file-&gt;fid]);
    $file_path = drupal_realpath($file-&gt;uri);
    $zip-&gt;addFile($file_path, $folder . '/' . $file-&gt;filename);
    $zip-&gt;addFromString($folder . '/' . $file-&gt;filename . '_entity.json', entity_var_json_export($file));
  }
  $zip-&gt;close();

  // Copy archive to public storage and redirect to its URL.
  $public_uri = file_default_scheme() . '://entity-export/' . $entity_type;
  file_prepare_directory($public_uri, FILE_CREATE_DIRECTORY);
  $public_uri .= '/' . basename($export_filename) . '.zip';

  $public_path = file_unmanaged_move($export_filename, $public_uri);
  $public_url = file_create_url($public_path);

  drupal_goto($public_url);
}


Note that this should be done using a batch callback and/or a cron-job, especially if you expect to get alot of data - which may cause the script to time out and/or run out of memory (although it really shouldn't).