 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Lun 29 Ago, 2005 12:13 am Asunto: Crear UDF para Firebird |
|
|
Hola amigos.
¿Alguien sabe como se puede crear una UDF desde Builder para Firebird? Por ejemplo que archivos incluir en el proyecto.
Deseo crear una UDF que me permita guardar un campo BLOB a un fichero y que recupere de un fichero a un campo BLOB.
Para que necesito esto?, bueno en el proyecto que me encuentro desarrollando debo guardar imagenes en la base y el volumen a guardar va ha ser que crezca demasiado la base de datos, asi que deseo hacer uso de una UDF para que la base de datos sea capaz de guardar los archivos en una carpeta o recuperarlos de ella.
Ahora si alguien posee una UDF que haga esto me ayudaria enormemenete.  |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
Publicado: Lun 29 Ago, 2005 4:49 am Asunto: |
|
|
También estaba interesado en algo asi.
Pero no encontre nada hecho y la verdad es que no tuve tiempo de desarrollarlo, pero busque algunas referencias que te paso.
Si depues podes compartir tu resultado, asi lo podemos probar estaría bueno.
Te dejo unos links que estan buenos:
Example blob UDFs
http://bdn.borland.com/article/0,1410,25785,00.html
Declaring a blob UDF
http://bdn.borland.com/article/0,1410,25786,00.html
Writing Clean and Safe UDFs In Delphi
http://www.ibphoenix.com/a476.htm?a=ibphoenix&page=ibp_howto5
Writing UDF's in Delphi for Interbase/Firebird
http://firebird.sourceforge.net/index.php?op=useful&id=geldenhuis
Writing UDFs for InterBase
http://firebird.sourceforge.net/index.php?op=useful&id=deatz_udf
Creating UDF's IN Delphi
http://www.ibphoenix.com/a476.htm?a=ibphoenix&page=ibp_howto7
También dentro del código fuente de firebird extan las UDF's definidas de ellos.
Suerte _________________ Crandel
"hay 10 tipos de personas, las que ven en binario y las que no"
Angel Zeitoune - Artículo: Generación de eventos en C++Builder |
|
| Volver arriba |
|
 |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Mar 30 Ago, 2005 12:03 am Asunto: |
