| Normalmente los programadores que queremos generar un
fichero a las carpetas compartidas (QDLS), lo que hacemos es generar un fichero (o
miembro) en el AS/400 y copiarlo después utilizando el mandato CPYTOPCD para dejarlo en
la carpeta compartida, y borrando el miembro o fichero creado en el AS. Con una sencilla
utilización de algunas API's conseguiremos el mismo resultado, pero sin utilizar recursos
de máquina para crear/copiar/borrar objetos. En resumen, conseguiremos crear documentos
de PC desde un RPG. Las API's que utilizaremos para esta finalidad son las siguientes:
QHFOPNSF - Abre un fichero en la IFS con sistema HFS.
QHFWRTSF - Graba a un fichero en la IFS con sistema HFS.
QHFCLOSF - Cierra un fichero en la IFS con sistema HFS.
documentadas en el manual: QB3AMK01
OS/400 Hyerarchial File System V4R2.
Para que la utilización de estas API's no signifiquen una carga extra en la
programación y podamos seguir el hilo conductor de los programas que las utilicen,
crearemos 3 prototipos o procedimientos para cada una de las acciones a realizar:
@ObreIFS - Abre un fichero IFS
Parámetros que le pasamos por valor:
obreIFS_Path de 1024a - Carpeta y nombre de fichero a abrir.
obreIFS_Info de 10a - Son los parámetros con los que abriremos el fichero.
Parámetro que retorna:
globalIFSHDL 16a - Es el identificador con el que la máquina reconoce el fichero
abierto.
@GravaIFS - Grabamos al fichero IFS
Parámetros que le pasamos por valor:
gravaIFS_txt 255a - Es el texto que grabamos al fichero.
gravaIFS_HDL 16a - Identificador de fichero.
Parámetro que retorna:
Indicador de resultado de la operación
@TancaIFS - Cerramos el fichero IFS
Parámetros que le pasamos por valor:
tancaIFS_HDL 16a - Identificador de fichero.
Parámetro que retorna:
Indicador de resultado de la operación
De esta manera, la hoja D de definición de los prototipos, y de la variable que
utilizaremos como identificador de archivo, quedará así:
d*
d GlobalIFSHDL1 s 16a
d GlobalIFSHDL2 s 16a
d*
d @ObreIFS PR 16a
d obreIFS_Path 1024a Value
d obreIFS_Info 10a Value
d*
d @GravaIFS PR n
d gravaIFS_Txt 255a Value
d gravaIFS_HDL 16a Value
d*
d @TancaIFS PR n
d tancaIFS_HDL 16a Value
d*
Para abrir un fichero, lo haremos de la siguiente manera:
c Eval GlobalIFSHDL = @ObreIFS(
c '/QDLS/PROVES/PROVES.TXT' :
c '211 211 ')
Siendo el primer parámetro el nombre del fichero con la via IFS a donde se generará
el fichero, y el segundo el resultado de aplicar las siguientes directrices:
Byte 1 Acción a tomar si el fichero existe:
0 No abre el fichero y vuelve un error.
1 Abre el fichero.
2 Reemplaza el fichero existente.
2 Acción a tomar si el fichero no existe:
0 Retorna un error
1 Crea el fichero
3 Tipo de grabación
0 Grabación asíncrona. Retorna el control al programa inmediatamente.
1 Grabación síncrona. Retorna el control al programa cuando ha efectuado la
operación.
4 Reservado, ha de estar a blancos.
5 Modalidad de bloqueo.
1 No bloqueamos
2 Bloqueamos la escritura
3 Bloqueamos la lectura
4 Bloqueamos la lectura i la escritura.
6 Modalidad de acceso
0 Sólo lectura
1 Sólo escritura
2 Lectura/escritura
7 Tipo de operaciones de obertura para optimización
0 Normal
1 El fichero se cerrará con la API QHFCLOSF. ENDRQS y RCLRSC no cierran el fichero.
8-10 Reservados, han de estar a blancos
Así pues abrimos nuestro fichero PROVES.TXT en la carpeta PROVES de la QDLS diciendo
que: si existe, que lo reemplace, si no existe, que lo cree, que retorne el control al
programa cuando realice la grabación física, que bloquee la escritura a otros trabajos,
que accederemos únicamente para escritura, y que cerraremos el fichero por programa con
la API. La carpeta que indiquemos tendrá que estar montada con el sistema de archivos
HFS, la QDLS lo está por omisión.
Para grabar en el fichero PROVES.TXT haremos lo siguiente:
c Eval *In99 = @GravaIFS(
c 'Hola Mundo!' : GlobalIFSHDL)
Siendo el primer parámetro el texto a grabar, que puede ser una combinación de texto
y valores de campo, y el segundo el identificador de fichero retornado anteriormente. Si
gestionamos más de un fichero al mismo tiempo, tendremos una variables de tipo
identificador para cada fichero.
Para cerrar el fichero procederemos de la siguiente manera:
c Eval *In99 = @TancaIFS(GlobalIFSHDL)
La codificación de los diferentes prototipos la pondremos al final del RPG o en un
programa de servicio.
p*---------------------------------------------------
p* Abrimos un fichero en la IFS
p*---------------------------------------------------
p @ObreIFS B
d @ObreIFS PI 16a
d obreIFS_Path 1024a Value
d obreIFS_Info 10a Value
d*
d o_PathLn s 9b 0
d o_Info ds
d o_NumInf 9b 0
d o_ParInf 400a
d o_InfoLn s 9b 0
d o_Accio s 1a
d o_Error s 1024a
c*
c* Llamamos a la API que abre el fichero
c Eval o_PathLn = %len(%trim(obreIFS_Path))
c*
c Call 'QHFOPNSF'
c Parm o_Hdl
c Parm obreIFS_Path
c Parm o_PathLn
c Parm obreIFS_Info
c Parm o_Info
c Parm o_InfoLn
c Parm o_Accio
c Parm o_Error
c*
c Return o_Hdl
c*
p E
p*---------------------------------------------------
p* Insertamos líneas en el fichero
p*---------------------------------------------------
p @GravaIFS B
d @GravaIFS PI n
d gravaIFS_Txt 255a Value
d gravaIFS_HDL 16a Value
d*
d i_Buffer s 1024a
d i_BufferLen s 9b 0
d i_BufferWri s 9b 0
d i_Error s 1024a
d i_NL c Const(X'0D')
d i_Text s 256a
c*
c* Grabamos al fichero
c Eval i_BufferLen = %len(%trim(i_Buffer))
c Call 'QHFWRTSF'
c Parm gravaIFS_HDL
c Parm i_Buffer
c Parm i_BufferLen
c Parm i_BufferWri
c Parm i_Error
c*
c Return *Off
c*
p E
p*---------------------------------------------------
p* Cierra un fichero en la IFS
p*---------------------------------------------------
p @TancaIFS B
d @TancaIFS PI n
d tancaIFS_HDL 16a Value
d*
d o_Error s 1024a
c*
c* Llamamos a la API que cierra el fichero
c Call 'QHFCLOSF'
c Parm tancaIFS_HDL
c Parm o_Error
c*
c Return *Off
c*
p E
Estos prototipos no gestionan los errores.
Cierto, los prototipos tal y como están codificados, no controlan los errores
posibles, y siempre retornan *Off. Se ha omitido este apartado para así poder ir
aprendiendo de los errores. Si se quiere gestionar estos errores, controlaremos si las
variables de error contienen algún valor, y crearemos en cada prototipo una subrutina
*PSSR que los controle, o que sencillamente retorne el valor *On. En el caso de la
apertura del fichero, como que el valor retornado no es un indicador sino el identificador
de fichero, podemos retornar la palabra *ERROR para controlarlo. Pero esto lo dejo a
vuestro libre albedrío.
El fichero generado no se entiende.
Esto se debe a que se genera en formato EBCDIC. Para que se guarde en formato ANSI, en
el prototipo @GravaIFS añadiremos el siguiente código antes de la primera instrucción
de cálculo:
d*
d c_CvtLenI s 5p 0
d c_Taula s 10a Inz('Q284A05A5U')
d c_Lib s 10a Inz('QUSRSYS')
c*
c* Convertimos el texto de EBCDIC a ANSI
c Eval i_Text = %trim(gravaIFS_Txt) + i_NL
c Eval c_CvtLenI = %len(%trim(i_Text))
c Call 'QDCXLATE'
c Parm c_CvtLenI
c Parm i_Text i_Buffer
c Parm c_Taula
c Parm c_Lib
Me gustaría que el fichero tuviera un nombre largo.
Estas API's sólo funcionan con carpetas IFS montadas con sistema de archivos HFS. Por
cuestiones de tiempo no he entrado en el tema de montar HFS en otra carpeta diferente de
la QDLS de manera que permita nombres largos como en OS/2, que según el manual se puede
hacer.
Así que para conseguir este objetivo, ejecutaremos el mandato CL CPY de la siguiente
manera:
CPY OBJ('/qdls/proves/proves.txt')
TOOBJ('/home/pruebas/fichero de pruebas.txt')
La carpeta /home del sistema está montada con el sistema de archivos root, que si
permite nombres largos.
Hasta el momento no he encontrado la manera de gestionar ficheros en carpetas con FS
root desde RPG. Desde C se puede hacer, pero al no disponer de compilador C, no he podido
diseccionar las API's necesarias y aplicarlas a RPG... todo llegará ;-)
Puedo controlar la seguridad de estos ficheros?
Si. Se puede controlar a nivel de grupo de usuarios o de usuario de igual manera que
tratamos los objetos del AS/400... claro, es que es un objeto del AS.
Para no extenderme más, recomiendo hacer GO FSSEC y ver las posibilidades de seguridad
de los diferentes sistemas de archivos.
Àlex Corretge
|