{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Chapitre 7 : \"Accès aux données\"\n",
    "\n",
    "### <span class=\"bg-info\">« *Cookie : Anciennement petit gâteau sucré, qu’on acceptait avec plaisir. Aujourd’hui : petit fichier informatique drôlement salé, qu’il faut refuser avec véhémence.* »</span>\n",
    "\n",
    "Luc Fayard $-$ Dictionnaire impertinent des branchés\n",
    "\n",
    "***"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### <span class=\"bg-success\">CE QU'IL FAUT RETENIR SUR LES FICHIERS</span>\n",
    "\n",
    "- Un fichier est une séquence d'octets stockée sur un support.\n",
    "- Il est identifié par un *chemin d'accès* comportant éventuellement des répertoires à traverser ainsi que le `nom_du_fichier` (on utilise généralement juste `nom_du_fichier`).\n",
    "- Il s'ouvre avec la fonction standard `open()`, qui retourne un objet fichier, et doit être refermé avec la méthode `close()` de cet objet.\n",
    "- À l'ouverture, il faut spécifier le mode d'accès, principalement lecture / écriture / ajout.\n",
    "- Nous utilisons le mode d'accès par défaut sous forme de texte <sup>(1)</sup> ; il est alors fortement conseillé de fournir le paramètre optionnel spécifiant l'encodage utilisé pour le stockage des caractères dans le fichier <sup>(2)</sup>.\n",
    "- Les méthodes d'écriture et de lecture manipulent des chaînes de caractères (ou des listes de chaînes de caractères).\n",
    "- L'accès se fait séquentiellement <sup>(3)</sup>, comme une tête de lecture parcourant une bande magnétique.\n",
    "\n",
    "\n",
    "> <sup>(1)</sup> Il existe un mode d'accès sous forme d'octets.\n",
    "\n",
    "> <sup>(2)</sup> Dans ces exercices, nous utilisons l'encodage `utf8` pour les fichiers textes.\n",
    "\n",
    "> <sup>(3)</sup> Des méthodes spécifiques permettent de connaître la position de lecture/écriture dans le fichier et de la modifier pour accéder directement à une partie du fichier. Une autre méthode permet de retailler le fichier.\n",
    "\n",
    "### <span class=\"bg-success\">CE QU'IL FAUT RETENIR SUR LES RÉPERTOIRES ET CHEMINS</span>\n",
    "\n",
    "- Les fichiers sont stockés dans des arborescences de répertoires sur les supports de stockage, qui constituent des chemins d'accès.\n",
    "- Des fonctions spécifiques permettent de manipuler les répertoires sur les supports, mais aussi les chaînes de caractères qui représentent ces chemins d'accès.\n",
    "\n",
    "***\n",
    "\n",
    "Dans les exercices suivants, les fichiers de données nommés `indata_exo07_yyyy.txt` sont fournis dans le répertoire des donnés : `../data/`. \n",
    "\n",
    "Sauf si explicitement demandé, les fichiers ne devront pas être chargés d'un bloc en mémoire (on se réserve la possibilité de traiter de très gros fichiers) mais lus/écrits au fur et à mesure.\n",
    "\n",
    "***"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_01 ✓\n",
    "Écrire une fonction `lecture()` prenant en paramètre un nom de fichier et retournant une liste des lignes de ce fichier en ne prenant qu'une ligne sur deux.\n",
    "\n",
    "Pour les tests, appeler cette fonction avec le nom de fichier `\"../data/indata_exo07_sandmusset.txt\"` (lettre de George Sand à Alfred de Musset)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_01"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_02 ✓\n",
    "Écrire une fonction `ecriture()` prenant en paramètre un nom de fichier ainsi qu'une liste de noms. Cette fonction écrit dans le fichier indiqué des lignes composées du numéro d'ordre (en commençant à 1) suivi d'un caractère `\":\"` de séparation puis du nom correspondant dans la liste.\n",
    "\n",
    "Pour les tests, utiliser le nom de fichier `\"../data/out_exo07_02_test.txt\"` et la liste `[\"Yves\", \"Maude\", \"Heinrich\", \"Fiona\", \"Malik\"]`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_02"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_03 ✓✓\n",
    "Écrire une fonction `combine()` prenant en paramètre deux noms de fichiers et affichant les lignes de même index de ces deux fichiers, séparées par un caractère espace, en nettoyant les retours à la ligne surnuméraires. On traitera comme on le souhaite le cas où un des fichiers contient plus de lignes que l'autre, tant que cela permet au programme de se terminer proprement et d'avoir un comportement cohérent.\n",
    "\n",
    "Pour les tests, reconstruire le texte de la tablette que Zadig a malencontreusement brisée en deux morceaux, contenus dans les fichiers : `\"../data/indata_exo07_tablette1.txt\"` et `\"../data/indata_exo07_tablette2.txt\"`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_03"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_04 ✓\n",
    "Écrire une fonction `stocke_points()` prenant en paramètre un nom de fichier ainsi qu'une liste de points où chaque point est représenté sous la forme d'un tuple de trois coordonnées (nombres flottants). La fonction stocke cette liste de points dans le fichier, au format texte, avec une ligne par point et en séparant les valeurs avec des caractères `\";\"`.\n",
    "\n",
    "Pour les tests, utiliser le nom de fichier `\"../data/out_exo07_04_test.txt\"` et la liste `[(0.0, 0.0, 0.0), (-1.5, 1.2, -3.4), (12.78, -4.25, 11.32), (0.03, -3e-2, 11.4)]`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_04"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_05 ✓✓\n",
    "Écrire une fonction `charge_points()` prenant en paramètre un nom de fichier et retournant une liste de points composés chacun d'un tuple de trois coordonnées (nombres flottants). Les coordonnées des points sont stockées dans le fichier au format texte, sur une ligne pour chaque point, les valeurs séparées par des caractères `\";\"`.\n",
    "\n",
    "Pour les tests, utiliser le fichier `\"../data/indata_exo07_points.txt\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_05"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_06 ✓\n",
    "Écrire une fonction `copie_debut()` prenant en paramètre deux noms de fichier (le premier pour le fichier à traiter et le second pour le fichier résultat) et un entier $n$ (par défaut à 10) représentant un nombre de lignes. La fonction recopie les $n$ premières lignes du fichier à traiter dans le fichier résultat.\n",
    "Pour les tests, utiliser le fichier à traiter `\"../data/indata_exo07_lievretortue.txt\"` (*Le lièvre et la tortue*, Jean de la Fontaine), le fichier résultat `\"../data/out_exo07_06_test.txt\"` et recopier les 7 premières lignes. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_06"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_07 ✓✓\n",
    "Écrire une fonction `copie_fin()` prenant en paramètre deux noms de fichier (le premier pour le fichier à traiter et le second pour le fichier résultat) et un entier $n$ (par défaut à 10) représentant un nombre de lignes. La fonction recopie les $n$ dernières lignes du fichier à traiter dans le fichier résultat (on rappelle qu'il est interdit d'avoir l'ensemble du fichier à traiter en mémoire — on accepte que les lignes à recopier y soient).\n",
    "\n",
    "Pour les tests, utiliser le fichier à traiter `\"../data/indata_exo07_bateauivre.txt\"` (*Le bateau ivre*, Arthur Rimbaud), le fichier résultat `\"../data/out_exo07_07_test.txt\"` et recopier les 9 dernières lignes. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_07"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_08 ✓✓\n",
    "Écrire une fonction `charge_dico()` prenant en paramètre un nom de fichier et retournant un dictionnaire construit à partir des données lues. Les données dans le fichier sont de la forme de lignes contenant `nom=valeur`. Les espaces autour du nom et autour de la valeur doivent être supprimés. Le dictionnaire retourné indice les valeurs par les noms. Le fichier peut contenir des lignes vides, qui seront ignorées.\n",
    "\n",
    "Pour les tests, utiliser le fichier `\"../data/indata_exo07_depts.txt\"` (départements et préfectures), puis le fichier `\"../data/indata_exo07_equa.txt\"` (série d'équations)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_08"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_09 ✓\n",
    "\n",
    "Écrire une fonction `sauve_dico()` prenant en paramètre un nom de fichier et un dictionnaire utilisant des chaînes pour indexer des chaînes. La fonction stocke les couples clé/valeur du dictionnaire dans les lignes du fichier, au format `clé=valeur`, en les ordonnant par ordre croissant des clés.\n",
    "\n",
    "Pour les tests, créer le fichier `\"../data/out_exo07_09_test.txt\"` à partir du dictionnaire :\n",
    "```python\n",
    "dict(un=\"one\", deux=\"two\", onze=\"eleven\", calculquatre=\"4 = 2 + 2\")\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_09"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_10 ✓\n",
    "Écrire une fonction `compte_lignes()` prenant en paramètre un nom de fichier, qui compte et retourne le nombre de lignes contenues dans ce fichier. \n",
    "\n",
    "Pour les tests, utiliser le fichier `\"../data/indata_exo07_blablator.txt\"` (cf. le [blablator](http://www.charlatans.info/blablator))."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_10"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_11 ✓\n",
    "\n",
    "Écrire une fonction `trouve_index()` prenant en paramètre un nom de fichier et une chaîne. La fonction retourne la liste des numéros des lignes du fichier qui contiennent la chaîne. On comptera les lignes des fichiers à partir de 1 pour la première ligne.\n",
    "\n",
    "Pour les tests, utiliser le fichier `\"../data/indata_exo07_blablator.txt\"` en cherchant la chaîne `\"Tout le monde sait\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_11"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### exo07_12 ✓\n",
    "\n",
    "Écrire une fonction `stocke_index()` prenant en paramètre deux noms de fichier ainsi qu'une chaîne cible. La fonction écrit dans le second fichier les numéros des lignes du premier fichier qui contiennent la chaîne cible. Les lignes seront comptées à partir de 1 pour la première ligne et on aura un seul numéro par ligne dans le second fichier. \n",
    "\n",
    "Pour les tests, utiliser le fichier `\"../data/indata_exo07_blablator.txt\"`, créer le fichier `\"../data/out_exo07_12_test.txt\"` en cherchant la chaîne `\"Tout le monde sait\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_12"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_13 ✓✓\n",
    "\n",
    "Écrire une fonction `somcol()` prenant en paramètre un nom de fichier et retournant une liste de sommes. Dans le fichier à traiter, chaque ligne contient une série de nombres séparés par des espaces, toutes les lignes comportent le même nombre de nombres.\n",
    "\n",
    "La fonction fait la somme des nombres qui sont dans la même colonne dans le fichier texte.\n",
    "\n",
    "Exemple de fichier :\n",
    "```text\n",
    "\t324     327.32      14332\n",
    "\t1432    4781        9977.24\n",
    "\t431.3   25013.13    786.43\n",
    "```\n",
    "\n",
    "Pour les tests, utiliser le fichier `\"../data/indata_exo07_popsurf.txt\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_13"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_14 ✓✓\n",
    "\n",
    "Écrire un script comprenant une fonction `filtre(nom_fic_lire, nom_fic_ecrire, seuil_bas, seuil_haut)` qui prend en paramètre les noms de deux fichiers ainsi que deux valeurs, limites basse et haute, et qui écrit dans le fichier de nom `nom_fic_ecrire`, les lignes du fichier de nom `nom_fic_lire` qui contiennent une valeur numérique située hors des deux seuils (seuils non compris).\n",
    "\n",
    "Comme cette fonction doit pouvoir travailler sur des fichiers très volumineux, il est interdit de charger en mémoire l'ensemble du contenu du fichier nom_fic_lire au même moment.\n",
    "\n",
    "Pour les tests, utiliser le fichier de données `\"../data/indata_exo07_hors_bande.txt\"` et créer le fichier de données filtrées `\"../data/out_exo07_14_res.txt\"`. On prendra l'intervalle à exclure suivant : $[30.0, 70.0]$.\n",
    "\n",
    "Le script comportera un auto-test de vérification de la fonction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_14"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### exo07_15 ✓✓✓\n",
    "\n",
    "*Exercice avancé permettant de travailler sur la mémorisation de position et le déplacement dans un fichier texte.*\n",
    "\n",
    "Écrire une fonction `indexation()` prenant en paramètre deux noms de fichiers. Le premier fichier est un fichier d'expériences, potentiellement très gros (ne tenant pas en mémoire vive), que l'on veut indexer. Le second fichier est l'index créé par cette fonction. \n",
    "\n",
    "Le fichier d'expériences contient des données issues de séries d'expériences. Chaque collection de données pour une expérience commence par une ligne *débutant* par la chaîne `\"%%EXPERIMENT\"`, suivie par des lignes qui contiennent les données de cette expérience. \n",
    "\n",
    "Le fichier d'index créé doit identifier les lignes des débuts des blocs d'expériences et mémoriser dans le fichier d'index deux colonnes : numéro de ligne de début de bloc, position du premier caractère de cette ligne dans le fichier.\n",
    "\n",
    "**Attention :** dans cet exercice *vous ne pouvez pas* utiliser l'instruction d'itération `for` sur fichier, qui réalise une lecture implicite, vous *devez* passer par la méthode `readline()` (qui retourne une chaîne vide lorsque la fin de fichier est atteinte). \n",
    "\n",
    "**Note :** On rappelle l'existence de la méthode [`tell()`](https://docs.python.org/3.6/library/io.html#io.TextIOBase.tell), qui permet de connaître la *position du curseur* de lecture/écriture dans un fichier (ce qui permet ensuite de positionner directement ce *curseur* à cet endroit avec la méthode [`seek(…)`](https://docs.python.org/3.6/library/io.html#io.TextIOBase.seek)).\n",
    "\n",
    "Pour les tests, utiliser le fichier d'expérience `\"../data/indata_exo07_expe.txt\"` et créer le fichier d'index `\"../data/out_exo07_15_res.txt\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# exo07_15\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