|
|
Hola amigos, después de estar revisando muchas páginas en ingles, ruso, chino y no se que otros idiomas creo que ya he logrado algo funcional aquí se los paso para que se hagan las respectivas pruebas y logremos depurarlo al máximo:
Primero crear un proyecto en la opción “DLL Wizard”
Elegir la opción “C” y “Multi Theaded”
Al archivo generado reemplazarlo completamente por lo siguiente:
| Código: |
//---------------------------------------------------------------------------
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include "ibase.h"
//---------------------------------------------------------------------------
typedef struct blob {
short (*blob_get_segment)(void *,UCHAR *, USHORT, USHORT *);
void *blob_handle;
long blob_number_segments;
long blob_max_segment;
long blob_total_length;
void (*blob_put_segment)(void *,UCHAR *, USHORT);
} *TBLOB;
//---------------------------------------------------------------------------
__declspec(dllexport) void __cdecl FileToBlob(char * Fichero, TBLOB B)
{
// char Buffer[32*1024];
UCHAR * Buffer;
int Tam;
USHORT x;
FILE * f;
// if not (Assigned(Filename) and FileExists(Filename)) then Exit;
f = fopen(Fichero, "rb");
if( f )
{ Buffer = (UCHAR *) malloc( 32*1024 );
__try
{
//Vamos al final y conseguimos el tamaño
fseek( f, 0, 2);
Tam = ftell( f );
//Regresamos al inicio
fseek( f, 0, 0 );
while( Tam > 0 )
{
x = fread((void*)Buffer,sizeof(UCHAR), 32*1024, f);
(*B->blob_put_segment)( B->blob_handle, Buffer, x);
Tam -= x ;
}
}
__finally
{
fclose(f);
free(Buffer);
}
}
}
//---------------------------------------------------------------------------
__declspec(dllexport) long __cdecl BlobToFile(TBLOB B, char * Fichero)
{
UCHAR *Buffer;
int Total = 0;
int TamBlob;
USHORT TamMaxSeg, BytesLeidos;
FILE * f;
long r = -1;
if( !B || !B->blob_handle)
return -1;
TamMaxSeg = B->blob_max_segment;
// if FileExists(FileName) then DeleteFile(FileName);
// if not (Assigned(Filename) and FileExists(Filename)) then Exit;
f = fopen(Fichero, "wb");
if( f )
{ Buffer = (char *) malloc( TamMaxSeg );
__try
{ //if (iFileHandle <=3D 0) then Exit;
while( (*B->blob_get_segment)( B->blob_handle, Buffer, TamMaxSeg, &BytesLeidos) )
{
fwrite((void*)Buffer,sizeof(UCHAR), BytesLeidos, f);
Total += BytesLeidos;
}
}
__finally
{
fclose(f);
free(Buffer);
r = Total;
}
}
return r;
}
//---------------------------------------------------------------------------
|
Luego ir a Project/Options
- Elegir “Directories/Contitionals” y en “include Path” se debe agregar la carpeta “INCLUDE” esta se encuentra dentro de “Archivos de progra-ma\Firebird\Firebird_1_5\include”
- En “Linker” desactivar “Create Debug Information, use dynamic RTL, use debug li-braries y generate import library”
- En “Packages” desactivar “build with runtime packages”
- En “Compiler” presionar el botón “Release”
- En “Advanced Compiler” activar “Pentium Pro”
Aceptar
Grabar todo( yo grabe con el nombre de “MisUDFS”)
nuevamente Project/ Build MisUDFS
y se crea el dll
ahora se debe copiar en la carpeta UDF dentro del FireBird
Para declararlas dentro de FireBird usar estas instrucciones
| Código: |
DECLARE EXTERNAL FUNCTION BLOBTOFILE
BLOB,
CSTRING(256)
RETURNS INTEGER BY VALUE
ENTRY_POINT 'BlobToFile' MODULE_NAME 'MisUDFS.dll';
DECLARE EXTERNAL FUNCTION FILETOBLOB
CSTRING(256),
BLOB
RETURNS PARAMETER 2
ENTRY_POINT 'FileToBlob' MODULE_NAME 'MisUDFS.dll';
|
Para hacer pruebas me hice una tabla
| Código: |
CREATE TABLE PRUEBITA (
ID INTEGER NOT NULL,
NOMBREARCHIVO VARCHAR(100),
ARCHIVO BLOB SUB_TYPE 2 SEGMENT SIZE 1024
);
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (1, 'F:\Block de No-tas\dir gnuwin.txt');
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (2, 'F:\Block de No-tas\direcciones 02.txt');
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (3, 'F:\Block de No-tas\Direcciones y claves.txt');
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (4, 'F:\Block de No-tas\Escribir en titulo de ventana.txt');
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (5, 'F:\Block de No-tas\para pintar.txt');
COMMIT WORK;
|
Por los datos pueden ver que poseo una unidad f: con una carpeta llamada “Block de notas” todos los nombres de archivos que están ingresados en la tabla existen en esa carpeta
Para probar FILETOBLOB y hacer que los archivos se carguen en un BLOB hice:
| Código: |
select NombreArchivo, FileToBlob(NombreArchivo)
from Pruebita
|
Para probar BLOBTOFILE primero cargue algunos archivos en los campos BLOB y luego puse:
| Código: |
select ID ,BlobToFile(Archivo, 'f:\PRUEBA_'||id||'.txt' )
from Pruebita
where Archivo is not null
|
y se crearon ficheros como “f:\Prueba_1.txt”
lo que NO PUDE HACER fue enviar el BLOB como parámetro desde el builder
en un TIBQuery puse:
| Código: | select BlobToFile( :BLOB, :Archivo ) as Total
from rdb$database |
pero me vota error ya que no reconoce el tipo de los parámetros
luego probe:
| Código: | select BlobToFile( :BLOB, 'f:\fotito.jpg' ) as Total
from rdb$database |
Trata de hacer algo pero bota un error al final
Al final para salvar el problema tuve que hacer lo siguiente:
Primero en el FireBird me cree un procedimiento almacenado
| Código: |
CREATE PROCEDURE XXPRUEBITA(
ID INTEGER,
NOMBREARCHIVO VARCHAR(100))
RETURNS (
RID INTEGER)
AS
begin
/* Procedure Text */
select BlobToFile(Archivo, :NombreArchivo )
from Pruebita
where ID = :ID into :RID;
RID = coalesce(:rid, 0);
if( :RID > 0 ) then
update pruebita set Archivo = null where id = :ID;
suspend;
end
|
luego en el builder puse ibquery y un storedprocedure conectados al mismo objeto transaccion y escribi esto en un botón:
| Código: |
void __fastcall TForm1::btnAgregarClick(TObject *Sender)
{
if(opd->Execute())//objeto TOpenDialog
{
Trans->StartTransaction();//Obeto Trasaccion comun
qr->ParamByName("BLOB")->LoadFromFile(opd->FileName,ftBlob);
sp->ParamByName("ID")->AsInteger = 1;
sp->ParamByName("NombreArchivo")->AsString = edtArchivo->Text;//Aquí le paso el nombre con el que deseo grabar el fichero
qr->ExecSQL();
sp->ExecProc();
try
{
ShowMessage( IntToStr(sp->ParamByName("RID")->AsInteger));
}
__finally
{
Trans->Commit();
}
}
}
|
el query tiene el sgte. Sql:
| Código: | update pruebita
set Archivo = :BLOB
where id = 1 |
y el objeto storedprocedure esta conectado a mi procedimiento “xxPruebita”
de esta forma he logrado enviar un fichero al servidor y que lo grabe en una carpeta.
Bueno amigos por favor revisenlo, estudienlo. No estoy seguro si realmente es multihilo, y si alguien logra enviar un fichero directamente al servidor sin valerse el procedimiento almacenado que por favor nos lo enseñe.
Si alguien pudiese convertirlo para linux seria muy interesante tambien.
Bueno seguiré investigando, esto de las UDFS me esta requetegustando.  |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
Publicado: Mar 30 Ago, 2005 12:15 am Asunto: |
|
|
Hola cecito, la verdad es que espectacular lo que lograste hacer en solo un día.
Apenas me haga un tiempito, lo pruebo y te contesto. _________________ Crandel
"hay 10 tipos de personas, las que ven en binario y las que no"
Angel Zeitoune - Artículo: Generación de eventos en C++Builder |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
Publicado: Mar 30 Ago, 2005 7:44 am Asunto: |
|
|
Hola cecito, te cuento que acabo de probar tu udf y me gusto.
Logre crearla y declararla sin ningun problema.
En vez de usar archivos de texto, use imágenes y me anduvo bien.
use un query para traerme la tabla
| Código: | SELECT ID, NombreArchivo, FileToBlob(NombreArchivo) AS FOTO
from Pruebita |
y anduvo perfecto
tambien probe haciendo una vista
| Código: | CREATE VIEW VISTA_BLOB (ID, NOMBRE, FOTO)
AS
SELECT ID, NOMBREARCHIVO, FileToBlob(NombreArchivo)
FROM PRUEBITA; |
y tambien anduvo perfecto.
mostre las imagenes en un TDBImage y las va trayendo de acuerdo al registro seleccionado.
Para enviar las fotos tuve bastantes dificultades.
En tu codigo de CBuilder le envias tres parámetros mientras que el procedimiento almacenado (SP) solo recibe dos
Tampoco me convencio que crees la tabla con un campo blob, asi que no la cree al principio, pero tu SP no se puede cargar si no lo creas.
La verdad es que no pude ejecutar en un SP propio la función BlobToFile, no se cual es mi problema, quise armar algo asi:
| Código: | CREATE PROCEDURE INSERTAR (ID INTEGER, NOMBRE VARCHAR(100), FOTO BLOB)
AS
BEGIN
INSERT INTO PRUEBITA(ID, NOMBREARCHIVO)
VALUES (:ID, :NOMBRE);
// aca esta el problema, no se como hacer que se guarde la foto
select ID , BlobToFile(:FOTO, :NOMBRE)
from Pruebita;
END^
|
pero no compila de ninguna forma
Estas son mis pruebas por ahora, cuando haga algo mas te comento. _________________ Crandel
"hay 10 tipos de personas, las que ven en binario y las que no"
Angel Zeitoune - Artículo: Generación de eventos en C++Builder |
|
| Volver arriba |
|
 |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Mar 30 Ago, 2005 2:09 pm Asunto: |
