| **Navigation:**  [[introduction.htm|Language Reference]] > 4 - Entity Declarations > File Structures >====== BLOB (declare a variable-length field) ====== | [[memo declare a text field .htm|{{btn_prev_n.gif|Previous page}}]][[introduction.htm|{{btn_home_n.gif|Return to chapter overview}}]][[record declare record structure .htm|{{btn_next_n.gif|Next page}}]] | | || | //label// | **BLOB** [,**BINARY**] [,**NAME( )**] | {{blk2blue.jpg|blk2blue.jpg}} | //Label// | The label of the BLOB (PROP:Label). | | **BLOB** | Declares a variable-length string stored on disk per record which may be greater than 64K | | **BINARY** | Declares the BLOB a storage area for binary data (PROP:BINARY). | | **NAME** | Specifies the disk filename for the BLOB field (PROP:NAME). | **BLOB** (Binary Large Object) declares a string field which is completely variable-length and may be greater than 64K in size. A BLOB must be declared before the RECORD structure. Generally, up to 255 BLOB fields may be declared in a FILE structure (the exact number and their manner of storage on disk is file driver dependent). A BLOB may not be used as a variable--you may not name a BLOB as a control's USE attribute, or directly assign data to or from the BLOB. You can use PROP:Handle to get the Windows handle to the BLOB entity and assign one BLOB to another: get the handle of both BLOB entities and then assign one BLOB's handle to the other BLOB's handle. A BLOB may not be accessed "as a whole;" you must either use Clarion's string slicing syntax to access the data (unlimited in 32-bit), or PROP:ImageBlob. The individual bytes of data in the BLOB are numbered starting with zero (0), not one (1). PROP:Handle when used with BLOB returns a Windows Global Memory Object Handle for use with low-level Windows GlobalXxxx() API calls that require it. The SIZE procedure returns the number of bytes contained in the BLOB field for the current record in memory. You can also get (and set) the size of a BLOB using **PROP:Size**. You may set the size of the BLOB before assigning data to a new BLOB using string slicing, but it is not necessary as the size is automatically set by the string slice operation. You can also use **PROP:ImageBlob** to store and retrieve graphic images without first setting PROP:Size. It is a good idea to first set PROP:Size to zero (0) before assigning data to a BLOB that has not previously contained data, to eliminate any "junk" leftover from any previously accessed BLOB. When assigning from one BLOB to another using PROP:Handle, you may need to use PROP:Size to adjust the size of the destination BLOB to the size of the source BLOB. PROP:Touched can be used to determine if the contents of the BLOB has changed since it was retrieved from disk. BLOB fields are not in the RECORD structure, and should not be listed in a [[prop sql 2.htm|PROP:SQL]].  If you need to retrieve an image field from an SQL backend, use [[set initiate sequential file processing .htm|SET]]/[[next get next record in sequence .htm|NEXT]] and BLOB syntax to retrieve the blob data. **Example:** **ArchiveFile PROCEDURE** **Names   FILE,DRIVER('TopSpeed')** **NaneKey  KEY(Name)** **Notes    BLOB        !Can be larger than 64K** **Rec      RECORD** **Name      STRING(20)** **         END** **        END** **ArcNames FILE,DRIVER('TopSpeed')** **Notes    BLOB        ** **Rec       RECORD** **Name       STRING(20)** **          END** **         END** ** CODE** ** SET(Names)** ** LOOP** **  NEXT(Names)** **  IF ERRORCODE() THEN BREAK.** **  ArcNames.Rec = Names.Rec                               !Assign rec data to Archive ** **  ArcNames.Notes{PROP:Handle} = Names.Notes{PROP:Handle} !Assign BLOB to Archive ** **  IF ERRORCODE() = 80** **   MESSAGE('BLOB size is too large')** **   BREAK** **  END** **  ArcNames.Notes{PROP:Size} = Names.Notes{PROP:Size}     ! and adjust the size** **  ADD(ArcNames)** ** END** **StoreFileInBlob PROCEDURE                                !Stores any disk file into a BLOB** **DosFileName STRING(260),STATIC** **LastRec     LONG** **SavPtr      LONG(1)                                      !Start at 1** **FileSize    LONG** **DosFile    FILE,DRIVER('DOS'),PRE(DOS),NAME(DosFileName)** **Record      RECORD** **F1           STRING(2000)** **            END** **           END** **BlobStorage  FILE,DRIVER('TopSpeed'),PRE(STO)** **File         BLOB,BINARY** **Record        RECORD** **FileName       STRING(64)** **              END** **             END** ** CODE** ** IF NOT FILEDIALOG('Choose File to Store',DosFileName,,0010b) THEN RETURN.** ** OPEN(BlobStorage)                     !Open the BLOB file** ** STO:FileName = DosFileName            ! and store the filename** ** OPEN(DosFile)                         !Open the file** ** FileSize = BYTES(DosFile)             !Get size of file** ** STO:File{PROP:Size} = FileSize        ! and set the BLOB to store the file** ** LastRec = FileSize % SIZE(DOS:Record) !Check for short record at end of file** ** LOOP INT(FileSize/SIZE(DOS:Record)) TIMES** **  GET(DosFile,SavPtr)                  !Get each record** **  ASSERT(NOT ERRORCODE())** **  STO:File[SavPtr - 1 : SavPtr + SIZE(DOS:Record) - 2] = DOS:Record** **                                       !String slice data into BLOB** **  SavPtr += SIZE(DOS:Record)           !Compute next record pointer** ** END** ** IF LastRec                            !If short record at end of file** **  GET(DosFile,SavPtr)                  !Get last record** **  ASSERT(BYTES(DosFile) = LastRec)     ! size read should match computed size** **  STO:File[SavPtr - 1 : SavPtr + LastRec - 2] = DOS:Record** ** END** ** ADD(BlobStorage)** ** ASSERT(NOT ERRORCODE())** ** CLOSE(DosFile);CLOSE(BlobStorage)** **See Also:** [[prop imageblob.htm|PROP:ImageBlob]] [[prop size.htm|PROP:Size]] [[implicit string arrays and string slicing.htm|Implicit String Arrays and String Slicing]] [[blobtofile copy data from blob field to file .htm|BLOBtoFILE]] [[filetoblob copy data from a file to a blob field .htm|FILEtoBLOB]] [[prop handle.htm|PROP:Handle]] [[prop clienthandle.htm|PROP:ClientHandle]]