Download Documentación externa
Document related concepts
no text concepts found
Transcript
Índice Introducción........................................................... ......................................2 1. Descripción del problema..................................................................3 1.1 Planteo del problema...................... .................................................3 1.2 Objetivos...........................................................................................3 1.3 Requerimientos ................................................................................3 2. Abstracción........................................................................................4 2.1 Especificación de la clase................................................................4 2.2 Operaciones y métodos...................................................................6 2.3 Eficiencia del programa...................................................................6 2.4 Especificación del programa............................................................7 2.5 Arquitectura del programa................................................................8 3. Implementación..................................................................................9 3.1 Modelo de la clase............................................................................9 3.2 Invariante de la clase......................................................................10 3.3 Arquitectura interna del programa...................................................10 3.4 Compilador usado...........................................................................12 3.5 ¿Cómo compilar el programa? .......................................................12 4. Guía de uso del programa................................................................13 5. Datos de prueba...............................................................................14 6. Código fuente...................................................................................16 Reconocimientos.........................................................................................17 Bibliografía...................................................................................................18 1 Introducción El presente programa pretende leer los nombres de los archivos y subdirectorios que tienen como raíz otro subdirectorio, el cual es especificado por parte del usuario, de manera tal que se pueda desplegar en pantalla los nombres de esos archivos y subdirectorios de forma ordenada. Tanto la documentación interna y externa de este programa, así como el código fuente del mismo, pueden ser accesados en la siguiente dirección: http://www.angelfire.com/ak5/juancho/tareas_p2/tarea6/tarea_6.htm 1. Descripción del problema 2 1.1 Planteo del problema El problema radica en el siguiente aspecto específico: - Implementar un programa que logre leer los nombres de archivos y subdirectorios de un subdirectorio raíz, el cual lo determina el usuario; esto mediante el uso de procesos recursivos y un árbol binario. 1.2 Objetivos El objetivo del programa es: - Lograr realizar la lectura de los archivos y subdirectorios mediante el uso de métodos o funciones recursivas y un contenedor de datos abstracto (árbol binario). 1.3 Requerimientos Para poder concretar los objetivos, se requiere: - - Implementar un programa que realice la lectura de los subdirectorios y archivos, esto bajo la premisa que los nombres de los mismos deben aparecer ordenadamente en la pantalla. Utilizar métodos recursivos tanto en el árbol binario como en la lectura de los nombres de los archivos y los subdirectorios. Utilizar un árbol binario, el cual va a almacenar los nombres de los archivos y subdirectorios. 2. Abstracción 3 2.1 Especificación de la clase La especificación de la clase FolderReader es la siguiente: Los atributos privados de la clase son: - string source; Tree< string > FileTree; Las funciones públicas de la clase FolderReader son: - FolderReader (const char* argv1); FolderReader ();//constructor por defecto ~FolderReader(){}; - void FolderReader::replaceSymbol(string& s); void getInformation (const string& source); void getInfo(const string& src); - Esta clase es la que realiza realmente las funciones del programa. Contiene como atributos un string, él cual la información con la cual se trabaja en ese momento, y un árbol binario, en él cual se guarda la información para luego desplegarla de forma ordenada. Entre sus métodos están el constructor y constructor por defecto que inicializan los objetos de tipo FolderReader y el destructor. Además contiene dos métodos que realizan la función de leer los archivos y insertarlos en l árbol. El primero es void getInformation (const string& source) que se encarga de los casos donde la información esta vacía o nula. El segundo void getInfo(const string& src) que se encarga de insertar toda la información en el árbol de forma ordenada para su posterior despliegue en pantalla. Hay que tomar en cuenta que dentro de este método es necesario el uso de métodos creados en la tarea anterior de manejo de archivos para poder leer con facilidad la información requerida. Por ultimo esta void replaceSymbol(string& s) que cambia todos los símbolos para que estos puedan ser leídos por los métodos, ya que algunos solo aceptan símbolos definidos y cesan de funcionar o funcionan erróneamente sin estos. 4 La especificación de la clase Tree es la siguiente: Los atributos privados de la clase son: - TreeNode< NODETYPE > *rootPtr; Las funciones públicas de la clase Tree son: - Tree(); void insertNode( const NODETYPE & ); void preOrderTraversal() const; void inOrderTraversal() const; void postOrderTraversal() const; Las funciones privadas de la clase Tree son: - void insertNodeHelper( TreeNode< NODETYPE > **, const NODETYPE & ); void preOrderHelper( TreeNode< NODETYPE > * ) const; void inOrderHelper( TreeNode< NODETYPE > * ) const; void postOrderHelper( TreeNode< NODETYPE > * ) const; Esta clase fue tomada del libro de Deitel para asegurar que su funcionamiento no tuviera ningún error, en el programa se utiliza para guardar los nombres de los subdirectorios y archivos. Después por medio de un recorrido se puedan desplegar en forma ordenada los archivos. La clase en si contiene dos tipos de métodos uno para insertar nodos al árbol (void insertNode( const NODETYPE & ))y los otros que son diferentes modos de recorrer el árbol. La raíz del árbol es el directorio donde el usuario decide empezar y para el funcionamiento de esta clase es necesaria la clase Treenode(nodos que se utilizan en la construcción del árbol). 5 La especificación de la clase Treenode es la siguiente: Los atributos privados de la clase son: - TreeNode< NODETYPE > *leftPtr; NODETYPE data; TreeNode< NODETYPE > *rightPtr; Las funciones públicas de la clase Treenode son: - TreeNode( const NODETYPE &d ) - NODETYPE getData() const { return data; } La clase friend de la clase Treenode es: - friend class Tree< NODETYPE >; Esta clase se incluye en el programa, porque es necesaria para el funcionamiento de la clase Tree(mencionada anteriormente), ya que esta provee los nodos necesarios para la construcción del árbol y el funcionamiento de los mismo. 2.2 Operaciones y métodos En este programa, se especifican la siguiente función: a44239_a45214.cpp - void readFiles (const char* argv1); 2.3 Eficiencia del programa La arquitectura lógica del programa va a responder, principalmente, a 3 módulos, en los cuales se trata de realizar un manejo eficiente de la memoria, por cuanto en el programa se opta por la creación de un objeto del tipo FolderReader, el cual va a determinar como se realizan las operaciones, el orden en que se ejecutan los métodos y el ciclo de vida de las variables que se necesitan para concretar los métodos. A nivel de tiempo de ejecución, no se puede garantizar que el programa corra de forma rápida o lenta, ya que esto dependerá fuertemente de los distintos métodos recursivos que se ejecutan en el programa, que, dependiendo de la profundidad del directorio fuente escrito en la línea de comandos (no es lo mismo que lea desde c: que desde un subdirectorio que solamente tiene archivos), pueden producir una gran cantidad de llamados a métodos, por lo que haría muy lento el programa. 6 2.4 Especificación del programa La especificación del programa responde a este esquema, en el cual se pasa el directorio raíz – el cual va a fungir como la raíz del árbol binario -, el cual se obtiene por medio de la línea de comandos (argv[1]): El programa va a tomar un solo argumento de la línea de comandos, el cual se va a referir a locación del subdirectorio desde donde va a iniciar la lectura de archivos. Este argumento se pasa a la clase FolderReader, el cual se va a encargar de leer el contenido de ese subdirectorio y los subdirectorios que dependan del mismo (subdirectorios hijos), consecuentemente este módulo se encarga de recopilar los nombres de los archivos y subdirectorios que dependan del subdirectorio padre especificado por el argumento escrito en la línea de comandos, además de almacenar esos nombres en un árbol binario. Este árbol binario posee 2 módulos, la clase propia del árbol, la cual contiene los métodos de insertar, eliminar y de recorrido, igualmente, se tiene a la clase Treenode, la cual representará a los nodos del árbol. 7 2.5 Arquitectura del programa El presente esquema, va a responder, básicamente, a la arquitectura del programa: <iostream> <iostream.h> <string> <string> <io.h> +----------+ |Treenode.h| +----------+ +------+ |Tree.h| +------+ +----------------+ +----------------+ |44239_a45214.cpp| |FolderReader.cpp| +----------------+ +----------------+ +-----------------+ +----------------+ |a44239_a45214.obj| |FolderReader.obj| +-----------------+ +----------------+ +-----------+ | read.exe | +-----------+ 8 3. Implementación 3.1 Modelo de las clases El modelo UML de la clase FolderReader es: Class FolderReader - string source; - Tree< string > FileTree; + + + + + + FolderReader (const char* argv1); FolderReader ();//constructor por defecto ~FolderReader(){}; void FolderReader::replaceSymbol(string& s); void getInformation (const string& source); void getInfo(const string& src); El modelo UML de la clase Tree es: Class Tree - TreeNode< NODETYPE > *rootPtr; + + + + + - Tree(); void insertNode( const NODETYPE & ); void preOrderTraversal() const; void inOrderTraversal() const; void postOrderTraversal() const; void insertNodeHelper(TreeNode< NODETYPE > **, const NODETYPE & ); - void preOrderHelper( TreeNode< NODETYPE > * ) const; - void inOrderHelper( TreeNode< NODETYPE > * ) const; - void postOrderHelper( TreeNode< NODETYPE > * ) const; El modelo UML de la clase Treenode es: Class Treenode - TreeNode< NODETYPE > *leftPtr; - NODETYPE data; - TreeNode< NODETYPE > *rightPtr; + TreeNode( const NODETYPE &d ) : leftPtr( 0 ), data( d ), rightPtr( 0 ); + NODETYPE getData() const { return data; } 9 3.2 Invariante de la clase La invariante de este programa va a girar en torno al árbol binario, cuya propiedad principal es tener un nodo padre con 2 hijos señalando, respectivamente, a los subárboles izquierdo y derecho; por lo tanto, la invariante del programa verificará si existe el nodo padre y si ese nodo posee un valor determinado. bool Check_Ok(const Tree& tree){ if (tree.rooPtr == 0){ return false; }else{ if (tree.rooPtr->data == 0){ return false; }else{ return true; } Se verifica si existe un nodo raíz en el árbol ---------------------------------------------------Se verifica si ese nodo raíz tiene algún valor --------------------------------------------------Si el nodo raíz del árbol existe y tiene un valor, entonces el objeto está construido correctamente. } } Nota: Debido a razones de diseño (ya que se contempla al objeto FolderReader como el ente encargado de recolectar, dirigir y manipular la información referente a los nombres de archivos y subdirectorios) y al hecho que este programa solamente lee una vez los nombres de archivos y subdirectorios desde una ubicación determinada (es por esta razón que se opta por llamar a todos los métodos de la clase FolderReader necesarios para la lectura de los nombres de los archivos y subdirectorios desde el constructor del objeto de la clase FolderReader; consecuentemente, toda invariante va a retornar falso en el constructor de algún objeto, ya que estos objetos se encuentra en su proceso de creación e inicialización durante la ejecución del constructor – no vale la pena verificar que los mismos estén correctamente creados en esta etapa, porque no lo van a estar hasta que se termine la ejecución del constructor – ), no es necesario verificar la invariante del objeto reader de la clase FolderReader. 3.3 Arquitectura interna del programa Básicamente, el programa esta compuesto por las clases FolderReader, Tree y Treenode y por la siguiente función: a44239_a45214.cpp - void readFiles (const char* argv1); 10 La arquitectura interna del programa va girar en torno a la función la cual se invoca en la función main, dentro del archivo a44239_a45214.cpp: void readFiles (const char* argv1 ), void readFiles (const char* argv1){ FolderReader* reader = new FolderReader(argv1); delete reader; } Obtiene el directorio destino por medio de la línea de comandos ---------------------------------------------Se crea el objeto reader, el cual se encargará de leer los nombres de los archivos y subdirectorios que tengan al argumento de la línea de comandos como padre. ---------------------------------------------Se borra ejecuta el objeto FolderReader reader Complementariamente, se adjuntan explicaciones de los siguientes métodos: void getInfo(const string& src) – método que obtiene el nombre de los archivos en los subdirectorios fuente y los subdirectorios que dependan de este void FolderReader::getInfo(const string& src){ const char* actualDirectory = src.c_str(); char* directory = new char[strlen(actualDirectory) + strlen("*.*") + 1]; strcpy(directory, actualDirectory); strcpy(directory + strlen(actualDirectory), "*.*"); _finddata_t FILE_BLOCK; long hFile; if ( (hFile = _findfirst( directory, &FILE_BLOCK )) == -1L) { } else { char* name; string subdirectory; string sname; while( _findnext( hFile, &FILE_BLOCK ) == 0) { if( FILE_BLOCK.attrib & _A_SUBDIR ) { Se convierte el subdirectorio a leer de string a const char* . ---------------------------------------------Se crea un char*, ya que _findfirst sólo acepta char*. Poner atención en la longitud de este char*. ---------------------------------------------Se copia el nombre del subdirectorio a leer en char* directory. ---------------------------------------------Se copia “*.*”(leer todos los archivos) al nombre del subdirectorio a leer en char* directory. ---------------------------------------------Se crea un “objeto” de la struct _finddata_t ---------------------------------------------Si el subdirectorio que se está leyendo tiene archivos o más subdirectorios, se genera un número identificador y se le asigna a hFile, de lo contrario se devuelve -1L ---------------------------------------------Mientras existan archivos o subdirectorios, se leen los archivos ---------------------------------------------Si es un subdirectorio, se convierte el 11 sname = string(FILE_BLOCK.name); if (sname == ".." || sname == "."){ }else{ subdirectory = src; name = FILE_BLOCK.name; FileTree.insertNode(string(name)); subdirectory += string(name); subdirectory += "/"; nombre a string, se analiza si es un nombre válido, se almacena el nombre del subdirectorio en el árbol y se vuelve a invocar el método con un nuevo subdirectorio getInfo(subdirectory); Aquí se da la recursividad ---------------------------------------------Condición de parada de la recursividad(que no se esté procesando un subdirectorio) name = FILE_BLOCK.name; Se convierte el nombre del archivo a string y se almacena en el árbol } }else{ FileTree.insertNode(string(name)); } ---------------------------------------------- }//fin del while } _findclose( hFile ); delete directory; Se borra el char* creado con new . } 3.4 Compilador usado Se uso el compilador Microsoft Visual C++ 6.0 . 3.5 ¿Cómo compilar el programa? Para compilar el programa, se deben seguir las siguientes instrucciones: - - Descomprimir el archivo ea44239.zip en el escritorio. Abrir Microsoft Visual C++ 6.0 ó superior y crear un nuevo proyecto. Agregar los archivos de encabezado - Header Files - (Tree.h, Treenode.h y FolderReader.h ) que se encuentran en la carpeta codigo_fuente. Agregar los archivos fuente – Source Files - (a44239_a45214.cpp, y FolderReader.cpp) que se encuentran en la carpeta codigo_fuente. Buscar el menú Build / Compile 12 4. Guía de uso del programa Para poder usar el programa, se deben seguir los siguientes pasos: - Descomprimir el archivo ea44239.zip en el escritorio. - Buscar y accesar la carpeta a44239_a45214. - Buscar y acceder la carpeta Debug. - Cargar el Command Prompt de Windows y buscar la carpeta donde se ubica el archive synch.exe mediante el comando cd. - Escribir en DOS read + el directorio donde se inicia la lectura de archivos. Ej: read “f:\ci-1201\respaldo” Nota: 1- El programa emite error si no se respeta la sintaxis planteada 5. Datos de prueba 13 5.1 Formato de los datos de prueba El formato de los datos de prueba va a radicar en 2 campos específicos: - Errores de digitación por parte del usuario. Subdirectorios con archivos y vacíos. 5.2 Entradas vs Salidas esperadas Las entradas y salidas esperadas para los errores de digitación de usuario son: ENTRADA SALIDA read “f:\ci-1201\respaldo” Read DOS – Archivos y subdirectorios leídos Error – programa read “ñ:/respaldo” Error DOS – no existe unidad ñ read “ci-1201\respaldo” Error DOS – no se especifica unidad read “4312kjfblk” Error DOS – sintaxis incorrecta Las entradas y salidas esperadas para los subdirectorios con archivos y vacíos son: ENTRADA Directorio fuente SALIDA Subdirectorios dependientes del directorio fuente ( se toma en cuenta que estos subdirectorios puedan tener archivos) 1 archivo 0 subdirectorios 25 archivos 0 subdirectorios 1 archivo 1 subdirectorios 26 archivos 25 subdirectorio 0 archivos 0 subdirectorios 1 archivo leído 0 subdirectorios leídos 25 archivos leídos 0 subdirectorios leídos 1 archivo leído 1 subdirectorio leído 26 archivos leídos 25 subdirectorios leídos 0 archivos leídos 0 subdirectorios leídos Nota: Las pruebas referentes al ordenamiento correcto de los nombres de los archivos y subdirectorios no se realizan, ya que el ordenamiento depende exclusivamente de los operadores de comparación de los strings de STL, por lo que no se tiene ninguna injerencia en los criterios de comparación que ahí se utilizan. 14 6. Código fuente 15 El código fuente del programa se encuentra disponible en la dirección electrónica: http://www.angelfire.com/ak5/juancho/tareas_p2/tarea6/tarea_6.htm Además, el código ha sido comentado, en su mayoría, en este trabajo, por lo que se obvia la impresión del mismo. Reconocimientos 16 Cabe destacar el aporte del profesor Adolfo Di-Mare, ya que este facilito la mayoría de la implementación del método void getInfo(const string& src) de la clase Folder. Igualmente, se debe reconocer el código referente al árbol binario del libro de texto del señor Deitel. Bibliografía 17 - Deitel y Deitel. ¿Cómo programar en C ++?. Editorial Prentice Hall. Segunda Edición.1998 http://www.cs.ndsu.nodak.edu/~kvanhorn/Fall2002/cs474/javatoc.html. Java to C++ transition tutorial. 1997. http://ourworld.compuserve.com/homepages/ronald_fischer/ . ANSI/ISO C++ Incompatibility Page. Fischer, Ronald. 2002 http://www.fz-juelich.de/zam/cxx/extmain.html#learn . Forschungszentrum Jülich. Última modificación: 19 de julio de 2004. 18