|
|
Hola Crandel, creo que la vez pasada no me explique bien, pero ahora lo corrijo.
Desde Builder no pude enviar un parámetro tipo BLOB , en otras palabras la función solo me esta aceptando un parámetro BLOB si es que este parámetro existe como campo de una tabla por eso esto es válido
| Código: |
select ID ,BlobToFile(Archivo, 'f:\PRUEBA_'||id||'.txt' )
from Pruebita
where Archivo is not null |
Puesto que el campo "Archivo" pertenece a la tabla pruebita, pero este otro:
| Código: | select BlobToFile( :BLOB, :NombreArchivo ) as Total
from rdb$database |
No lo acepta por que el parámetro :BLOB no es un campo de la base de datos.
Entonces para solucionar este impase hice las sguientes acciones.
1.- Enviaba un parámetro :BLOB a actualizar un campo blob de una tabla( osea guardaba el BLOB en la tabla), todo esto por medio de un query.
2. Utilizaba un Procedimiento almacenado que buscara en esta tabla al registro que se habia actualizado y su campo blob lo guardaba en un fichero, luego de no haber errorres borrara el contenio de ese campo blob asignadole NULL .
Para lograr esto coloque un query(qr) y un storedprocedure(sp) los dos conectados al mismo objeto transacction(Trans) ( la base de datos tiene su propia Transaccion - TransDB ).
En el query(qr) puse:
| Código: | update pruebita
set Archivo = :BLOB
where id = 1 |
En el StroredProcedure(sp) lo conecte a mi procedimiento "xxxPruebita"( como lo indique antes)
Luego , en el builder puese:
| Código: | void __fastcall TForm1::btnAgregarClick(TObject *Sender)
{
if(opd->Execute())//objeto TOpenDialog
{
Trans->StartTransaction();//Obeto Trasaccion comun
qr->ParamByName("BLOB")->LoadFromFile(opd->FileName,ftBlob);
sp->ParamByName("ID")->AsInteger = 1;
sp->ParamByName("NombreArchivo")->AsString = edtArchivo->Text;//Aquí le paso el nombre con el que deseo grabar el fichero
qr->ExecSQL();
sp->ExecProc();
try
{
ShowMessage( IntToStr(sp->ParamByName("RID")->AsInteger));
}
__finally
{
Trans->Commit();
}
}
} |
Espero que ahora si puedas recrear lo que hice.
No se donde habia leido que no se podia pasar prámetros BLOB a los procedimientos por eso ni lo intente, voy a revisar tu "procedure" y te cuento. |
|
| Volver arriba |
|
 |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Mar 30 Ago, 2005 3:50 pm Asunto: |
