Pues, eso... como dice el título. ¿Cuál es la manera más apropiada de manejar un TFileStream capturando y lanzando las excepciones de forma apropiada?
Actualmente tengo esta chapuza de código:
procedure TArrayConverter.LoadMatrix(AMatrix: TAMatrix; FileName: string); var Header: TMatrixHeader; Fmt: TFileFormat; i, j, RM, CM, Err, ConvE: integer; Can: boolean; begin Can := CheckMatrix(AMatrix, RM, CM, Err); if Can AND (Err = OPERATION_DONE) then begin try // Cargar el archivo FFile.Create(FileName, fmOpenRead or fmShareDenyWrite); // leemos formato FInUse := true; Fmt.SizeFile := FFile.Seek(0, soEnd); FFile.ReadBuffer(Fmt.IDIni, SizeOf(Fmt.IDIni)); // ID.Ini FFile.ReadBuffer(Header, SizeOf(Header)); // Header FFile.Seek(INI_ID_END, soFromEnd); FFile.ReadBuffer(Fmt.IDEnd, SizeOf(Fmt.IDEnd)); // ID.End // ¿Valido? if ISValidFormat(Fmt, Header) then begin // Supuesto tamaño de datos if (Header.Rows = RM) AND (Header.Cols = CM) then begin // Leemos data if Header.Orientation = aoCol then begin // ... por columnas for j := 0 to CM - 1 do for i := 0 to RM - 1 do FFile.ReadBuffer(AMatrix[i, j], SizeOf(TYPEDATA)); end else begin // ... por filas for i := 0 to RM - 1 do for j := 0 to CM - 1 do FFile.ReadBuffer(AMatrix[i, j], SizeOf(TYPEDATA)); end; end else ConvE := 3; end else ConvE := 2; finally FFile.Free; FInUse := false; end; end else ConvE := 1; // ¿Lanzamos excepción? case ConvE of 1: raise EInconsistentArray.Create('Check of matrix failed', itCheck); 2: raise EFileOperation.Create('Invalid matrix file format'); 3: raise EInconsistentArray.Create('The dimensions of the matrix and file data do not match', itDimNotMatch); end; end;
Creería que el código se explica solo. Básicamente estoy leyendo un archivo matricial y cargando la data. Mi archivo está pensado con una estructura como la siguiente:
1) Viene una especie de identificador de archivo. Para el caso de matrices, tiene un valor y para vectores otro.
2) Seguidamente una cabecera que contiene la información relacionada con la dimensión de la estructura de datos.
3) Los datos propiamente dichos
4) Y por último un identificador de fin de archivo. Este es común para ambos tipos de archivos.
Se que puede ser mejorado. Pero ya tengo la cabeza muy hecha trizas, y se me confunden los tantos... Por un lado quisiera poder detectar posibles excepciones que arroje el FFileStream, desde su creación hasta cuando intenta leer y/o escribir y por el otro quisiera poder lanzar las excepciones propias que tengo definidas para el contexto de esta clase que estoy diseñando en base a mis pruebas. ¿Cómo debo proceder? ¿Un doble try anidado? ¿Cómo lo encararían ustedes?
Por si ayuda a comprender el código, adjunto la descripción de la clase:
TArrayConverter = class private FFile: TFileStream; FInUse: boolean; function IsValidFormat(AFormat: TFileFormat; AHeader: TMatrixHeader): boolean; overload; function ISValidFormat(AFormat: TFileFormat; AHeader: TVectorHeader): boolean; overload; function MakeHeader(Rows, Cols: integer; Orientation: TArrayOrientation): TMatrixHeader; overload; function MakeHeader(Dim: integer): TVectorHeader; overload; public constructor Create; destructor Destroy; override; procedure LoadMatrix(AMatrix: TAMatrix; FileName: string); procedure LoadVector(AVector: TAVector; FileName: string); procedure SaveMatrix(AMatrix: TAMatrix; OnDir: TArrayOrientation; FileName: string); procedure SaveVector(AVector: TAVector; FileName: string); property InUse: boolean read FInUse; end;
Los métodos MakeHeader() como IsValidFormat() creerían que no hace falta que adjunte. Se pueden hacer una idea de su uso. Básicamente se procede a armar la cabecera de cada archivo, y en los otros de realizar las comprobaciones de formato para asegurarse de que se ha leído un archivo correcto.
Leyendo la documentación, durante la creación del TFileStream es posible que se presente una excepción EFOpenError, y también puede presentarse excepciones durante el ReadBuffer y en el WriteBuffer... no dice la documentación cual. Aparentemente, de lo que estoy viendo en el código de la clase TStream parecen ser EReadError y EWriteError respectivamente.
Para el guardado de vectores el código sería algo similar. Las versiones Save() estimo que debieran de tener un código análogo, salvando el detalle de aplicar un WriteBuffer.
Cualquier ayuda y propuesta se les agradece.
Muchas gracias.