I am trying to read data from a LONG column in Oracle which is storing an Image file. When doing so I am getting following :
IL 39 321 30580� 3� 10 0 59��
����\0\u0010JFIF\0\u0001\u0001\0\0\0\0\0\0\0��\0C\0\b\u0006\u0006\
I think the question marks are not allowing me to decode the string.
What is the meaning of these �� ?
Thanks,
In general you should not use LONG data type at all. It is deprecated for ages.
Apart from that, data type LONG is used for text data, i.e. like VARCAHR2 or CLOB. You cannot use it for binary data like images.
Update based on comment
Try this function to convert LONG to BLOB - Good luck!
CREATE OR REPLACE FUNCTION ConvertLONG(InChar IN LONG) RETURN BLOB IS
dest_lob BLOB;
lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;
dest_offset INTEGER := 1;
src_offset INTEGER := 1;
read_offset INTEGER := 1;
warning INTEGER;
BEGIN
DBMS_LOB.CREATETEMPORARY(dest_lob, TRUE);
DBMS_LOB.CONVERTTOBLOB(dest_lob, TO_LOB(InChar), DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset, DBMS_LOB.DEFAULT_CSID, lang_context, warning);
RETURN dest_lob;
END;
First of all, you should avoid using LONG data type columns and switch to BLOB (or CLOB, depending on what you plan to store in there). In your case, as that column contains images, that would be a BLOB.
You can't expect a SQL SELECT statement to return an image "as is" (i.e. to actually see that image on the screen) - all you get is that heap of junk characters. That's expected, it is a binary file, after all.
As you use TOAD, go to Schema Browser, open that table, view its data, right-click column that stores images and choose "Export Blobs (Longs, Raws ...)" from the menu. Follow instructions and export images into some folder on a disk.
Otherwise, you'd have to create an application (for example, using Apex) which is capable of displaying/downloading images.
If that's not what you are trying to do (as you mentioned that you'd want to "decode" a string), could you explain it?
Related
PROGRAM archivosejercic1o;
TYPE
num = file of integer;
VAR
arch_num: num;
name: string[20];
x: integer;
BEGIN
writeln('Type the name of the file without extension:');
readln(name);
name:=name+'.txt';
Assign (arch_num,name);
Rewrite(arch_num);
writeln('Type in a number to add to the file:');
readln(x);
WHILE (x <> 0) DO BEGIN
write(arch_num,x);
writeln('Type in another number to add to the file:');
readln(x);
END;
close(arch_num);
END.
I have this code which creates a file with a series of numbers that the user provides, after compiling and executing the file appears in the Pascal directory but when I open it, I get something like this:
I'm just starting to interact with archives so I'm brand new at this, if you can help me I'd be thankful.
Binary vs. text
You are opening a file of Integer. This means that you write integers to the file, i.e. the file is in a binary format.
But you name it name + '.txt', which suggests to me you want to write text, not binary values, to the file.
Now if you display it as text, but it isn't text, you don't get what you want.
Binary means that you, for instance, write a 4 byte integer like 12345 (or hex $3039) as those 4 bytes, i.e. the bytes $39, $30, $00 and $00, in that order (or in reverse order, depending on the endianness of your computer).
Binary is compact, but seldom human readable. If you display such a binary file as text, you may get weird output, or perhaps even none at all (just try to open an .exe file in a text editor and see what you get). You probably want to write the numbers as text. Or you use something like a hex editor to view them (if you can read hex).
So open your files as type text:
PROGRAM archivosejercic1o;
TYPE
num = text;
VAR
arch_num: num;
name: string[20];
x: integer;
BEGIN
...
writeln(arch_num, x);
...
END.
More info on binary vs text: https://fileinfo.com/help/binary_vs_text_files. Note that that doesn't explain the different versions of Unicode text yet.
I'm looking for an easy/quick way to identify and extract hashtags from a string, and temporarily store them separately - e.g.:
If I have the following string:
2017-08-31 This is a useless sentence being used as an example. #Example #Date:2017-09-01 #NothingWow (and then some more text for good measure).
Then I want to be able to get this:
#Example
#Date:2017-09-01
#NothingWow
I figured storing it in a TStringList should be sufficient until I'm done. I just need to store them outside of the original string for easier cross referencing, then if the original string changes, add them back at the end.
(but that's easy - its the extracting part I'm having trouble with)
It should start at the # and end/break when it encounters a [space].
The way I initially planned it was to use Boolean flags (defaulted to False), then check for the different hashtags, set them to true if found, and extract anything after a [:] separately.
(but I'm sure there is a better way of doing it)
Any advice will be greatly appreciated.
The following shows a simple console application which you could use as the basis
for a solution. It works because assigning your input string to the DelimitedText property of a StringList causes the StringList to parse the input into a series of space-limited lines. It is then a simple matter to look for the ones which start with a #.
The code is written as a Delphi console application but should be trivial to convert to Lazarus/FPC.
Code:
program HashTags;
{$APPTYPE CONSOLE}
uses
Classes, SysUtils;
procedure TestHashTags;
var
TL : TStringList;
S : String;
i : Integer;
begin
TL := TStringList.Create;
try
S := '2017-08-31 This is a useless sentence being used as an example. #Example #Date:2017-09-01 #NothingWow (and then some more text for good measure)';
TL.DelimitedText := S;
for i := 0 to TL.Count - 1 do begin
if Pos('#', TL[i]) = 1 then
writeln(i, ' ', TL[i]);
end;
finally
TL.Free;
end;
readln;
end;
begin
TestHashTags;
end.
I need someone could help me out on how to trace the error of "mismatched data type" in visual foxpro 6.0 When I issues a command like this "insert into tmpcur from memvar".
tmpcur is a cursor having bulk numbers of columns and it is ready hard to trace which one is having mismatch in data type for insertion problem.
It is pretty difficult to trace the insertion loop of each record into VFP tables one by one unliked MSSQL profiler.
Appreciate to someone could help. Thanks.
This should help you. I have a temp cursor created with some bogus field / column names testing for types of character, integer, double, currency, date and time. Trying to follow what is the result of your scenario, I am taking the memory variable of "bbbb" which should be double (or numeric at the least), and changed it to a string.
I am then HOLDING the error trapping routine that MAY be in effect, then setting my own (as I don't think try/catch existed in VFP6.. it may, but I just don't remember. So, I did an ON ERROR, set a variable to true. Then, I default it to false, try the insert, then check the flag. If the flag IS set, then I go into a loop and try for each column in the given table/alias (in my example it is "C_Tmp", so replace with your table/alias). It goes through each variable, and if the data type is different from the table structure, it will dump the column name and table / memory value for you to review.
You could put this to a log file or something.
Now, another consideration. Some types are completely valid and common for implied conversion, such as character and memo fields can both get strings. Integer, double, float, currency can all work with generic "numeric" values.
So, if you encounter these differences, then we can go one level further and look for comparable types, but let me know and we can adjust as needed.
At least this should give you a huge jump to your insert issue.
CREATE CURSOR C_tmp ( cccc c(10), iiii i, bbbb b(2), ccyyyy y, ddd d, tttt t )
SCATTER MEMVAR memo
m.bbbb = "wrong data type, was double with 2 decimal"
lcHoldError = ON("ERROR")
ON ERROR lFailInsert = .t.
lFailInsert = .f.
INSERT INTO C_Tmp FROM memvar
IF lFailInsert
FOR lnI = 1 TO FCOUNT( "C_Tmp" )
lcTmp = FIELD( lnI, "C_Tmp" )
IF NOT TYPE( "C_Tmp." + lcTmp ) == TYPE( "m.&lcTmp" )
? "Invalid " + lcTmp + ", C_Tmp.&lcTmp, m.&lcTmp
ENDIF
ENDFOR
ENDIF
ON ERROR &lcHoldError
I have a BITSTREAM from XML message. An I want to break in to multiple parts of equal size depending upon of the length of stream using ESQL i.e. if my bitstream 1000 characters I want to break it in to 200character equal sets. And late I want to pass this parts to a store procedure to insert or update the table. I have BITSREAM Something like this
DECLARE vBlobMsgBody BLOB;
DECLARE refIn REFERENCE TO Environment.OriginalXML;
DECLARE vEncoding INT InputRoot.Properties.Encoding;
DECLARE vCCSID INT InputRoot.Properties.CodedCharSetId;
DECLARE vMsgBitStream BLOB ASBITSTREAM(refIn,1208);
How I will be to do that?
You can use the same function of CHARACTER variables.
SO you can use functions like:
DECLARE BLOB_LENGTH INTEGER LENGTH(vMsgBitStream);
DECLARE FIRST_PART BLOB SUBSTRING(vMsgBitStream FROM 1 FOR 200);
I am trying to learn Free Pascal using Lazarus and one of my pet projects involves reading the 64 byte headers of a particular set of untyped files that cannot be read and displayed using text or ASCII related procedures (so cannot be outputted directly to Memo boxes etc).
So far, I have devised the following code which does, I think, read in the 64 bytes of the header and I am using TStreams and a "Select Directory" dialog box to do this, based on advice received via the Lazarus IRC. My question though is how to actually USE the data that is read into the buffer from the header? For example, in the headers, there are sequences of 8 bytes, then 16 bytes, then 2 bytes and so on that I want to "work on" to generate other output that will eventually be converted to a string to go into my string grid.
Some of what I have so far is based on what I found here written by Mason Wheeler near the end (http://stackoverflow.com/questions/455790/fast-read-write-from-file-in-delphi) but it only shows how to read it in, not how to use it. I also read this (http://stackoverflow.com/questions/4309739/best-way-to-read-parse-a-untyped-binary-file-in-delphi) but again, it shows you how to READ the data too, but not subsequently USE the data. Any guidance wamrly received! So far, the code below just outputs single value integer numbers to the edit box, as opposed to, say, a range of 8 hexadecimal values.
PS - I am new to programming so please be gentle! Nothing too complex.
procedure TForm1.ProbeFile(FileIterator: TFileIterator);
type
TMyHeader = Array[1..64] of packed record
First8Bytes,
Next16Bytes,
Next2Bytes: byte;
end;
var
FI : TFileIterator; //File Iterator class
SG : TStringGrid;
NumRead : SmallInt;
FileToProbe: TStream;
header: TMyHeader;
begin
FI := TFileIterator.Create;
SG := TStringGrid.Create(self);
// Open the file and read the header
FileToProbe := TFileStream.Create(FileIterator.FileName, fmOpenRead);
try
FileToProbe.seek(0, soFromBeginning);
FileToProbe.ReadBuffer(header, SizeOf(header));
edit1.text := IntToStr(header[0].First8Bytes); // Just outputs '0' to the field? If I try '10' it ooutputs '29' and so on
finally
FileToProbe.Free;
end;
Please forgive me if I misunderstood your question.
As I understand it there is a header of 64 bytes. The first 8 bytes belong together, then the next 16 bytes and finally another 2 bytes.
To me it seems the declaration for this header should be:
TMyHeader = packed record
First8Bytes: array[0..7] of byte;
Next16Bytes: array [0..15] of byte;
Next2Bytes: array [0..1] of byte;
// add more if you like
end;
This recordtype has a size of 8+16+2 = 26 bytes.
Your code that reads the header looks ok to me, So I won't repeat that.
The next16bytes in your header can be retrieved, for example, like this:
edit1.text:= '';
// needs a declaration of a variable "i" as integer
for i:= 0 to 15 do
edit1.text:= edit1.text + IntToStr(header.next16bytes[i]) + '-';
Change the value of the first byte in the next2bytes part of your header as follows (again as an example):
header.next2bytes[0]:= 123;
Finally, you could write your changes back to the header of the file with help of the filetoprobe.writebuffer method.