|
|
Hey amigo Crandel diste en el clavo. yeeeeeeee
He creado el Siguiente Procedimiento:
| Código: | CREATE PROCEDURE xxPrueba2 (ID INTEGER, NOMBRE VARCHAR(100), FOTO BLOB)
RETURNS (
RID INTEGER)
AS
--DECLARE R INTEGER = 0;--Forma simplificada de declarar una variable
BEGIN
INSERT INTO PRUEBITA(ID, NOMBREARCHIVO)
VALUES (:ID, :NOMBRE);
-- Un select siempre debe devolver sus valores a variables( el "into" )
select BlobToFile(:FOTO, :NOMBRE)
from rdb$database into :RID;
--rdb$database es una tabla de sistema que siempre devuelve un registro
--Devolvemos el valor de RID, si es mayor a cero no hubo problemas
suspend;
END |
Borre el campo BLOB de mi tabla Pruebita y a quedado ahora asi:
| Código: | CREATE TABLE PRUEBITA (
ID INTEGER NOT NULL,
NOMBREARCHIVO VARCHAR(100)
); |
En el Builder coloque los siguientes controles en un formulario:
- Un TIBDatabase(llamado db) conectado a su propio objeto TIBTransaction(TransBD) y perfectamente enlazado a la base de datos
- Un objeto TIBStoredProcedure(sp2) conectado a su propio objeto Transaction(Trans) el cual esta conectado a la base(db)
- Un TOpenPictureDialog(opd)
- Un TEdit(edtID)
- Un Botón(btnInsertar)
y puse este código:
| Código: |
//Agrega esta libreria para que el TOpenPictureDialog muestre archivos JPG
#include <jpeg.hpp>
void __fastcall TForm1::btnInsertarClick(TObject *Sender)
{
if(opd->Execute())
{ AnsiString tmp;
int ID = edtID->Text.ToIntDef(100);
tmp.printf("F:\\FotosBD\\BD%d%s",ID,ExtractFileExt(opd->FileName));
Trans->StartTransaction();
sp2->ParamByName("ID")->AsInteger = ID;
sp2->ParamByName("Nombre")->AsString = tmp;
sp2->ParamByName("FOTO")->LoadFromFile(opd->FileName,ftBlob);
sp2->ExecProc();
try
{
ShowMessage( IntToStr(sp2->ParamByName("RID")->AsInteger));
}
__finally
{
Trans->Commit();
}
edtID->Text = IntToStr(ID+1);//Para evitar Ingresar a cada rato el ID
}
} |
Todos los archivos se graban en la siguiente ruta "F:\FotosBD" y los archivos los estoy guardando con los sgtes. nombres:
| Código: | BD<ID>.<Extensión original>
ejem. "F:\FotosBD\BD1232.JPG" o "F:\FotosBD\BD111.BMP" |
Si todo va bien al ejecutar el procedimiento mostrara un "ShowMessage" con la cantidad de bytes grabados.
Que falta ahora en la UDF:
- Verificar si un archivo existe o no.
- Crear la carpeta donde se va ha grabar el archivo si es que no existiese.
- Crear algo llamado "CrearCarpeta" para que la base de datos pueda crear carpetas
- Tambien cosas como "BorrarCarpeta", "BorrarArchivo" , "ExisteCarpeta" o "ExisteArchivo"
Me gustaría que usemos un "C/C++" lo más estandarizado posible dentro de las funciones para que asi podamos migrarlo a linux( es que al final mi FireBird va ha correr en Linux )
Sigo con las pruebas, cualquier correción que haga se las indico, bye  |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
Publicado: Mie 31 Ago, 2005 4:02 am Asunto: |
|
|
Te cuento que termine creando el procedimiento almacenado asi:
| Código: | CREATE PROCEDURE INSERTAR (ID INTEGER, NOMBRE VARCHAR(100), FOTO BLOB)
RETURNS (RID INTEGER)
AS
BEGIN
INSERT INTO PRUEBITA(ID, NOMBREARCHIVO)
VALUES (:ID, :NOMBRE);
// al asignar el valor a una variable, no hace falta usar el select
RID = BlobToFile(:FOTO, :NOMBRE);
END |
voy a intentar aportar algo a la udf, cuando consiga algo mejor te cuento. _________________ Crandel
"hay 10 tipos de personas, las que ven en binario y las que no"
Angel Zeitoune - Artículo: Generación de eventos en C++Builder |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
Publicado: Mie 31 Ago, 2005 10:29 pm Asunto: |
|
|
Hola cecito, recien me puse de nuevo con la udf.
Algunos puntos:
1. Alguna razón en especial para manipularlos como C y no como C++?
2. Me puse primero con la función BlobToFile para cerrarla, porque parece la mas terminada y estuve revisando el porque el tamaño del bloque de lectura. Por lo visto la función blob_put_segment no acepta mas que ese tamaño, esto es raro porque vos la definiste como un USHORT y no como short.
Buscando en los manuales de interbase no dicen nada del tipo de dato, en los que tengo de firebird no dice nada de la estructura.
Ahora me voy a poner con la otra función. _________________ Crandel
"hay 10 tipos de personas, las que ven en binario y las que no"
Angel Zeitoune - Artículo: Generación de eventos en C++Builder |
|
| Volver arriba |
|
 |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Jue 01 Sep, 2005 6:41 am Asunto: |
