食 品 相 克 列 表 |
1.猪肉菱角若共食,肚子疼痛不好受. 2.牛肉栗子一起吃,食后就会发呕吐. 3.羊肉滋补大有用,若遇西瓜定相侵. 4.狗肉滋补需注意,若遇绿豆定伤身. 5.兔肉芹菜本不合,同食之后头发脱. 6.鸡肉芹菜也相忌,同食就会伤元气. 7.鹅肉鸡蛋不同窝,一同入胃伤身体. 8.鲤鱼甘草性相反,兼食而之定伤身. 9.黄鳝皮蛋皆佳肴,不可同桌结伴行. 10.鸡蛋若遇消炎片,同室操戈两相争. 11.鸡蛋糖精更相克,同食中毒更伤身. 12.柿子红薯若同吃,体内结石易形成. 13.柿子螃蟹也相背,同食之后会腹泻. 14.柿子白酒更不合,食后使你心发闷. 15.豆腐蜂蜜伴着吃,味道虽好耳要聋. 16.洋葱蜂蜜也不合,同食就会伤眼睛. 17.香蕉芋头本不合,同时入胃腹胀痛. 18.香蕉相克马铃薯,同食面部要起斑. 19.黄瓜生熟都可以,进食之际忌花生. 20.萝卜木耳不同食,食了容易生皮炎. 21.萝卜水果更相背,甲状腺肿会诱发. |
* 以下食物两小时内不能同时食用,否则会发生中毒,甚至有生命危险,千万不可大意,提供中毒解救小窍门,供参考: 鲤鱼与甘草:食则死亡。解救:吃麻油二两; 狗肉和绿豆:食则胀腹。解救:甘草一两煎水服; 桃子下烧酒:食则昏倒,多吃死亡。解救:服牛黄解毒丸三粒; 黄瓜与花生:食则泻肚。解救:吃藿香正气丸二粒; 蜂糖与生葱:食则死亡。解救:米炒枯研末,再用甘草二两煎水冲枯米吃; 茶煮青蛙:食则死亡,无法解救; 蚕豆与田螺:食则绞畅痛。解救:吃儿童小便二两; 香蕉与芋头:食则中毒。解救:吃桐油五钱; 冰棒与西红柿:食则中毒。解救:吃穿心莲二两煎水服; 羊肉和西瓜:食则中毒。解救:甘草二两煎水服; 猪肉和芝麻花:食则死亡。解救:吃空心菜汁二两; 芥菜与兔肉:食则死亡。解救:吃杨梅水二两; 不可单用生姜下酒:食则胃脘痛,多吃则烂肝脏; 冬笋和龟肉:食则中毒。解救:甘草二两煎水服; 鲫鱼与冬瓜:食则脱水。解救:吃空心菜汁二两; 黄疸病忌马肉:食则死亡。无法解救 甜酒与味精:食则中毒。解救:甘草煎水服; 牛肉与香附子:食则生九子疡; 油煎鸡蛋与糖精:食则中毒。解救:牛黄五分,开水服; 鹿肉与南瓜:食则死亡。无法解救; 抬头黄鳝不能吃:食则死亡。无法解救; 洋葱与癞蛤蟆:食则死亡。解救:车钱子一两水煎服; 红薯与柿子:食则胃结石,多吃死亡; 螃蟹与柑桔:食则中毒。解救:吃大蒜汁; 螃蟹与柿子:食则中毒。解救:吃藕节(煮水) 螃蟹与泥鳅:食则中毒。解救:吃黄泥水 螃蟹与茄子:食则中毒。解救:吃藕节(煮水) 螃蟹与香瓜:食则中毒。解救:吃柑桔皮 螃蟹与生花生:食则中毒。解救:吃黄泥水 螃蟹与冰水:食则中毒。解救:吃藕节(煮水) 田螺与玉米:食则中毒。解救:吃黄泥水。 田螺与香瓜:食则中毒。解救:吃黄泥水。 鲫鱼与蜂糖;食则中毒。解救:吃黑豆甘汤草 牛奶与酸醋物:食则腹结石。解救:吃绿豆汤 牛肉与韭菜:食则中毒。解救:吃人奶或豉汁 蟮鱼与红枣:吃则脱发。解救:吃蟹 牛奶与菠菜:食则拉痢。解救:吃绿豆汤 鳝鱼与南瓜:食则中毒。解救:吃蟹 竹笋与麦芽糖;食则中毒。解救:吃绿豆汤 番茄与石榴:食则中毒。解救:吃韭菜汁 鸡肉与李子:食则拉痢,解救:吃鸡屎白 鸭蛋与李子:食则中毒。解救:吃黄泥水 竹笋与羊肝:食则中毒。解救:吃黄泥水 雀肉与李子:食则中毒。解救:吃鸡屎白 黑枣与柿子:食则解释。解救:无方 以上仅供参考,若发生中毒症状,应及时送医院为妥。 |
1、萝卜: 严禁与桔子同食,同食患甲状腺肿;忌何首乌、地黄;服人参时忌食;忌与胡萝卜同食。 2、胡萝卜:不宜和西红柿、萝卜、辣椒、石榴、莴苣、木瓜等水果同吃。最好单独吃肉类烹调。 3、黄瓜: 不宜和维生素c含量高的蔬菜如西红柿、辣椒等同烹调。 4、甘薯: (红薯、白薯、地瓜、山芋);不能与柿子同食,二者相聚会形成胃柿石,引起胃胀、腹痛、 呕吐,严重时可导致胃出血等,危及生命;也不宜与香蕉同吃。 5、韭菜: 不可与菠菜同食,二者同食有滑肠作用,易引起腹泻;不可与蜂蜜同食,同食则令人心痛; 不可与牛肉同食,同食令人发热动火。 6、茄子: 忌与黑鱼、蟹同食,同食有损肠胃;过老熟的茄子不宜食,易中毒。 7、菠菜: 忌韭菜;不宜与豆腐同食,同食使人缺钙。 8、小白菜:忌兔肉。 9、南瓜: 不可与羊肉同食,否则易发生黄疸和脚气;不可与富含维生素c 的蔬菜、水果同食。 10、竹笋: 不宜与豆腐同食,同食易生结石;不可与鹧鸪肉同食,同食令人腹胀;不可与糖同食;不宜与羊肝同食。 11、辣椒: 忌与羊肝、南瓜同食。 12、香菜: 不可与一切补药同食;忌白术、牡丹皮。 13、莼菜: 忌与醋同食。 14、茭白: 不宜与豆腐同食,否则易形成结石。 15、芹菜: 忌同醋食,否则易损齿;不宜与黄瓜同食。 16、芥菜: 忌与鲫鱼同食,否则易引发水肿。 17、蕨菜: 忌与黄豆、花生、毛豆等同吃。 18、菜瓜: 忌与牛奶、奶酪、鱼类同食,否则易生疾病。 19、山药: 忌鲫鱼、甘遂。 20、豆腐(豆浆):不要与牛奶同食;不要与菠菜同烹调;忌用豆浆冲鸡蛋;忌与四环素同用。 21、木耳: 忌与田螺、雉鸡、野鸭、鹌鹑肉同食;忌与四环素同服 22、苋菜: 不宜与菠菜、蕨粉同食 23、苦菜: 不可与蜂蜜同食 24、花生: 忌蕨菜、毛蟹、黄瓜。 25、马齿苋:不宜与鳖甲同食。 26、香瓜: 忌与蟹、田螺、油饼同吃 27、猪肉: 忌与鹌鹑同食,同食令人面黑;忌与鸽肉、鲫鱼、虾同食,同食令人滞气;忌与荞麦同食,同食令人落毛发;忌与菱角、黄豆、蕨菜、桔梗、乌梅、百合、巴豆、大黄、黄连、苍术同食;忌与牛肉、驴肉、羊肝同食。 28、猪脑髓:不可与酒、盐同食,影响男子性功能; 29、羊肉: 忌与豆酱、荞麦面、乳酪、南瓜、醋、赤豆、梅干菜同食;忌铜、丹砂。 30、鸡肉: 老鸡鸡头不能吃,因毒素滞留在脑细胞内,民间有"十年鸡头生砒霜"的说法;忌与糯米、李子、大蒜、鲤鱼、鳖鱼、虾、兔肉同食;忌芥末、菊花。 31、猪油: 不宜与梅子同食。 32、牛肉: 不可与鱼肉同烹调;不可与栗子、黍米、蜂蜜同食;不宜与韭菜、白酒、生姜同食。 33、猪肝: 忌与荞麦、黄豆、豆腐同食,同食发痼疾;忌与鱼肉同食,否则令人伤神;忌与雀肉、山鸡、鹌鹑肉同食。 34、牛肝: 忌鲍鱼、鲇鱼;不宜与富含维生素c的食物同食。 35、鸭肉: 反木耳、胡桃;不宜与鳖肉同食,同食令人阴盛阳虚,水肿泄泻。 36、狗肉: 忌与绿豆、杏仁、菱角、鲤鱼、泥鳅同食;忌用茶;不宜与大蒜同食。 37、猪血: 忌黄豆,同食令人气滞;忌地黄、何首乌。 38、羊心、 羊肝:忌与生椒、梅、赤豆、苦笋、猪肉同食;不宜与富含维生素c的蔬菜同食。 39、驴肉: 忌荆芥;不宜与猪肉同食,否则易致腹泻。 40、马肉: 不宜与大米(粳米)、猪肉同食;忌生姜、苍耳。 41、鹅肉: 不宜与鸭梨同吃。 42、鹿肉: 不宜与雉鸡、鱼虾、蒲白同食 43、雀肉: 春夏不宜食,冬三月为食雀季节。不宜与猪肝、牛肉、羊肉同食;忌李子、白术。 44、鸡蛋: 忌与柿子同食,同食可引起腹痛、腹泻,易形成"柿结石";不宜与兔肉、鲤鱼、豆浆同食;民间有吃"毛蛋"之习,其实"毛蛋"中含有大量病菌,易中毒。 45、鸭蛋: 不宜与李子、桑椹子同食。 46、野鸭: 忌与木耳、核桃、荞麦同食 47、鹧鸪肉:忌与竹笋同食 48、水獭肉:忌与兔肉、柿子同吃 49、獐肉: 不宜与虾、生菜、梅子、李子同食 50、鹌鹑肉:不宜与猪肉、猪肝、蘑菇、木耳同食。 51、雉鸡(野鸡)不宜与猪肝、鲇鱼、鲫鱼、木耳、胡桃、荞麦同食 52、猫肉: 忌藜芦;猫肉有伤胎之弊,孕妇忌服。 53、虾: 严禁同时服用大量维生素c。否则,可生成三价砷,能致死,不宜与猪肉同食损精;忌与狗、鸡肉同食;忌糖。 54、鲤鱼: 忌朱砂、狗肉。葵菜、赤小豆、咸菜不宜与狗肉同食。 55、泥鳅: 不宜与狗肉同食。 56、海带: 不宜与甘草同食。 57、鲫鱼: 不宜与芥菜、猪肝、猪肉、蒜、鸡肉、鹿肉等同食;忌山药、厚朴、麦冬、甘草。 58、鳖肉: 忌猪肉、兔肉、鸭蛋、苋菜;忌与薄荷同煮;忌与鸭肉同食,久食令人阴盛阳虚,水肿泄泻。 59、带鱼、 平鱼、银鱼、黄花鱼:忌用牛、羊油煎炸;凡海味均禁甘草;反荆芥。 60、龟肉: 不宜与酒、果、瓜、猪肉、苋菜同食。 61、蜗牛: 忌蝎子。 62、田螺: 忌与香瓜、木耳、蛤蚧、冰糖同食;忌与四环素同用。 63、鲶鱼: 不宜与牛肝同食;忌用牛、羊油煎炸;不可与荆芥同用。 64、鳝鱼: 忌狗血、狗肉,同食助热动风;忌荆芥,同食令人吐,青色鳝鱼有毒,黄色无毒。有毒鳝鱼一次吃250克,可致死。 65、海鳗鱼:不宜与白果、甘草同食。 66、青鱼: 忌用牛、羊油煎炸;不可与荆芥、白术、苍术同食。 67、牡蛎肉:不宜与糖同食。 68、枣: 不可与海鲜同食,否则令人腰腹疼痛;不可与葱同食,否则令人脏腑不合,头胀。 69、苹果: 不宜与海味同食(海味与含有鞣酸的水果同吃,则易引起腹痛、恶心、呕吐等)。 70、鸭梨: 忌鹅肉、蟹;忌多吃;忌与油腻、冷热之物杂食。 71、桔子: 忌与萝卜同食,同食诱发甲状腺肿;忌与牛奶、蟹、蛤同食。 72、山楂、 石榴、木瓜、葡萄:不宜与海鲜类、鱼类同食;服人参者忌用;忌铁器;忌和四环素同吃。 73、桃子: 不宜与鳖肉、龟肉同食。 74、香蕉: 不宜与白薯同食。 75、柿子: 忌与蟹、水獭肉同食,同食腹痛、大泻;忌与红薯、酒同食。 76、杨梅: 忌生葱;不宜与羊肛,鳗鱼同食。 77、杏: 忌与小米同食,否则令人呕泻。 78、芒果:忌与大蒜等辛物同食。 79、银杏(白果):严禁多吃,婴儿吃10颗左右可致命,三、五岁小儿吃30~40颗可致命;不可与鱼同吃,同食则产生不利于人体的生化反应,小儿尤忌。 80、柑子:忌与蟹同食。 81、大米(粳米):不可与马肉同食,不可与苍耳同食,同食心痛; 82、黄豆:不宜与猪血、蕨菜同食;服四环素时忌用。 83、绿豆:不宜与狗肉、榧子同食 84、小米(粟米)不可与杏同食,同食易使人呕吐泄泻;气滞者忌用。 85、黑豆:忌与厚朴、蓖麻籽、四环素同用。 86、红豆:忌与米同煮,食之发口疮;不宜与羊肉同食;蛇咬伤,忌食百日;多尿者忌用。 87、葱: 不宜与杨梅、蜜糖同食,同食易气壅胸闷;忌枣、常山、地黄。 88、醋: 忌丹参、茯苓;不宜与海参、羊肉、奶粉同食;忌壁虎,可致死。 89、糖: 忌虾;不可与竹笋同煮;不宜与牛奶、含铜食物同食。 90、酒: 忌与汽水、啤酒、咖啡、奶、茶、糖同饮,不然对胃肠、肝、肾脏器官有严重的损害;不宜与牛肉、柿同食。 91、茶: 贫血病人服用铁剂时,忌饮茶。不宜与狗肉同食;服人参等滋补药品时忌用。 92、蒜: 一般不与补药同服。忌蜜、地黄、何首乌、牡丹皮; 93、花椒:忌防风、附子、款冬。 94、牛奶:忌牛奶中放钙粉;勿用牛奶冲鸡蛋;不宜与巧克力、桔子, 四环素同食。 95、蜜: 不宜与葱、蒜、韭菜、莴苣、豆腐同食,不然易引起腹泄 |
星期日, 十二月 03, 2006
食 品 相 克 列 表
星期五, 十一月 24, 2006
Delphi之面向对象程序开发
作者:熊建峰 网址:http://www.passtwo.com 邮箱:passtwo@gmail.com
使用Delphi编程也有一段时间了,Delphi开发程序效率很高,但是一直感觉和VB开发程序没有什么两样,除了语法的区别之外就是在控件、窗体等基础上进行程序开发了,Delphi面向对象开发的特点没有一点体现出来。
最近在开发一个应用程序的时候对系统代码进行查看,才恍然大悟,其实,基于Delphi的VCL组件下的开发实际上就已经遵循了面向对象的规则。举例说明如下:
例1:一个普通的Delphi窗体
我们利用Delphi进行程序开发的时候,首先就是一个窗体,设置好窗体的属性,好了,我们来看看窗体的代码。如下:
type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
private
{ Private declarations }
public
{ Public declarations }
end;
首先看看这段代码,定义了一个类型TForm1,它集成自TForm类,同时有两个属性:Edit1和Button1。同时还有可以添加private和public的地方。从面向对象的角度来讲,这属于面向对象的一个典型应用(使用了集成来生成新的类型)。那么,有人会说,在delphi下本来就是这样,跟我的程序有什么关系?我又怎样才能把面向对象的方法应用到我的程序中来呢?下面我来举一个例子说明。
例2:一个简单的继承
图1列出了一个大家比较熟悉的继承关系,图中包含三各类:水果,苹果,桔子。水果作为基类,它有两个属性:颜色和重量,另外水果都可以被食用,但是不同的水果有不同的方法,所以在水果类中有一个public abstract void 食用(),所有水果的子类必须实现该方法。苹果和桔子为水果的子类,它们集成了水果的基本特性:颜色和重量,另外它们分别实现了水果的食用()方法。它们的代码看起来如下:
unit Ufruit;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Forms, Dialogs;
type
TFruit = class(TObject)
private
mColor: Integer;
weight: Integer;
public
procedure eat; virtual; abstract;
end;
TApple = class(TFruit)
public
procedure eat;
end;
TOrange = class(TFruit)
public
procedure eat;
end;
implementation
{
************************************ TApple ************************************
}
procedure TApple.eat;
begin
end;
{
*********************************** TOrange ************************************
}
procedure TOrange.eat;
begin
end;
end.
以上的代码是继承关系在Delphi下的编写,那么这些东西怎样才能和VCL组件结合起来,形成我们所熟悉的Form展现给用户呢?下面我们举例说明这个问题
图1
例三:使用Form实现水果的集成
有了我们水果的类图,我们使用Delphi的窗体来对水果集成关系做一个界面出来,首先是基类:TFruit,窗体界面如图2:
图2
它的代码如下:
unit UFruit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TfrmFruit = class(TForm)
mColor: TEdit;
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure eat; virtual; abstract;
end;
var
frmFruit: TfrmFruit;
implementation
{$R *.dfm}
procedure TfrmFruit.Button1Click(Sender: TObject);
begin
eat;
end;
end.
接下来我们实现苹果类:选择File->New->Other->project1,如图3所示
图3
点击ok后,将出现苹果类的窗体(有没有感觉和水果类很像呀^_^),更改窗体的caption和name属性,然后实现fruit的eat方法,好了,我们的苹果类就做好了,如图4:
图4
它的代码如下:
unit UApple;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, UFruit, StdCtrls;
type
TfrmApple = class(TfrmFruit)
private
{ Private declarations }
public
{ Public declarations }
procedure eat;override;
end;
var
frmApple: TfrmApple;
implementation
{$R *.dfm}
{ TfrmApple }
procedure TfrmApple.eat;
begin
Application.MessageBox ('我是苹果,吃起来是甜的!','',32);
end;
end.
同样的方法,实现桔子类,程序界面如图:
图5
代码如下:
unit UOrange;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, UFruit, StdCtrls;
type
TfrmOrange = class(TfrmFruit)
private
{ Private declarations }
public
{ Public declarations }
procedure eat;override;
end;
var
frmOrange: TfrmOrange;
implementation
{$R *.dfm}
{ TfrmOrange }
procedure TfrmOrange.eat;
begin
Application.MessageBox('我是桔子,吃起来是酸的!','',32);
end;
end.
小结
以上我们使用Delphi的窗体实现了水果类、苹果类和桔子类,这样,就将实际的业务类和VCL组件类结合起来了。使用同样的方法,我们在进行数据库编程的时候可以首先考虑进行业务建模,然后画出类图,最后使用Delphi的窗体来完成整个程序的开发。我写这篇文章旨在抛砖引玉,欢迎大家一起讨论。
星期一, 十一月 06, 2006
针对URL的SEO方法-随想飞翔
作者:Cloudream http://www.5iya.com/blog/
转载请注明以上信息
匹配指匹配用户搜索关键字。
1. 主域名匹配优于目录名或网页名匹配。
2. 英文关键字之间应使用 - 或 _ 链接。
3. 针对中文关键字,中文目录名和网页名优于英文目录名和网页名。Google、百度可识别中文目录名和网页名,但其它搜索引擎未知。中文目录名和网页名可能导致部分浏览器无法识别该URL。
"
Google Adsense 提示100条-随想飞翔
1. AdSense 收入 = 广告展示次数 x 点击率 x 点击单价 x 智能定价因素(Smart Price)
2. 广告展示次数基于你的网站流量,该项代表Adsense广告展示次数。(译注:废话-。-!)
3. 点击率为广告被点击次数÷广告展示次数,基本范围为0.1%-30%,大多数为1%-10%(译注:中文广告偏低,大陆地区平均点击率约0.2%)。
4. 点击单击为每次点击的收入,一般根据广告商付出的点击单价决定。
5. 智能定价机制为Google衡量你的网站刊登广�"
星期四, 十一月 02, 2006
计算机二级上机考试评分方法 - QQread.com 教育频道
http://edu.qqread.com 作者:玲珑草草 来源:
上机必读
二级上机考试部分评分方法
自动评分系统有客观、公正的优点,但也有死板的缺点,要想得到比较好的分数,应当考虑到机器的这一特点。实际考试还有人工复查一项,由省级考试部门负责进行.但是人工复查如何进行,我们完全不得而知。因此我们下面的所有内容均不含人工复查内容,仅从考试系统本身来进行分析和说明。
我们从多次使用中摸索�"
星期二, 十月 24, 2006
给控件做数字签名之三:进行数字签名 - 阿泰的软件实用主义 - 博客园
文中提到的数字签名工具包,请在此处下载
http://www.cnblogs.com/Files/babyt/SignTool.rar
至此,数字签名完成
在DOS窗口下,输入
chktrust.exe E:\myTest\08\Package\WebRTF.CAB
对我们的成果进行检验
此时成功,对了,这个“恭喜”的红字是我做上去的,可别到时候这俩字出不来还觉得奇怪
最后就是发布了
将这两个文件拷贝到WEB目录下进行测试,出现证书安装提示后按是安装即可
"
星期二, 十月 17, 2006
请教如何获得所有当前用户可以访问的,不是系统表的表名和列名? - ITPUB论坛
FROM all_col_comments
WHERE OWNER NOT IN('SYS','SYSTEM');"
如何有效地利用oracle的数据字典
数据字典里存有用户信息、用户的权限信息、所有数据对象信息、表的约束条件、统计分析数据库的视图等。我们不能手工修改数据字典里的信息。很多时候,一般的ORACLE用户不知道如何有效地利用它。
dictionary 全部数据字典表的名称和解释,它有一个同义词dict
dict_column 全部数据字典表里字段名称和解释
如果我们想查询跟索引有关的数据字典时,可以用下面这条SQL语句:
SQL>select * from dictionary where instr(comments,'index')>0;
如果我们想知道user_indexes表各字段名称的详细含义,可以用下面这条SQL语句:
SQL>select column_name,comments from dict_columns where table_name='USER_INDEXES';
依此类推,就可以轻松知道数据字典的详细名称和解释,不用查看ORACLE的其它文档资料了。
下面按类别列出一些ORACLE用户常用数据字典的查询使用方法。
一、用户
查看当前用户的缺省表空间
SQL>select username,default_tablespace from user_users;
查看当前用户的角色
SQL>select * from user_role_privs;
查看当前用户的系统权限和表级权限
SQL>select * from user_sys_privs;
SQL>select * from user_tab_privs;
二、表
查看用户下所有的表
SQL>select * from user_tables;
查看名称包含log字符的表
SQL>select object_name,object_id from user_objects where instr(object_name,'LOG')>0;
查看某表的创建时间
SQL>select object_name,created from user_objects where object_name=upper('&table_name');
查看某表的大小
SQL>select sum(bytes)/(1024*1024) as size(M) from user_segments where segment_name=upper('&table_name');
查看放在ORACLE的内存区里的表
SQL>select table_name,cache from user_tables where instr(cache,'Y')>0;
三、索引
查看索引个数和类别
SQL>select index_name,index_type,table_name from user_indexes order by table_name;
查看索引被索引的字段
SQL>select * from user_ind_columns where index_name=upper('&index_name');
查看索引的大小
SQL>select sum(bytes)/(1024*1024) as size(M) from user_segments where segment_name=upper('&index_name');
四、序列号
查看序列号,last_number是当前值
SQL>select * from user_sequences;
五、视图
查看视图的名称
SQL>select view_name from user_views;
查看创建视图的select语句
SQL>select view_name,text_length from user_views;
SQL>set long 2000;说明:可以根据视图的text_length值设定set long 的大小
SQL>select text from user_views where view_name=upper('&view_name');
六、同义词
查看同义词的名称
SQL>select * from user_synonyms;
七、约束条件
查看某表的约束条件
SQL>select constraint_name, constraint_type,search_condition, r_constraint_name from user_constraints where table_name = upper('&table_name');
SQL>select c.constraint_name,c.constraint_type,cc.column_name
from user_constraints c,user_cons_columns cc
where c.owner = upper('&table_owner') and c.table_name = upper('&table_name')
and c.owner = cc.owner and c.constraint_name = cc.constraint_name
order by cc.position;
八、存储函数和过程
查看函数和过程的状态
SQL>select object_name,status from user_objects where object_type='FUNCTION';
SQL>select object_name,status from user_objects where object_type='PROCEDURE';
查看函数和过程的源代码
SQL>select text from all_source where owner=user and name=upper('&plsql_name');
九、触发器
查看触发器
set long 50000;
set heading off;
set pagesize 2000;
select
'create or replace trigger ' ||
trigger_name || '' || chr(10)||
decode( substr( trigger_type, 1, 1 ),
'A', 'AFTER', 'B', 'BEFORE', 'I', 'INSTEAD OF' ) ||
chr(10) ||
triggering_event || chr(10) ||
'ON ' || table_owner || '.' ||
table_name || '' || chr(10) ||
decode( instr( trigger_type, 'EACH ROW' ), 0, null,
'FOR EACH ROW' ) || chr(10) ,
trigger_body
from user_triggers;
星期四, 十月 12, 2006
上机必读 二级上机考试部分评分方法
自动评分系统有客观、公正的优点,但也有死板的缺点,要想得到比较好的分数,应当考虑到机器 的这一特点。实际考试还有人工复查一项,由省级考试部门负责进行.但是人工复查如何进行,我们完全不得而知。因此我们下面的所有内容均不含人工复查内容, 仅从考试系统本身来进行分析和说明。
我们从多次使用中摸索到的考生可能感兴趣的几点介绍如下:
1. DOS操作题的评分比较复杂,评分系统在几次考试中标准似乎有一些变化。
按系统的操作说明,只要命令正确即可得分,但实际情况并非如此。机器评分只根据结果,结果正确即得分,命令正确而结果不正确,不能得分。
要注意使用规定的命令。比如考试系统不允许使用 deltree 命令,您如果习惯于用该命令来删除子目录,考试时将无法使用。
本人曾做过试验,将结果做得完全符合要求,而不让考试系统看到我所作的事(比如使用另外的工具来做),结果照样得分;而使用正确的命令(即使与答案完全相同),而结果不正确(自然使用了"不正当"的方法),评分结果是不能得分。
2. 程序修改题的评分大约有下面一些特点:
有结果输出到文件中的,先检查结果文件。如果结果文件内容完全正确,给满分,并不再检查修改内容。
结果没有输出到文件,或结果文件不正确的,逐个错误语句进行检查。分数平均分配(如果共有两个错误,每修正一个得15分;共有三个错误,则每修正一个得10分……)。
检查标志为"***found***"。即机器死板地检查第X个"***found***"下面第N行(第X个错误语句应在的行)是否修改得和标准答案中的一个相同,相同则给分,否则不给分。
例如:您的修改是完全正确的,与标准答案也完全一致。但是您插入了一个空行在"***found***"和修改了的行之间,这显然不影响程序的正确性,但自动评分系统却会认定您"修改错误"。
更有甚者:如果您在程序的前面增加一个含有"***found***"的注释行,则不论您的程序修改得有多正确,评分系统会毫不留情地给您一个零分。
程序修改题中还应注意考虑原程序作者的思路,所作改动应尽量小。
这里有一个极端的例子:(1999年上半年二级BASIC)
'* 给定程序MODI1.BAS其功能是: 从键盘上每次输入两个100以下
'* 的正数分别赋给Y和Z(如不符合此条件的, 则重新输入),累加到累
'* 加器X中,直到X的值超过500为止。请找出程序中的错误,将程序调
'* 试出所需结果。
'* 注意: 不得增行或删行, 也不得更改程序的结构!
X = 0
DO
DO
t = 0
INPUT "Y,Z="; Y, Z
IF 0 < Y AND Y < 100 AND 0 < Z AND Z < 100 THEN
t = 2
ELSE
PRINT "Out of Range! Input again"
END IF
'**********found**********
LOOP WHILE t <> 1
X = X + Y + Z
'**********found**********
'WHILE X <> 500
PRINT "X="; X
END
这里共有两个错误:第一个为条件错,第二个语句和条件均有错。因此第一个错误可只改动条件为 t<>2 或 t=0,整个语句为
loop while t<>2 或者 loop while t=0
第二个错误可改为
LOOP WHILE X <= 500
总之,这里的思路就是用 DO ... LOOP WHILE <条件> 语句。
如果使用 do ... loop until <条件>,程序可以同样成立。如第一个错误改为
loop until t=2
运行结果完全相同。
但是自动评分系统会认为您"修改错误!"扣掉您应得的15分!!!
过去 C 语言的考试题目一般都出的较为严谨,很少有错误发生(但2002上半年的题虽然没发现什么严重错误,其质量实在不敢恭维)。但在2001年下半年中,仍有错判现象。举一例如下:
/*
给定程序MODI1.C中函数fun的功能是:先将在字符串s中的字符
按逆序存放到t串中,然后把s中的字符按正序连接到t串的后面。
例如:当s中的字符串为:"ABCDE"时,
则t中的字符串应为:"EDCBAABCDE"。
请改正程序中的错误,使它能得出正确的结果。
注意:不要改动main函数,不得增行或删行,也不得更改程序
的结构!
*/
#include <conio.h>
#include <stdio.h>
#include <string.h>
void fun (char *s, char *t)
{
/************found************/
int i,sl;
// int i;
/* 由于C语言对书写格式不作要求,本错误如改为 int i, 其结果显然也是
正确的。然而遗憾的是,自动批改系统此时会判错! */
sl = strlen(s);
for (i=0; i < sl; i++)
/************found************/
t[ i ] = s[sl-i-1];
// t[i] = s[sl-i];
for (i=0; i t[sl+i] = s[i];
t[2*sl] = '\0';
}
main()
{ char s[100], t[100];
clrscr();
printf("\nPlease enter string s:"); scanf("%s", s);
fun(s, t);
printf("The result is: %s\n", t);
}
有的考生怕修改过程中忘记了原来的内容,把原来的内容用注释的方法保留在程序中(应该说,这是一个好的习惯)。比如把上面的内容写成
t[ i ] = s[sl-i-1]; // t[ i ] = s[sl-i]; 或者
t[ i ] = s[sl-i-1]; /* t[ i ] = s[sl-i]; */
毫无疑问,这是正确的。但是评分系统竟然会判为"错误",不给分。考试系统会出现这种低级错误,倒是我以前未曾想到的,而且直至目前,这种错误仍未得到修正。
因此考生必须注意把错误的内容全部删除掉。
3. 编程题除去少部分类似填空或改错的BASIC程序外,均有结果输出到文件。自动评分时检查结果文件,如果结果文件内容正确,则给满分;如果没有结果文件 (即使程序是正确的,但没有运行),则得零分;如果应有若干个结果,则得分一般按结果数平均分配(比如应有两个结果,其中一个正确,另一个错误,则一般可 得40/2=20分)。在多数情况下,编程题往往不是满分就是零分。
要注意的是,在FoxBASE编程题中,如果要生成新的数据库,只要库结构正确,哪怕其他都是错误的,也可得10到20分(随题目不同而有所变化)。因此做不到编程题的考生不可轻言放弃。
部分BASIC的编程题实际上是填空题,因此是一个个空来改的,分数按空数平均分配。与程序修改题不同的是,它没有使用"***found***"标记,即使有添行等,也能正确进行评分。
有的编程题对考生提出了一些限制,比如不许使用某个或某类函数,或不许使用某种方法等。在评分时,却很可能没有考虑如何限制这一点。我曾试过专门用"不 许"的方法去做题,在结果正确的情况下,照样得满分。看来考试系统也是"撑死胆大的,饿死胆小的"。当然,本人绝不鼓励考生不按要求做。如果你看了我的贴 子,去做一个"胆大的",得不到分可不要找我负责哟!!!
首先,我讲一下考试评分系统的工作原理:
考试评分系统是不看源程序。而是对你的源程序编译时所产生的.obj文件和.exe文件进行测试。测试分为两部份组成:
一、运行:完成输入、输出。
二、评分:与预期的结果对比。
运行:
1、运行.exe文件(由你的源程序生成的),运行时,它会调用一个读函数,把in.dat文件里的测试数据读入主函数;一般二级有20组数据,三级、四是一大组数据(一篇英文、400个四位数、100个记录等)
2、调用你所编写的函数,把这些数代入。
3、调用写函数,把运行结果写入out.dat文件里。一般二级有20行结果(就是每组数据的运行结果),三级、四级有一大组结果(如一组字符流)或二到三个结果(如求平均值、公差、符合条件的数的个数等)
以上这三个过程二级里是调用NONO函数完成,三级、四级是分别调用ReadDat()和WriteDat()函数来完成。
评分:
运行test.exe文件,把out.dat文件里的内容与评分系统内的内容(预期结果)比较,在二级里,每对一行(就是这组数据的测试结果),给5分。
三级、四级的就要看具体情况给分了,如:字符流处理的,那只要错一个小部分就0分,因为字符流是连续的。如果是数值处理的(有2-3个结果),那就是 每对一个结果结20-30分,但错了一个答案就很难及格了,因为数值处理很多数是互相关联的,如:求平均值,如果符合条件的数的个数错了,那平均值也一定 是错的。还有那个100个记录的,那它是以那一行上的内容是不是与预期的一样,每对一行给1分。(因为这个测试数据刚好一百行),这就是三级或四级里有: 0<成绩<100 分的原故。(很多人都说三级四级上机成绩不是0分就是一百分,这个观点是错的)
以上文件名、函数名应以源程序调用时的名为准。
由上述可知:一个题如果通过编译、能运行就一定有分,那是错的,因为一个题,如果你一点都不做(放空),那是一定能通过编译和运行的。但这时,out.dat文件为空,如果你编写了程序,而运行的结果都是错的,那和空是一样的。这样是不能得分的。
还有是有人说我做了题,通过了编译,也出了"正确"结果,那为什么会不及格呢?是不是考试系统有问题,这个可能很小,一般是因为你的程序有问题,如以前考网上有一个题:
求一子字符串在主字符串出现的次数;
例如:子串:go
主串:good yjgocel liugo ygoygong
结果为: 5
以下是两个人的回复:
一、int fun(char *str,char *s)
{
int m=0;
char *p=s;
while(*str!='\0')
{ if(*str==*p)
{ str++;
p++;
} /*两字符相同就同时移动指针。*/
else
{p=s;
str++ ; /*不同只移动一个指针,并把另一指针指向初始位置 */
}
if(*p=='\0') /*如果是连续的同时移动到了后一个字符串尾,就计一次数 */
{ m++;
p=s ;
}
}
return m;
}
二、int fun(char *str,char *s)
{
int i,j,m=0;
for(i=0;i<strlen(str);) {
for(j=0;j<strlen(s);)
if(str[i]==s[j]) {
i++;
j++;
}
else {
i++;
break;
}
if(j==strlen(s))
m++;
}
return m;
}
其实这两个答案,对于上面的那个主串和子串也许是可以的,但,如果主串是aaa aa,子串是aa,那上面这两个程序就不行了,因为,aa在aaa aa里出现了3次,而不是2次,字符串是可以嵌套出现的,而测试数据里的数据一般什么情况都有,而象这种嵌套的多,这就是他认为自已程序是对的,而结果是 不及格的原故。
以上两位如果是考生的话,他们肯定会说他们的程序是绝对对的,是评分系统问题。
正确的应这样写:
fun(char *str,char *s)
{char str1[10]="";
int i,k=0;
for(;*str;str++)
{for(i=0;i<strlen(s);i++)
str1[i]=*(str+i);
if(!strcmp(str1,s)) k++;
}
return k;
}
下面我再讲一个测试上述程序的实例:
星期一, 十月 09, 2006
共享软件防破解的实用招法
1、检测主程序大小,防止破解补丁之类: Function TForm1.GesSelfSf: integer; var F: file of byte; begin Filemode:=0; Assignfile(F,'.\FileName.exe'); Reset(f); Result:=Filesize(F); Closefile(F); end; 2、检测创建日期和时间,让破解补丁实效: Function TForm1.FinDate:String; var t:TDate; begin ShortDateFormat:='yyyy-mm-dd'; t:=FileDateToDateTime(FileAge('FileName.exe')); Result:=DateToStr(t); end; 3、注册码加密函数嵌入数学函数,增加破解难度: (略) 4、必要时自己删除自己(主程序): procedure TForm1.Funll; var hModule:THandle; buff:array[0..255]of Char; hKernel32:THandle; pExitProcess,pDeleteFileA,pUnmapViewOfFileointer; begin hModule:=GetModuleHandle(nil); GetModuleFileName(hModule, buff, sizeof(buff)); CloseHandle(THandle(4)); hKernel32:=GetModuleHandle('KERNEL32'); pExitProcess:=GetProcAddress(hKernel32, 'ExitProcess'); pDeleteFileA:=GetProcAddress(hKernel32, 'DeleteFileA'); pUnmapViewOfFile:=GetProcAddress(hKernel32, 'UnmapViewOfFile'); asm LEA EAX, buff PUSH 0 PUSH 0 PUSH EAX PUSH pExitProcess PUSH hModule PUSH pDeleteFileA PUSH pUnmapViewOfFile RET end; begin Funll; end; end; 具体怎么使用,那要看你自己的意愿了和需要了。反正我是这样做的,我的软件ADSL拨号计时器只在很早版本上出过注册机,后来的v3.70出过破解补丁 ——其实只是破掉了启动时提示注册的对话框,实质上根本没破解。用了上述的着法以后,到现在的v5.28版本,再没有过什么破解补丁或注册机。 如果现在的v5.28版本谁能破解,将立即公布程序源码。 附:注册机破解法的原理以及应对方法 认识注册机破解法 顾名思义,写注册机来破解软件注册的方法,就是模仿你的注册码生成算法或者逆向注 册码验证算法而写出来的和你一模一样的注册机。如果被写出注册机,你的软件只好免费了。或者你必须更换算法,但以前注过册的合法用户都得被迫更换注册码了。 Cracker要写注册机必须详细研究你软件的验证模块,这必须先将你的软件脱壳,再反汇编或者用调试器跟踪。市面上许多加壳和保护软件都吹嘘不可能被 脱壳,但到目前为止没有一个软件兑现了自己的诺言。由于CPU最终执行的都是有效指令,所以等你的程序自解压完成后再从内存中Dump出来就可以实现脱 壳。因此不要在壳上面花很多功夫,因为没有这个必要。 第一招:制造假相 反汇编和调试器跟踪都是不可能防止的,因为所有的Win32程序都必须通过API来调用Windows系统中的关键DLL的(如Kernel32.dll、GDI32.dll等),然而API是可以Hook的。我们只能从自己的代码着手来保护我们的劳动果实了。 为了自己调试和以后维护的方便,我们一般采用有意义的名字给我们的函数命名,可这给了Cracker可乘之机。例如这样的函数是什么意思大家应该一目了 然吧?IsRegistered(),IsLicensed(),LicenseVerify(),CheckReg()……这样Cracker就可以轻 松地从数千个函数中找到他的目标——你的注册码校验函数!而且破解Delphi编写的软件还有一件TMG小组的破解利器——DeDe。它可以轻松地看到你 软件里的Form、Unit和函数名,还可以反汇编一部分代码,更可以和Win32DASM合作反汇编更多的代码,对Delphi编出的程序威胁极大。 为了不给Cracker创造温馨舒适的破解环境,要故意混乱(Obfuscate)我们的代码,将软件中所有的函数名全部替换成随机 生成的函数名。例如Func_3dfsa_fs32zlfv这个函数是什么意思?恐怕只有天知道了。网上有现成的代码混乱器,按你使用的编程语言的种 类可以找到一些。但要注意,只有当你要发布软件时才使用它,而且一定注意备份源代码。否则,当你看不懂你自己的代码时就着急了:) 第二招:用公匙,并改名 另外,一定要使用公开密匙算法保护你的软件。RSA、DSA和El Gamal之类的算法都可以从网上找到。但注意:将你算法单元中所有涉及到算法名称的字符串全部改名。避免被Cracker发现你用的算法而模仿写出注册 机来!你还可以张冠李戴,明明用的DSA,将名字全部替换成RSA。 其它算法,如对称算法和Hash算法也要注意改名,否则这样: EncryptedCode = Blowfish(MD5(UserName),MD5(Key)); //你的加密算法,使用了Blowfish(对称算法)和MD5(Hash算法) 虽然那些Cracker不了解Blowfish和MD5算法的原理,也不会逆向推测它们,但他们了解你的校验算法的流程和算法名,便可马上从网上找到类似的Blowfish和MD5算法包,从而模拟你的软件仿造出注册机。 如果你用不常见的,算法如Skipjack(NASA美国航天局标准算法)、LOKI、3-WAY、Safer之类不出名但保密程度很高的算法,并且全部改名,这样就会伤透他们脑筋了。 当然,最好把Hash算法也全部改名,会给他们制造更多的困难。但注意,MD5和SHA之类的Hash初始值会被Cracker从内存中找到,这样他就 知道你用的Hash了。所以建议同时使用MD5的变形算法Ripe-MD(RMD)128或160或其它的Hash,如Tiger、Haval等算法。 第三招:阻止别人调试 还有一点,调试器对我们的威胁很大,我们不会让Cracker们舒舒服服地使用SoftICE、TRW或OllyDbg来调试我们的程序。除了常用的MeItICE方法外,这里我给一个笔者写的方法: {检查自己的进程的父进程是否为Explorer.exe,否则是被调试器加载了} {不过注意,控制台程序的父进程在WinNT下是Cmd.exe!} {注意加载TlHelp32.pas单元} procedure CheckParentProc; var //检查自己的进程的父进程 Pn: TProcesseNtry32; sHandle:THandle; H,ExplProc,ParentProc:Hwnd; Found:Boolean; Buffer:array[0..1023]of Char; Path:string; begin H:= 0; ExplProc:= 0; ParentProc:= 0; //得到Windows的目录 SetString(Path,Buffer) GetWindowsDirectory(Buffer,Sizeof(Buffer)- 1)); Path:= UpperCase(Path)+ '\EX PLORER.EXE';//得到Explorer的路径 //得到所有进程的列表快照 sHandle:= CreateToolHelp32Snap Shot(TH32CS_SNAPALL,0); Found:= Process32First(sHandle,Pn);//查找进程 while Found do //遍历所有进程 begin if Pn.szExeFile = ParamStr(0)then //自己的进程 begin ParentProc:= Pn.th32ParentProcessID://得到父进程的进程ID //父进程的句柄 H:= OpenProcess(PRO CESS_ALL_ACCESS,True,Pn.th32Parent ProcessID); end else if UpperCase(Pn.szExeFile)= Path then ExplProc:= Pn.th32ProcessID;//Ex plorer的PID Found:= Process32Next(sHandle,Pn);//查找下一个 end; //父进程不是Explorer,是调试器…… if ParentProc <> ExplProc then begin TerminateProcess(H,0);//杀之!除之而后快也! :) //你还可以加上其它什么死机代码来消遣消遣这位可爱的Cracker:) end� end � 你可以在Delphi或者VC中试试,这样可以把Delphi和VC杀掉了,因为你现在用的是Delphi和VC的内置调试器来运行你的程序。调试的时候你还是把它的注释删掉吧,发布时别忘记激活哟! 第四招:保护字符串 最后一个问题,这也是一个非常重要的问题:保护你的字符串!字符串在注册模块中非常重要!当一个富有经验的Cracker破解你的软件时,首先做的就是 窃取你的字符串。比如他会输入错误的注册码,得到你关于错误注册码的提示,通常是"无效的注册码,请重新输入!"或者"Invalid key(please input again)"等等,然后用OllyDbg进行断点调试或者用WinDASM、IDA Pro等静态分析工具在被他脱壳后的程序中查找那个字符串,找到后进行分析。因此,请一定加密你的字符串! 使用时再临时解密出来,而且要尽量少使用消息提示框,避免被Cracker找到漏洞。加密字符串不需要太复杂的算法,随便找一个快速的对称算法就可以了。 最后提醒大家一句,不要在加密上花太多的功夫!你应该把更多的时间和精力都用来完善你的软件,这样会更合算。借用一位前辈的话来忠告 大家吧:花点时间考虑你自己的软件,看看它是否值得保护?如果没人用你的软件,保护也就没有意义了,不要过高估计你的软件"对世界的重要性 | |||||
|
星期日, 九月 10, 2006
oracle 942错误
==============================
前日晚上准备对刚刚启用的Unix环境Oracle数据库做一次Exp逻辑备份,报如下错误:
ORA-00942: table or view does not exist
EXP-00000: Export terminated unsuccessfully
SQL>startup migrate;
SQL>@?/rdbms/admin/catpatch.sql
========================
XP-00056: 遇到 ORACLE 错误 942
ORA-00942: 表或视图不存在
EXP-00000: 导出终止失败
解决办法:报此错误并不是因为你的权限不够,也不是因为你的命令有误,而是ORACLE本身的问题,是由于你的客户端版本低于服务器端的版本造成的。最好的办法就是装一个与服务器端版本相同客户端。要不就到服务器端去导吧。
星期五, 九月 08, 2006
在Oracle中存取BLOB对象实现文件的上传和下载
存取BLOB出现这么多问题,我认为大半是由数据库开发商、应用服务器商在JDBC驱动上的不兼容性带来的。而实际应用中,每个人的开发运行环境不同,使得某个网友的solution没有办法在别人的应用中重现,以至于骂声一片。至于为什么会不兼容、有哪些问题,我没有时间去弄清,这里只说说我们怎样解决了问题的。
基于上述原因,先列出我们的开发环境,免得有人配不出来,招人唾骂。
数据库 Oracle 9i
应用服务器 BEA Weblogic 8.11
开发工具 JBuilder X
在JSP实现文件Upload/Download可以分成这样几块 :文件提交到形成InputSteam;InputSteam以BLOB格式入库;数据从库中读出为InputSteam;InputStream输出到页面形成下载文件。先说BLOB吧。
1. BLOB入库
(1) 直接获得数据库连接的情况
这是Oracle提供的标准方式,先插入一个空BLOB对象,然后Update这个空对象。代码如下:
//得到数据库连接(驱动包是weblogic的,没有下载任何新版本)
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:testdb", "test", "test");
//处理事务
con.setAutoCommit(false);
Statement st = con.createStatement();
//插入一个空对象
st.executeUpdate("insert into BLOBIMG values(103,empty_blob())");
//用for update方式锁定数据行
ResultSet rs = st.executeQuery(
"select contents from BLOBIMG where id=103 for update");
if (rs.next()) {
//得到java.sql.Blob对象,然后Cast为oracle.sql.BLOB
oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob(1).;
//到数据库的输出流
OutputStream outStream = blob.getBinaryOutputStream();
//这里用一个文件模拟输入流
File file = new File("d:\\proxy.txt");
InputStream fin = new FileInputStream(file);
//将输入流写到输出流
byte[] b = new byte[blob.getBufferSize()];
int len = 0;
while ( (len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
//blob.putBytes(1,b);
}
//依次关闭(注意顺序)
fin.close();
outStream.flush();
outStream.close();
con.commit();
con.close();
(2) 通过JNDI获得数据库连接
在Weblogic中配置到Oracle的JDBC Connection Pool和DataSource,绑定到Context中,假定绑定名为”orads”。
为了得到数据库连接,做一个连接工厂,主要代码如下:
Context context = new InitialContext();
ds = (DataSource) context.lookup("orads");
return ds.getConnection();
以下是BLOB写入数据库的代码:
Connection con = ConnectionFactory.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
st.executeUpdate("insert into BLOBIMG values(103,empty_blob())");
ResultSet rs = st.executeQuery(
"select contents from BLOBIMG where id=103 for update");
if (rs.next()) {
//上面代码不变
//这里不能用oracle.sql.BLOB,会报ClassCast 异常
weblogic.jdbc.vendor.oracle.OracleThinBlobblob = (weblogic.jdbc.vendor.oracle.OracleThinBlob) rs.getBlob(1);
//以后代码也不变
OutputStream outStream = blob.getBinaryOutputStream();
File file = new File("d:\\proxy.txt");
InputStream fin = new FileInputStream(file);
byte[] b = new byte[blob.getBufferSize()];
int len = 0;
while ( (len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
}
fin.close();
outStream.flush();
outStream.close();
con.commit();
con.close();
2. BLOB出库
从数据库中读出BLOB数据没有上述由于连接池的不同带来的差异,只需要J2SE的标准类java.sql.Blob就可以取得输出流(注意区别java.sql.Blob和oracle.sql.BLOB)。代码如下:
Connection con = ConnectionFactory.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
//这里的SQL语句不再需要”for update”
ResultSet rs = st.executeQuery(
"select contents from BLOBIMG where id=103 ");
if (rs.next()) {
java.sql.Blob blob = rs.getBlob(1);
InputStream ins = blob.getBinaryStream();
//用文件模拟输出流
File file = new File("d:\\output.txt");
OutputStream fout = new FileOutputStream(file);
//下面将BLOB数据写入文件
byte[] b = new byte[1024];
int len = 0;
while ( (len = ins.read(b)) != -1) {
fout.write(b, 0, len);
}
//依次关闭
fout.close();
ins.close();
con.commit();
con.close();
3. 从JSP页面提交文件到数据库
(1) 提交页面的代码如下:
<form action="handle.jsp" enctype="multipart/form-data" method="post" >
<input type="hidden" name="id" value="103"/>
<input type="file" name="fileToUpload">
<input type="submit" value="Upload">
</form>
(2) 由于JSP没有提供文件上传的处理能力,只有使用第三方的开发包。网络上开源的包有很多,我们这里选择Apache Jakarta的FileUpload,在http://jakarta.apache.org/commons/fileupload/index.html 可以得到下载包和完整的API文档。法奥为adajspException
处理页面(handle.jsp)的代码如下
<%
boolean isMultipart = FileUpload.isMultipartContent(request);
if (isMultipart) {
// 建立一个新的Upload对象
DiskFileUpload upload = new DiskFileUpload();
// 设置上载文件的参数
//upload.setSizeThreshold(yourMaxMemorySize);
//upload.setSizeMax(yourMaxRequestSize);
String rootPath = getServletConfig().getServletContext().getRealPath("/") ;
upload.setRepositoryPath(rootPath+\\uploads);
// 分析request中的传来的文件流,返回Item的集合,
// 轮询Items,如果不是表单域,就是一个文件对象。
List items = upload.parseRequest(request);
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
//如果是文件对象
if (!item.isFormField()) {
//如果是文本文件,可以直接显示
//out.println(item.getString());
//将上载的文件写到服务器的\WEB-INF\webstart\下,文件名为test.txt
//File uploadedFile = new File(rootPath+"\\uploads\\test.txt");
//item.write(uploadedFile);
//下面的代码是将文件入库(略):
//注意输入流的获取
…
InputStream uploadedStream = item.getInputStream();
…
}
//否则是普通表单
else{
out.println("FieldName: " + item.getFieldName()+"<br>");
out.println("Value: "+item.getString()+"<br>"); }
}
}
%>
4. 从数据库读取BLOB然后保存到客户端磁盘上
这段代码有点诡异,执行后将会弹出文件保存对话窗口,将BLOB数据读出保存到本地文件。全文列出如下:
<%@ page contentType="text/html; charset=GBK" import="java.io.*" import="java.sql.*" import="test.global.ConnectionFactory"%><%
Connection con = ConnectionFactory.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(
"select contents from BLOBIMG where id=103 ");
if (rs.next()) {
Blob blob = rs.getBlob(1);
InputStream ins = blob.getBinaryStream();
response.setContentType("application/unknown");
response.addHeader("Content-Disposition", "attachment; filename="+"output.txt");
OutputStream outStream = response.getOutputStream();
byte[] bytes = new byte[1024];
int len = 0;
while ((len=ins.read(bytes))!=-1) {
outStream.write(bytes,0,len);
}
ins.close();
outStream.close();
outStream = null;
con.commit();
con.close();
}
%>
注意,在<% … … %>之外,绝对不能有任何字符,空格或回车都不行,不然会导致outputStream出错,对非ASCII输出文件来说就是格式错误不可读。
在Oracle中存取BLOB对象实现文件的上传和下载_站长技术站 -
最近做一个J2EE项目,需要在JSP页面实现对文件的上传和下载。很早以前就知道JDBC支持大对象(LOB)的存取,以为很容易,做起来才发现问题多多,读了一大堆文章,反而没有什么头绪了。正如一位网友文章所讲:“…网络上的教程99%都是行不通的,连SUN自己的文档都一直错误……”,实际情况大致如此了。
存取BLOB出现这么多问题,我认为大半是由数据库开发商、应用服务器商在JDBC驱动上的不兼容性带来的。而实际应用中,每个人的开发运行环境不同,使得某个网友的solution没有办法在别人的应用中重现,以至于骂声一片。至于为什么会不兼容、有哪些问题,我没有时间去弄清,这里只说说我们怎样解决了问题的。
基于上述原因,先列出我们的开发环境,免得有人配不出来,招人唾骂。
数据库 Oracle 9i
应用服务器 BEA Weblogic 8.11
开发工具 JBuilder X
在JSP实现文件Upload/Download可以分成这样几块 :文件提交到形成InputSteam;InputSteam以BLOB格式入库;数据从库中读出为InputSteam;InputStream输出到页面形成下载文件。先说BLOB吧。
1. BLOB入库
(1) 直接获得数据库连接的情况
这是Oracle提供的标准方式,先插入一个空BLOB对象,然后Update这个空对象。代码如下:
//得到数据库连接(驱动包是weblogic的,没有下载任何新版本)
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:testdb", "test", "test");
//处理事务
con.setAutoCommit(false);
Statement st = con.createStatement();
//插入一个空对象
st.executeUpdate("insert into BLOBIMG values(103,empty_blob())");
//用for update方式锁定数据行
ResultSet rs = st.executeQuery(
"select contents from BLOBIMG where id=103 for update");
if (rs.next()) {
//得到java.sql.Blob对象,然后Cast为oracle.sql.BLOB
oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob(1).;
//到数据库的输出流
OutputStream outStream = blob.getBinaryOutputStream();
//这里用一个文件模拟输入流
File file = new File("d:\\proxy.txt");
InputStream fin = new FileInputStream(file);
//将输入流写到输出流
byte[] b = new byte[blob.getBufferSize()];
int len = 0;
while ( (len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
//blob.putBytes(1,b);
}
//依次关闭(注意顺序)
fin.close();
outStream.flush();
outStream.close();
con.commit();
con.close();
(2) 通过JNDI获得数据库连接
在Weblogic中配置到Oracle的JDBC Connection Pool和DataSource,绑定到Context中,假定绑定名为”orads”。
为了得到数据库连接,做一个连接工厂,主要代码如下:
Context context = new InitialContext();
ds = (DataSource) context.lookup("orads");
return ds.getConnection();
以下是BLOB写入数据库的代码:
Connection con = ConnectionFactory.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
st.executeUpdate("insert into BLOBIMG values(103,empty_blob())");
ResultSet rs = st.executeQuery(
"select contents from BLOBIMG where id=103 for update");
if (rs.next()) {
//上面代码不变
//这里不能用oracle.sql.BLOB,会报ClassCast 异常
weblogic.jdbc.vendor.oracle.OracleThinBlobblob = (weblogic.jdbc.vendor.oracle.OracleThinBlob) rs.getBlob(1);
//以后代码也不变
OutputStream outStream = blob.getBinaryOutputStream();
File file = new File("d:\\proxy.txt");
InputStream fin = new FileInputStream(file);
byte[] b = new byte[blob.getBufferSize()];
int len = 0;
while ( (len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
}
fin.close();
outStream.flush();
outStream.close();
con.commit();
con.close();
2. BLOB出库
从数据库中读出BLOB数据没有上述由于连接池的不同带来的差异,只需要J2SE的标准类java.sql.Blob就可以取得输出流(注意区别java.sql.Blob和oracle.sql.BLOB)。代码如下:
Connection con = ConnectionFactory.getConnection();
con.setAutoCommit(false);
Statement st = con.createStatement();
//这里的SQL语句不再需要”for update”
ResultSet rs = st.executeQuery(
"select contents from BLOBIMG where id=103 ");
if (rs.next()) {
java.sql.Blob blob = rs.getBlob(1);
InputStream ins = blob.getBinaryStream();
//用文件模拟输出流
File file = new File("d:\\output.txt");
OutputStream fout = new FileOutputStream(file);
//下面将BLOB数据写入文件
byte[] b = new byte[1024];
int len = 0;
while ( (len = ins.read(b)) != -1) {
fout.write(b, 0, len);
}
//依次关闭
fout.close();
ins.close();
con.commit();
con.close();
3. 从JSP页面提交文件到数据库
(1) 提交页面的代码如下:
name="fileToUpload">
value="Upload">
(2) 由于JSP没有提供文件上传的处理能力,只有使用第三方的开发包。网络上开源的包有很多,我们这里选择Apache Jakarta的FileUpload,在http://jakarta.apache.org/commons/fileupload/index.html 可以得到下载包和完整的API文档。法奥为adajspException
处理页面(handle.jsp)的代码如下
<%
boolean isMultipart = FileUpload.isMultipartContent(request);
if (isMultipart) {
// 建立一个新的Upload对象
DiskFileUpload upload = new DiskFileUpload();
// 设置上载文件的参数