我已经确定了在通过Adobe AIR操作数据库时插入到任何blob字段中的随机字节序列。 (从我的结果来看,似乎总是以 bytes [12,...] 开头,但我不确定那个)
我认为这是字节的sizeinfo,让我解释一下我是如何得出这个结论的。
首先我的上下文:我通过Adobe AIR(客户端)和System.data.sqlite(C#服务器端)操作sqlite数据库
使用System.data.sqlite,如果我通过Adobe AIR读取一个填充BLOB的Sqlite数据库,我必须得到AIR开头附加的那些字节,然后我将二进制数据整齐好。完善!
使用Adobe AIR,如果我尝试读取由System.data.Sqlite填充BLOB的sqlite数据库,则数据已损坏,我收到错误消息!显然是因为我没有AIR研究过的缺少的字节。
当然我试图通过复制我在第一种情况下删除的一系列3个字节来添加这些字节,但之后它部分地返回数据,而在图像的情况下,最后一行像素全部变为灰色并且在某些情况下我有或多或少的灰色线条。因为数据对应于相同~4k大小的一系列图像,并且我从其中一个中添加了3个字节,我得到了这个结果。
Air还有时会抛出这个错误:
错误:错误#2030:文件结束了 遇到。
很明显,这些字节给出了大小的信息,但我真的不知道它是怎么做的!?!
我尝试添加一个长度为4k的bytearray,它往往会增加3个字节,但我尝试添加4M,最多可达5个字节。
我发现了这个问题How do you convert 3 bytes into a 24 bit number in C#?,我认为这可能是存储尺寸信息的方式。
但我仍然没有得到它......
答案 0 :(得分:1)
感谢FluorineFX(AMF for .NET)开源项目,这就是答案。
因为在我的Adobe AIR项目中,我必须将我的air.ByteArray对象作为参数传递给sqlite Blob字段中的所有内容; AIR会将所有内容序列化为AMF,这是一种紧凑的二进制动作消息格式。
Page 11 Secion 3.14 ByteArray类型
http://opensource.adobe.com/wiki/download/attachments/1114283/amf3_spec_05_05_08.pdf
该文件规定:
AMF 3使用a序列化此类型 可变长度编码29位 字节长度前缀的整数 然后是原始字节 的ByteArray。
但不是全部,我搜索了一个AMF .NET开源项目并创立了FluorineFX。查看代码,我发现每个AMF二进制文件都以字节TypeCode为前缀,对于ByteArray 12 :
/// <summary>
/// AMF ByteArray data type.
/// </summary>
public const byte ByteArray = 12;
进一步搜索并再次在FluorineFX源中找到 AMFReader.ReadAMF3ByteArray()和 AMFWriter.WriteByteArray()
这有助于我快速构建我需要的东西:
private static byte[] RemoveAMF3ByteArrayPrefixBytes(byte[] ar)
{
var ms = new MemoryStream(ar);
var br = new BinaryReader(ms);
// if first byte is AMF TypeCode for ByteArray
if (br.Read() != 12)
return ar;
int handle = ReadAMF3IntegerData(br);
bool inline = ((handle & 1) != 0);
handle = handle >> 1;
if (inline)
{
int length = handle;
byte[] buffer = br.ReadBytes(length);
return buffer;
}
return ar;
}
private static byte[] AddAMF3ByteArrayPrefixBytes(byte[] ar)
{
var ms = new MemoryStream();
var bw = new BinaryWriter(ms);
bw.Write((byte)12); // AMF TypeCode for ByteArray
var handle = (int)ar.Length;
handle = handle << 1;
handle = handle | 1;
WriteAMF3IntegerData(bw, handle);
bw.Write(ar);
return ms.ToArray();
}
/// <summary>
/// Handle decoding of the variable-length representation which gives seven bits of value per serialized byte by using the high-order bit
/// of each byte as a continuation flag.
/// </summary>
/// <returns></returns>
private static int ReadAMF3IntegerData(BinaryReader br)
{
int acc = br.ReadByte();
if(acc < 128)
return acc;
else
{
acc = (acc & 0x7f) << 7;
int tmp = br.ReadByte();
if(tmp < 128)
acc = acc | tmp;
else
{
acc = (acc | tmp & 0x7f) << 7;
tmp = br.ReadByte();
if(tmp < 128)
acc = acc | tmp;
else
{
acc = (acc | tmp & 0x7f) << 8;
tmp = br.ReadByte();
acc = acc | tmp;
}
}
}
//To sign extend a value from some number of bits to a greater number of bits just copy the sign bit into all the additional bits in the new format.
//convert/sign extend the 29bit two's complement number to 32 bit
int mask = 1 << 28; // mask
int r = -(acc & mask) | acc;
return r;
//The following variation is not portable, but on architectures that employ an
//arithmetic right-shift, maintaining the sign, it should be fast.
//s = 32 - 29;
//r = (x << s) >> s;
}
private static void WriteAMF3IntegerData(BinaryWriter bw, int value)
{
//Sign contraction - the high order bit of the resulting value must match every bit removed from the number
//Clear 3 bits
value &= 0x1fffffff;
if (value < 0x80)
bw.Write((byte)value);
else
if (value < 0x4000)
{
bw.Write((byte)(value >> 7 & 0x7f | 0x80));
bw.Write((byte)(value & 0x7f));
}
else
if (value < 0x200000)
{
bw.Write((byte)(value >> 14 & 0x7f | 0x80));
bw.Write((byte)(value >> 7 & 0x7f | 0x80));
bw.Write((byte)(value & 0x7f));
}
else
{
bw.Write((byte)(value >> 22 & 0x7f | 0x80));
bw.Write((byte)(value >> 15 & 0x7f | 0x80));
bw.Write((byte)(value >> 8 & 0x7f | 0x80));
bw.Write((byte)(value & 0xff));
}
}
我希望这能帮助别人。
答案 1 :(得分:0)
非常感谢,这帮助我解决了这个问题。以下是使用Java代码的方法:
为您的项目添加org.granite花岗岩核心依赖
使用样板代码
初始化GDSGraniteConfig graniteConfig = new GraniteConfig(null, null, null, null);
ServicesConfig servicesConfig = new ServicesConfig(null, null, false);
Map<String, Object> applicationMap = new HashMap<String, Object>();
SimpleGraniteContext.createThreadIntance(graniteConfig, servicesConfig, applicationMap);
在我的例子中,我读了一个我将插入BLOB的图像文件:
fis = new FileInputStream(file);
ps = connection.prepareStatement(INSERT_PICTURE);
ps.setString(1, key);
byte[] fileBytes = FileUtils.readFileToByteArray(file);
ByteArrayOutputStream out = new ByteArrayOutputStream();
AMF3Serializer ser = new AMF3Serializer(out);
ser.writeObject(fileBytes);
ser.flush();
ps.setBytes(2, out.toByteArray());
像魅力一样,感谢提示:)
法比安