|
|
Hola Crandel sabes tambien estoy un poco confundido. en el manual Developer Guide de Interbase 6 definen esta estructura para los BLOBs(pag. 91).
| Código: | typedef struct blob {
void (*blob_get_segment) ();
int *blob_handle;
long number_segments;
long max_seglen;
long total_size;
void (*blob_put_segment) ();
} *Blob; |
En la UDF rFunc( unas udfs rusas usan esto otro, aunque lo tenian comentado ):
| Código: | typedef struct blob {
ISC_STATUS (*blob_get_segment) (
isc_blob_handle *,
char *,
unsigned short,
unsigned short *);
isc_blob_handle *blob_handle;
ISC_LONG blob_number_segments;
ISC_LONG blob_max_segment;
ISC_LONG blob_total_length;
ISC_STATUS (*blob_put_segment) (
isc_blob_handle *,
char *,
unsigned short);
} *BLOB; |
Revisando en el codigo fuente del interbase 6 encontre esto:
| Código: | static SSHORT blob_get_segment (BLB, UCHAR *, USHORT, USHORT *);
static void blob_put_segment (BLB, UCHAR *, USHORT);
static SLONG blob_lseek (BLB, USHORT, SLONG);
|
Ahora revisando los fuentes de esta UDF FreeAdhocUDF ( del año 2004) define esto otro:
| Código: | ypedef struct blob {
short (*get_segment)(
isc_blob_handle *blob_handle,
void *buffer,
long bytes_to_read,
long *bytes_read);
isc_blob_handle *blob_handle;
long blob_number_segments;
long blob_max_segment;
long blob_total_length;
void (*put_segment)(
isc_blob_handle *blob_handle,
void *buffer,
long bytes_to_write);
long (*seek)();
};
|
Revisando las blobudflib ( en pascal) lo definen asi: | Código: | TISC_BlobGetSegment = function(BlobHandle: PInt;
Buffer: PChar;
BufferSize: Long;
var ResultLength: Long): Short; cdecl;
TISC_BlobPutSegment = procedure(BlobHandle: PInt;
Buffer: PChar;
BufferLength: Short); cdecl;
TBlob = record
GetSegment : TISC_BlobGetSegment;
BlobHandle : PInt;
SegmentCount : Long;
MaxSegmentLength : Long;
TotalSize : Long;
PutSegment : TISC_BlobPutSegment;
end;
PBlob = ^TBlob;
|
Al revisar todo esto uno ve que no se tiene claro el tipo del último parámetro de la función "get_segment" ya que es un puntero, que algunos lo definen con short o unsigned short ( 16 bits) y otros como long(32 bits) creo que es aqui donde podria darnos error.
A ver si nos echan una mano y encontramos la correcta definición de estos dos punteros a función:
- get_segment
- put_segment
Ahora contestando tus preguntas:
1) Hice el proyecto como C por que un documento que encontre me enseño a crear una udf simple con estas indicaciones, no lo he probado como C++ pero supongo que debe funcionar.
2) Revisando algunas UDFS, vi que usaban de forma arbitraria 8Kb otros 16KB y decidi probar con 32KB realmente no he usado ninguna informacion tecnica específica para colocar este número
Ahora me encuentro viendo la posibilidad de implementarla en linux, a ver como ve va
Sigo investigando, nos vemos mas rato...  |
|
| Volver arriba |
|
 |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Jue 01 Sep, 2005 1:39 pm Asunto: |
|
|
Me he puesto a revisar el código fuente del Firebird 1.5 y tambien la libreria "iBase.h" que incluimos en el proyecto y descubri esto:
| Código: | /* Blob passing structure */
enum lseek_mode {blb_seek_relative = 1, blb_seek_from_tail = 2};
typedef struct blobcallback {
short ( *blob_get_segment)
(void * hnd, unsigned char* buffer, ISC_USHORT buf_size, ISC_USHORT* result_len);
void *blob_handle;
ISC_LONG blob_number_segments;
ISC_LONG blob_max_segment;
ISC_LONG blob_total_length;
void ( *blob_put_segment)
(void * hnd, unsigned char* buffer, ISC_USHORT buf_size);
ISC_LONG ( *blob_lseek)
(void * hnd, ISC_USHORT mode, ISC_LONG offset);
} *BLOBCALLBACK;
#endif /* !defined(JRD_VAL_H) && !defined(REQUESTER) */ |
Por lo que se ve aquí se encuentra ya definida la estructura con todos los parámetros, para probarla en el proyecto comente la estructura que se habia puesto y agregue esta línea para que no se tenga que hacer muchas modificaciones en el código:
| Código: | typedef BLOBCALLBACK TBLOB; | y compila perfectamente. Asi que ya esta solucionado lo de los tipos de parámetros que se deben pasar( era "unsigned short *" o "USHORT*").
Bueno sigo investigando.  |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
Publicado: Mie 14 Sep, 2005 5:35 am Asunto: Cuidado con almacenar en disco |
|
|
Hola, hoy acabo de llegar exactamente a los 21844 archivos guardados dentro de una carpeta de Windows.
La forma en que almacenaba y recuperaba los datos los estaba por reemplazar por esta udf.
Pero hoy la máquina se taro y mi programa comenzó a comportarse de forma extraña. Despues de un largo rato sin descifrar que era me di cuanta que Windows 98 no me permitia seguir guardando archivos en el disco
Por supuesto al disco le sobra lugar. y la maquina es un P4, asi que esto no debía ser limitante.
Por lo que me estoy replanteando la forma de guardar las imágenes y parece que van a terminar dentro de la DB, algo que no quería porque en antes el servidor funcionaba en una maquina muy chica Pentium 100MHz con poca RAM, y las fotos supuestamente solo permanecerían un tiempo limitado.
Muy loco. _________________ Crandel
"hay 10 tipos de personas, las que ven en binario y las que no"
Angel Zeitoune - Artículo: Generación de eventos en C++Builder |
|
| Volver arriba |
|
 |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Mie 14 Sep, 2005 12:35 pm Asunto: |
|
|
Hola Crandel, ya estaba considerando la posibilidad de que no se pueda grabar muchos archivos en una carpeta y tú me lo acabas de confirmar. Habia leido que en una carpeta y con formato FAT32 puede, en teoría, almacenar 65.534 archivos o subcarpetas, pero esto es cierto solamente si los nombres de archivo usan el formato de DOS de 8.3 caracteres, que es más corto. El número total de archivos por carpeta se reduce drásticamente cuando los archivos usan nombres más largos.
Ahora esto va ha ser un problema, uhmmm, dejame idear una forma para que la UDF grabe los archivos en subcarpetas dentro de nuestra carpeta principal y los pueda recuperar de ellas, todo de esto de forma transparente para nosotros, se me ocurre aplicar la busqueda HASH pero con las subcarpetas..
Tal vez se te ocurra otra forma más elegante de salvar este problema, me la indicas para trabajarla juntos.
Estaremos en contacto.  |
|
| Volver arriba |
|
 |
cecito Capt

Registrado: 25 Nov 2003Mensajes: 164Ubicación: Arequipa - Perú
|
Publicado: Jue 15 Sep, 2005 6:47 pm Asunto: |
|
|
| Hola Crandel indicastes antes que habias grabado "21844 archivos" podrias indicarse si has usado nombres de 8 letras para los archivos o has usado nombres mas grandes. |
|
| Volver arriba |
|
 |
Crandel Lt


Registrado: 31 May 2005Mensajes: 94Ubicación: Argentina
|
|
| Volver arriba |
|
 |
|
|
No puedes publicar temas nuevos en este foro No puedes responder a temas en este foro No puedes editar tus mensajes en este foro No puedes borrar tus mensajes en este foro No puedes votar en las encuestas de este foro
|
© 2002–2026 Club Builder · Funciona con phpBB.
|