|
2006年4月2日
/Files/rttw/Excel.zip
本程序用來將多個excel 報表合并成一個文件,取第一個文件的前n 行做為報表的題頭,n 可自定義。
1.支持直接添加多個文件
2.支持直接添加某個文件夾下面的所有excel文件
3 支持直接將excel文件拖放到程序界面
4.可以單選或多選記錄然后用右鍵刪除
5.可以定義excel表頭記錄數
6.本版本暫時只支持合并Excel文件的第一個sheet
7.雙擊某條記錄可直接刪除
8.開發環境 VC6+OFFICE2007,其他版本OFFICE有可能不兼容
北京寄來的件,已經第四天了,打電話到廣州中轉,說還沒到廣州,竟然讓我自己打電話到北京去問.再說了兩句竟然掛了我的電話.簡直是垃圾啊.客戶打電話上來的有問題的件應該是快遞公司內部處理解決吧,竟然讓客戶自己去跟蹤??奉勸大家以后千萬不要用申通快遞,切記且記
[root@linux-test188 ~]# cdrecord -scanbus Cdrecord-Clone 2.01-dvd (i686-pc-linux-gnu) Copyright (C) 1995-2004 J枚rg Schilling Note: This version is an unofficial (modified) version with DVD support Note: and therefore may have bugs that are not present in the original. Note: Please send bug reports or support requests to http://bugzilla.redhat.com/bugzilla Note: The author of cdrecord should not be bothered with problems in this version. scsidev: 'ATA' devname: 'ATA' scsibus: -2 target: -2 lun: -2 Linux sg driver version: 3.5.27 Using libscg version 'schily-0.8'. cdrecord: Warning: using inofficial libscg transport code version (schily - Red Hat-scsi-linux-sg.c-1.83-RH '@(#)scsi-linux-sg.c???? 1.83 04/05/20 Copyright 1997 J. Schilling'). scsibus1: ??????? 1,0,0?? 100) 'HL-DT-ST' 'CD-RW GCE-8400B ' '1.02' Removable CD-ROM ??????? 1,1,0?? 101) * ??????? 1,2,0?? 102) * ??????? 1,3,0?? 103) * ??????? 1,4,0?? 104) * ??????? 1,5,0?? 105) * ??????? 1,6,0?? 106) * ??????? 1,7,0?? 107) * [root@linux-test188 ~]# cdrecord -v speed=8 dev=1,0,0 test.iso
[root@linux-test188 ~]# mkisofs -r -o cd.iso -m temp ./tempfiles
select * from a,b where a.id=b.id(+); select * from a left join b on a.id=b.id;
很多資料說上面兩個語句的效果是一樣的,實際上今天經過測試發現兩者的執行計劃大不相同(查詢結果是一樣的); 至于為什么會這樣,暫時沒有深究,手頭的一個例子表明按照第一種寫法的效率會高,或許其他的例子結果不一樣,等有時間的時候再測試一下吧.
同樣的一條語句,一條是在pl/sql里面組裝成sql之后提交執行,另外一條是用pro*c程序后綁定執行,沒想到執行策略和效率天差地別。看來做什么事都不能想當然,要細心學習才行。保留此條語句以做紀念:
select * ? from (select /*+ INDEX(A IDX_HISBUFAREJOUR_ACCOUNT) +*/ ???????? a.*, f.sort_name ????????? from hs_his.hisbufarejour a, hs_fund.faresort f ???????? where (((((((a.fare_sort = f.fare_sort and a.client_id = :b0) and ?????????????? (:b1 = 0 or a.fund_account = :b2)) and ?????????????? a.init_date >= :b3) and a.init_date <= :b4) and ?????????????? (trim(:b5) is null or ?????????????? instr(((',' || :b6) || ','), ???????????????????????? ((',' || a.exchange_type) || ',')) > 0)) and ?????????????? (trim(:b7) is null or ?????????????? instr(((',' || :b8) || ','), ??????????????????????? ((',' || a.money_type) || ',')) > 0)) and ?????????????? (trim(:b9) is null or a.position_str > :b10)) ???????? order by a.position_str) ?where rownum <= :b11
?????? b0:130330000516 b1:595995 b2:595995 b3:20061221 b4:20061221 b5:1 b6:1 b7:2 b8:2 b9: b10: b11:30
vc的對話框中,如果直接用picturebox作為對話框的背景,則其他控件會被擋住。經過高手指點,重載了WM_ERASEBKGND消息處理函數,很少的解決了這個問題。而且按照這個思路,可以很方便的為dialog增加動態的skin:
聲明消息處理函數:
?// Generated message map functions ?//{{AFX_MSG(Input) ?afx_msg BOOL OnEraseBkgnd(CDC* pDC); ?afx_msg void OnButtonOk(); ?afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); ?afx_msg void OnPaint(); ?//}}AFX_MSG ?DECLARE_MESSAGE_MAP()
聲明消息循環: BEGIN_MESSAGE_MAP(Input, CDialog) ?//{{AFX_MSG_MAP(Input) ?ON_BN_CLICKED(IDC_BUTTON_OK, OnButtonOk) ?ON_WM_LBUTTONDBLCLK() ?ON_WM_PAINT() ?ON_WM_ERASEBKGND() ?//}}AFX_MSG_MAP END_MESSAGE_MAP()
實現: BOOL Input::OnEraseBkgnd(CDC* pDC) {
?if(m_hBmp) ?{ ??BITMAP bm; ??GetObject(m_hBmp,sizeof(bm),&bm); ??HDC hMemdc=CreateCompatibleDC(pDC->m_hDC); ??if(hMemdc) ??{ ???? HBITMAP hOldBmp=(HBITMAP)SelectObject(hMemdc,m_hBmp); ???? if(hOldBmp) ???? { ????? BitBlt(pDC->m_hDC,0,0,bm.bmWidth,bm.bmHeight,hMemdc,0,0,SRCCOPY); ????? SelectObject(hMemdc,hOldBmp); ????? DeleteDC(hMemdc); ????? DeleteObject(hOldBmp); ????? return TRUE; ???? } ???? else ??? DeleteDC(hMemdc); ??} ?} ?return CDialog::OnEraseBkgnd(pDC); }
??????今天系統莫明其妙的故障,以前用的好好的客戶信息匯總統計突然出現異常,查看日志顯示oracle的sql語句異常. ??????跟蹤調試后臺發現問題出現在sprintf語句上面,sql預定義 char[8000],然后用sprintf來格式化,結果當語句的數據超過8000的時候就不能正常處理了. ???? google了一下:
眾所周知,sprintf不能檢查目標字符串的長度,可能造成眾多安全問題,所以都會推薦使用snprintf.
snprintf(_snprintf)的聲明是這樣的
int _snprintf( ?? char *buffer, ?? size_t count, ?? const char *format [, ????? argument] ... );
If len < count, then len characters are stored in buffer, a null-terminator is appended, and len is returned.
If len = count, then len characters are stored in buffer, no null-terminator is appended, and len is returned.
If len > count, then count characters are stored in buffer, no null-terminator is appended, and a negative value is returned.
最常見的錯誤用法有: 1. char sa[256]={0}; _snprintf(sa,sizeof(sa),"%s",sb); //錯誤原因:當sb的長度>=256的時候,sa將沒有'\0'結尾
2. char sa[256]; _snprintf(sa,sizeof(sa)-1,"%s",sb); //錯誤原因:當sb的長度>=255的時候,sa將沒有'\0'結尾,忘記給sa初始化
3. char sa[256]; _snprintf(sa,sizeof(sa)-1,"%s",sb); sa[sizeof(sa)]=0; //錯誤原因:最后一行數組越界
正確的用法 1. //推薦用法 char sa[256]; sa[sizeof(sa)-1]=0; _snprintf(sa,sizeof(sa),"%s",sb); if(sa[sizeof(sa)-1]!=0) { ?? printf("warning:string will be truncated"); ?? sa[sizeof(sa)-1]=0; }
2. char sa[256]={0}; int result = _snprintf(sa,sizeof(sa),"%s",sb); if(result==sizeof(sa) || result<0) { ??? printf("warning:sting will be truncated"); ?? sa[sizeof(sa)-1]=0; }
首先定義消息:
#define POST_DATA_START WM_USER+1 #define POST_DATA_END WM_USER+2 #define RECEIVE_DATA_START WM_USER+3 #define RECEIVE_DATA_END WM_USER+4 #define THREAD_START WM_USER+5 #define THREAD_END WM_USER+6 #define TASK_START WM_USER+7 #define TASK_END WM_USER+8 #define TASK_IDEL WM_USER+9
聲明處理函數 ?//{{AFX_MSG(CMyDlg) ?........ ?afx_msg void OnPostDataStart(WPARAM wParam, LPARAM lParam); ?afx_msg void OnPostDataEnd(WPARAM wParam, LPARAM lParam); ?afx_msg void OnReceiveDataStart(WPARAM wParam, LPARAM lParam); ?afx_msg void OnReceiveDataEnd(WPARAM wParam, LPARAM lParam); ?afx_msg void OnThreadStart(WPARAM wParam, LPARAM lParam); ?afx_msg void OnThreadEnd(WPARAM wParam, LPARAM lParam); ?afx_msg void OnTaskStart(WPARAM wParam, LPARAM lParam); ?afx_msg void OnTaskEnd(WPARAM wParam, LPARAM lParam); ?afx_msg void OnTaskIdel(WPARAM wParam, LPARAM lParam); ?//}}AFX_MSG ?DECLARE_MESSAGE_MAP() 注意所有函數聲明都要在 DECLARE_MESSAGE_MAP()前面
綁定消息和處理函數: BEGIN_MESSAGE_MAP(CMyDlg, CDialog) //{{AFX_MSG_MAP(CMyDlg) ON_MESSAGE(POST_DATA_START,OnPostDataStart) ON_MESSAGE(POST_DATA_END,OnPostDataEnd) ON_MESSAGE(POST_DATA_START,OnReceiveDataStart) ON_MESSAGE(RECEIVE_DATA_START,OnReceiveDataEnd) ON_MESSAGE(RECEIVE_DATA_END,OnThreadStart) ON_MESSAGE(THREAD_START,OnThreadEnd) ON_MESSAGE(TASK_END,OnTaskStart) ON_MESSAGE(TASK_START,OnTaskEnd) ON_MESSAGE(TASK_IDEL,OnTaskIdel)
//}}AFX_MSG_MAP END_MESSAGE_MAP()
當然最后還要完成函數實體
新裝的redhat linux,先增加系統用戶,然后
cat /etc/passwd|mksmbpasswd.sh > /etc/samba/smbpasswd 此命令根據系統的用戶文件 /etc/passwd自動生成了samba的用戶文件
smbpasswd? 修改用戶登陸samba的密碼
service smb restart 重啟samba服務
通過以上三步可以用os用戶登陸samba(密碼不是os的,可以單獨改),登陸后默認可以訪問該用戶在os的home目錄
補充: 修改 [global]下面的 security = user為security = share可以允許匿名登陸,登陸后可以訪問的內容可以用guest ok = yes 來標記
??? 為了工作需要不得不開始學習delphi。 ??? 看了一個星期的代碼和資料,由于有C++和java的基礎,所以看起來并不算費力。 ??? 主觀上覺得delphi的設計理念更簡單和容易理解,程序架構比較清晰,但是也有比較別扭的地方,覺得pascal的條條框框太多,不想C++和Java那樣隨心所欲。 ??? delphi有相對非常豐富的lib可以使用,可以用來快速的開發解決一些簡單的問題,尤其是對數據庫的支持比vc/java要方便得多(只是說方便,不是強大),還是值得一學的。
我所向往的, 是最簡單的、平凡的幸福, 不用呼吸渾濁的空氣, 不用厭煩吵鬧擁擠的交通和人群.
我只希望, 每天早上醒來, 可以看到從窗口射進來的第一縷陽光, 照著你的臉
以前寫jdbc相關的程序一直沒有注意到 statement/resultset 是需要關閉的,直到最近在一個系統里面發現了這個“maximum open cursors exceeded”的異常。 通過查找相關文檔,原來一個statement通常會對應一個db cursor,如果大量使用statement而不關閉就會引起此異常,關閉的代碼很簡單:
if(rs!=null)?? //ResultSet ????try { ?????rs.close(); ????} catch (SQLException e1) { ?????logger.error(e1.getMessage());
????}
???if(pst!=null)? //PreparedStatement?? ????try { ?????pst.close(); ????} catch (SQLException e1) { ?????logger.error(e1.getMessage()); ????}
有二個和尚住在隔壁,所謂隔壁是隔壁那座山,他們分別住在相鄰的二座山上的廟里。這 二座山之間有一條溪,於是這二個和尚每天都會在同一時間下山去溪邊挑水,久而久之他 們便成為好朋友了。就這樣時間在每天挑水中不知不覺已經過了五年,突然有一天左邊這 座山的和尚沒有下山挑水,右邊那座山的和尚心想:「他大概睡過頭了。」便不以為意。 哪知第二天左邊這座山的和尚還是沒有下山挑水,第三天也一樣,過了一個星期還是一樣 ,直到過了一個月右邊那座山的和尚終於受不了了,他心想:「我的朋友可能生病了,我 要過去拜訪他,看看能幫上什么忙。」於是他便爬上了左邊這座山,去探望他的老朋友。
等他到達左邊這座山的廟,看到他的老友之後大吃一驚,因為他的老友正在廟前打太 極拳,一點也不像一個月沒喝水的人。他很好奇地問:「你已經一個月沒有下山挑水了, 難道你可以不用喝水嗎?」 左邊這座山的和尚說:「來來來,我帶你去看。」於是他帶著右邊那座山的和尚走到 廟的後院,指著一口井說:「這五年來,我每天做完功課後都會抽空挖這口井,即使有時 很忙,能挖多少就算多少。如今終於讓我挖出井水,我就不必再下山挑水,我可以有更多 時間練我喜歡的太極拳。」 我們在公司領的薪水股票再多,那是挑水。若我們只是把握下班後的時間挖一口屬於 自己的井,未來當我們年紀大了,體力拼不過年輕人了,我們還是有水喝,而且喝得很悠 閑。
時間管理專家為一群商學院學生講課。他現場做了演示,給學生們留下一生難以磨滅的印象。
?
??? 站在那些高智商、高學歷的學生前面,他說:"我們來個小測驗",拿出一個一加侖的廣口瓶放在他面前的桌上。 隨后,他取出一堆拳頭大小的石塊,仔細地一塊塊放進玻璃瓶里。直到石塊高出瓶口,再也放不下了,他問道:"瓶子滿了嗎?"所有學生應道:"滿了"。時間管理專家反問:"真的?"他伸手從桌下拿出一桶礫石,倒了一些進去,并敲擊玻璃瓶壁使礫石填滿下面石塊的間隙。"現在瓶子滿了嗎?"他第二次問道。
?
??? 但這一次學生有些明白了,"可能還沒有",一位學生應道。"很好!"專家說。他伸手從桌下拿出一桶沙子,開始慢慢倒進玻璃瓶。沙子填滿了石塊和礫石的所有間隙。他又一次問學生:"瓶子滿了嗎?""沒滿!"學生們大聲說。他再一次說:"很好。"然后他拿過一壺水倒進玻璃瓶直到水面與瓶口平。抬頭看著學生,問道:"這個例子說明什么?" 一個心急的學生舉手發言:"它告訴我們:無論你的時間表多么緊湊,如果你確實努力,你可以做更多的事!"。"不!",時間管理專家說,"那不是它真正的意思。這個例子告訴我們:
??? 如果你不是先放大石塊,那你就再也不能把它放進瓶子里。那么,什么是你生命中的大石塊呢,與你愛人共度時光,你的信仰,教育,夢想,或是和我一樣,教育指導其他人?切切記得先去處理這些''大石塊'',否則,一輩子你都不能做到。"
??? 那么,今晚,或許是今晨,你正在閱讀這篇短文,可曾試著問自己這個問題:我今生的''大石頭''是什么?然后,請把它們先放進你人生的瓶子.
package com.gf.rttw.warrants;
import java.util.Timer; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator;
public class Main { ?static Logger logger = Logger.getLogger(Main.class); ?static { ??PropertyConfigurator.configure("log4jconfig.properties"); ?} ?public static void main(String[] arg) ?{ ??//get args from the console ??int gap=0; ??try { ???if(arg.length<1) ???{ ????throw new Exception(); ???} ???gap=Integer.parseInt(arg[0]); ???if((gap<1)||(gap>3600)) ???{ ????throw new Exception(); ???} ??} catch (Exception e) { ???logger.error("PLEASE INPUT THE TIMER GAP 1-3600(SECONDS)"); ???System.exit(1); ??} ??? ??java.util.Timer timer= new Timer(true);? ??timer.schedule( ??new java.util.TimerTask() ??{ ?? public void run() ??{ ??? logger.debug("run task once"); ??? //define any task you like ??} ??}, ??0, gap*1000 ??); ??try { ???Thread.sleep(Long.MAX_VALUE); ??} catch (InterruptedException e) { ???logger.fatal(e.getMessage()); ??} ?} }
上面的代碼很簡單,從命令行讀取一個參數(以秒為單位的時間間隔)然后該程序就會每隔一段時間打印一個"run task once";
說明:根據提供的sql/標題/參數列表進行查詢,返回的二維String數組可以直接用來顯示,將會陸續增加排序/格式化等功能,核心的execQuery方法如下:
public String[][] execSQL(String sql,String[] titles,Object[] params) throws Exception {
//todo:驗證數據庫連接是否可用 ??if(con==null||con.isClosed())throw new Exception("數據庫連接不可用");
//todo:簡單的驗證輸入參數 ??if(sql==null) ???throw new Exception("SQL語句不能為空"); ??sql=sql.trim(); ??if(sql.equals("")) ???throw new Exception("SQL語句不能為空"); ?? //對輸入參數做簡單的日志記錄?? logger.info(sql);?? ??logger.info(Dao.msgOfArray(titles)); ??logger.info(Dao.msgOfArray(params)); ??? //準備sql?? PreparedStatement pst = con.prepareStatement(sql);
//如果參數不空,則準備參數?? if(params!=null) ??{ ???for(int i=0;i<params.length;i++) ???{ ????if(params[i]==null) ????{ ?????break; ????} ????pst.setObject(i+1,params[i]);? //此處依賴JDBC Driver實現,不同的驅動可能實現的程度不一樣 ???} ??}
//查詢 ??ResultSet rs = pst.executeQuery(); ?? //metaData ResultSetMetaData md = rs.getMetaData(); ??int colCount = md.getColumnCount(); ??ArrayList al = new ArrayList(maxCount); //maxCount為Dao的一個屬性,定義每次查詢返回的最大記錄數
//如果參數沒有輸入表格頭信息,則從metadata取得列名字作為默認值?? if (titles == null) { ???titles = new String[colCount]; ???for (int i = 0; i < colCount; i++) { ????String columnName = md.getColumnName(i + 1); ????if (columnName == null) { ?????columnName = "無列名"; ????}; ????titles[i] = columnName; ???} ??}
??int count = 0; ??al.add(count++, titles); // 標題
//遍歷結果集合? ?while (rs.next()) { ???String[] buffer = new String[colCount]; ???for (int i = 0; i < colCount; i++) { ????int type = md.getColumnType(i + 1); ????int scale = md.getScale(i + 1); ????String value=null;
//todo:根據對于頁面顯示的要求,對不同的數據類型用不同的方式格式化 ????switch (type) ????{ ????case Types.LONGVARCHAR: // -1 dataType="Long"; ?????value=rs.getString(i+1); ?????break; ????case Types.CHAR: // 1 dataType="Character"; ?????value=rs.getString(i+1); ?????break; ????case Types.NUMERIC: // 2 ?????switch (scale) { ?????case 0: // dataType="Number"; ??????value=rs.getString(i+1); ??????break; ?????case -127: // dataType="Float"; ??????value=rs.getString(i+1); ??????break; ?????default: ??????value=rs.getString(i+1); ???????? break; ?????} ?????break;
????case Types.VARCHAR: // 12 ?????// dataType="String"; ?????value=rs.getString(i+1); ?????break; ????case Types.DATE: // 91 ?????// dataType="Date"; ?????value=rs.getString(i+1); ?????break; ????case Types.TIMESTAMP: // 93 ?????// dataType="Date"; ?????value=rs.getString(i+1); ?????break; ????case Types.BLOB: ?????// dataType="Blob"; ?????value="不支持的數據類型"; ?????break; ????default: ?????value=rs.getString(i+1); ????} ???? ????buffer[i]=value; ???} ???al.add(count++, buffer); ???if (count >= maxCount) { ????break; ???} ??}
//convert to String[][] and return?? String[][] returnValue = new String[count][]; ??for (int i = 0; i < count; i++) { ???returnValue[i] = (String[]) al.get(i); ??} ??return returnValue; ?} //end here
最近做一個基于J2EE的WEB項目,該項目的特點是查詢比較多,本來設計中打算用hibernate實現持久層,但是基于項目時間緊張和開發人員不熟悉hibernate而取消.于是想到了傳統的Dao,加上最近看了好多關于類反射的東西,于是自己寫了一個簡單的Dao,基本的方法很簡單,輸入sql語句/參數/,返回String二維數組(直接在頁面顯示).由于只是針對web顯示,所以在設計上加入了一些小技巧,例如數組的第一行是表頭信息,通過參數傳入,如果參數為null則根據dbms metadata來讀取,相關的api列表如下:
 其中以Simple開頭的查詢方法只支持單條查詢并直接返回結果,其打開和關閉連接等過程在內部自動實現.以exec開頭的的方法支持多條查詢和update,支持事務,要自己打開(init)和關閉(close)連接,下面是一個stuts actionbean里面的代碼片斷,是不是看起來很簡單呢:)
? Dao d = new Dao(); ??String[][] result = null; ??String sql="select name,phone from users where schoolID=? and classID=?" ??result=d.simplyQuery(sql, ????new String[]{"姓名","電話號碼"},? //表頭 ????new String[]{theForm.getSchoolID(),theForm.getClassID}?? //參數 ????); ??request.getSession().setAttribute("xxxx..",result);
作者:劉穎博
時間:2004-6-12 mail:liuyingbo@126.com,請指正 轉載請注明出處及作者
本文討論的是關于oracle從8i開始引進object的概念后的rowid,即擴展(extended)的rowid:
1.?????? rowid的介紹
先對rowid有個感官認識:
SQL> select ROWID from Bruce_test where rownum<2;
ROWID ------------------ ---------- AAABnlAAFAAAAAPAAA ? ROWID的格式如下:
數據對象編號??????? 文件編號??????? 塊編號?????????? 行編號 OOOOOO???????????? FFF??????????????? BBBBBB? RRR
我們可以看出,從上面的rowid可以得知: AAABnl 是數據對象編號 AAF是相關文件編號 AAAAAP是塊編號 AAA 是行編號
怎么依據這些編號得到具體的十進制的編碼值呢,這是經常遇到的問題。這里需要明白rowid的是基于64位編碼的18個字符顯示(數據對象編號(6) +文件編號(3) +塊編號(6)+?????? 行編號(3)=18位),其中 A-Z <==> 0 - 25 (26) a-z <==> 26 - 51 (26) 0-9 <==> 52 - 61 (10) +/ <==> 62 - 63 (2)
共64位,明白這個后,就可以計算出10進制的編碼值,計算公式如下: d * (b ^ p) 其中:b就是基數,這里就是64,p就是從右到左,已0開始的位置數 比如:上面的例子 文件號AAF,具體的計算應該是: 5*(64^0)=5; 0*(64^1)=0; 0*(64^2)=0; 文件號就是0+0+5=5 剛才提到的是rowid的顯示方式:基于64位編碼的18個字符顯示,其實rowid的存儲方式是:10 個字節即80位存儲,其中數據對象編號需要32 位,相關文件編號需要10 位,塊編號需要22,位行編號需要16 位,由此,我們可以得出: 32bit的object number,每個數據庫最多有4G個對象 10bit的file number,每個對象最多有1022個文件(2個文件預留) 22bit的block number,每個文件最多有4M個BLOCK 16bit的row number,每個BLOCK最多有64K個ROWS
2.?????? rowid相關的有用的sql
最簡單的基于rowid的顯示方式得到的響應的64位編碼對應值的sql: select rowid , substr(rowid,1,6) "OBJECT", substr(rowid,7,3) "FILE", substr(rowid,10,6) "BLOCK", substr(rowid,16,3) "ROW" from TableName;
OWID????????????? OBJECT?????? FILE?? BLOCK??????? ROW ------------------ ------------ ------ ------------ ------ AAABc4AADAAAGLUAAA AAABc4?????? AAD??? AAAGLU?????? AAA AAABc4AADAAAGLUAAB AAABc4?????? AAD??? AAAGLU?????? AAB AAABc4AADAAAGLUAAC AAABc4?????? AAD??? AAAGLU?????? AAC AAABc4AADAAAGLUAAD AAABc4?????? AAD??? AAAGLU?????? AAD AAABc4AADAAAGLUAAE AAABc4?????? AAD??? AAAGLU?????? AAE
通過dbms_rowid這個包,可以直接的得到具體的rowid包含的信息: ? select dbms_rowid.rowid_object(rowid)? object_id, dbms_rowid.rowid_relative_fno(rowid) file_id, dbms_rowid.rowid_block_number(rowid)? block_id ,dbms_rowid.rowid_row_number(rowid)? num from bruce_t where rownum<5;
OBJECT_ID??? FILE_ID?? BLOCK_ID??????? NUM ---------- ---------- ---------- ---------- ????? 5944????????? 3????? 25300????????? 0 ????? 5944????????? 3????? 25300????????? 1 ????? 5944????????? 3????? 25300????????? 2 ????? 5944????????? 3????? 25300????????? 3
一些使用ROWID的函數 ROWIDTOCHAR(rowid) :將ROWID轉換成STRING CHARTOROWID('rowid_string') :將STRING轉換成ROWID
另外,就是自己寫的一些函數:(下面的函數是網友eygle提供)
create or replace function get_rowid
(l_rowid in varchar2) return varchar2 is ls_my_rowid???? varchar2(200);????????? rowid_type???? number;????????? object_number???? number;????????? relative_fno???? number;????????? block_number???? number;????????? row_number???? number;?
begin ?dbms_rowid.rowid_info(l_rowid,rowid_type,object_number,relative_fno, block_number, row_number);????????? ?ls_my_rowid := 'Object# is????? :'||to_char(object_number)||chr(10)|| ??????? 'Relative_fno is :'||to_char(relative_fno)||chr(10)|| ??????? 'Block number is :'||to_char(block_number)||chr(10)|| ??????? 'Row number is?? :'||to_char(row_number); ?return ls_my_rowid ; end;?????????
/
應用上面的函數如下: SQL> select get_rowid(rowid), name from bruce_t; GET_ROWID(ROWID)???????????????????????????????????????????????????????????????? NAME
-------------------------------------------------------------------------------- -------------------------------- Object# is????? :5944????????????????????????????????????????????????????? BruceLau Relative_fno is :3?????????????????????????????????????????????????????????????? Block number is :25300?????????????????????????????????????????????????????????? Row number is?? :0?????????????????????????????????????????????????????????????? Object# is????? :5944???????????????????????????????????????????????????? MabelTang Relative_fno is :3?????????????????????????????????????????????????????????????? Block number is :25300?????????????????????????????????????????????????????????? Row number is?? :1???
?
SELECT * INTO XLImport3 FROM OPENDATASOURCE('Microsoft.Jet.OLEDB.4.0', 'Data Source=C:\test\xltest.xls;Extended Properties=Excel 8.0')...[Customers$]
SELECT * INTO XLImport4 FROM OPENROWSET('Microsoft.Jet.OLEDB.4.0', 'Excel 8.0;Database=C:\test\xltest.xls', [Customers$])
SELECT * INTO XLImport5 FROM OPENROWSET('Microsoft.Jet.OLEDB.4.0', 'Excel 8.0;Database=C:\test\xltest.xls', 'SELECT * FROM [Customers$]')
?
crontab是一個很方便的在unix/linux系統上定時(循環)執行某個任務的程序
基本用法: ?1. crontab -l ???? 列出當前的crontab任務 ?2. crontab -d ???? 刪除當前的crontab任務 ?3. crontab -e (solaris5.8上面是 crontab -r) ???? 編輯一個crontab任務,ctrl_D結束 ?4. crontab filename ???? 以filename做為crontab的任務列表文件并載入
crontab file的格式: ??? crontab 文件中的行由 6 個字段組成,不同字段間用空格或 tab 鍵分隔。前 5 個字段指定命令要運行的時間 ?????? 分鐘 (0-59) ?????? 小時 (0-23) ?????? 日期 (1-31) ?????? 月份 (1-12) ?????? 星期幾(0-6,其中 0 代表星期日) ?????? 第 6 個字段是一個要在適當時間執行的字符串
例子: ????? #MIN HOUR DAY MONTH DAYOFWEEK COMMAND ????? #每天早上6點10分 ????? 10 6 * * * date ????? #每兩個小時 ????? 0 */2 * * * date??? (solaris 5.8似乎不支持此種寫法) ????? #晚上11點到早上8點之間每兩個小時,早上8點 ????? 0 23-7/2,8 * * * date ????? #每個月的4號和每個禮拜的禮拜一到禮拜三的早上11點 ????? 0 11 4 * mon-wed date ????? #1月份日早上4點 ????? 0 4 1 jan * date
補充:在使用crontab的時候,要特別注意的是運行腳本中能夠訪問到的環境變量和當前測試環境中的環境變量未必一致,一個比較保險的做法是在運行的腳本程序中自行設置環境變量(export)
?
Log4j由三個重要的組件構成:日志信息的優先級,日志信息的輸出目的地,日志信息的輸出格式。日志信息的優先級從高到低有ERROR、WARN、INFO、DEBUG,分別用來指定這條日志信息的重要程度;日志信息的輸出目的地指定了日志將打印到控制臺還是文件中;而輸出格式則控制了日志信息的顯示內容。
一、定義配置文件
其實您也可以完全不使用配置文件,而是在代碼中配置Log4j環境。但是,使用配置文件將使您的應用程序更加靈活。Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面我們介紹使用Java特性文件做為配置文件的方法:
1.配置根Logger,其語法為:
log4j.rootLogger = [ level ] , appenderName, appenderName, …
其中,level 是日志記錄的優先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個級別,優先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應用程序中相應級別的日志信息的開關。比如在這里定義了INFO級別,則應用程序中所有DEBUG級別的日志信息將不被打印出來。 appenderName就是指定日志信息輸出到哪個地方。您可以同時指定多個輸出目的地。
2.配置日志信息輸出目的地Appender,其語法為:
log4j.appender.appenderName = fully.qualified.name.of.appender.class log4j.appender.appenderName.option1 = value1 … log4j.appender.appenderName.option = valueN
其中,Log4j提供的appender有以下幾種: org.apache.log4j.ConsoleAppender(控制臺), org.apache.log4j.FileAppender(文件), org.apache.log4j.DailyRollingFileAppender(每天產生一個日志文件), org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件), org.apache.log4j.WriterAppender(將日志信息以流格式發送到任意指定的地方)
3.配置日志信息的格式(布局),其語法為:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class log4j.appender.appenderName.layout.option1 = value1 … log4j.appender.appenderName.layout.option = valueN
其中,Log4j提供的layout有以下幾種: org.apache.log4j.HTMLLayout(以HTML表格形式布局), org.apache.log4j.PatternLayout(可以靈活地指定布局模式), org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串), org.apache.log4j.TTCCLayout(包含日志產生的時間、線程、類別等等信息)
Log4J采用類似C語言中的printf函數的打印格式格式化日志信息,打印參數如下: %m 輸出代碼中指定的消息
%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL %r 輸出自應用啟動到輸出該log信息耗費的毫秒數 %c 輸出所屬的類目,通常就是所在類的全名 %t 輸出產生該日志事件的線程名 %n 輸出一個回車換行符,Windows平臺為“\r\n”,Unix平臺為“\n” %d 輸出日志時間點的日期或時間,默認格式為ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921 %l 輸出日志事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數。舉例:Testlog4.main(TestLog4.java:10)
二、在代碼中使用Log4j
1.得到記錄器
使用Log4j,第一步就是獲取日志記錄器,這個記錄器將負責控制日志信息。其語法為:
public static Logger getLogger( String name)
通過指定的名字獲得記錄器,如果必要的話,則為這個名字創建一個新的記錄器。Name一般取本類的名字,比如:
static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () )
2.讀取配置文件
當獲得了日志記錄器之后,第二步將配置Log4j環境,其語法為:
BasicConfigurator.configure (): 自動快速地使用缺省Log4j環境。 PropertyConfigurator.configure ( String configFilename) :讀取使用Java的特性文件編寫的配置文件。 DOMConfigurator.configure ( String filename ) :讀取XML形式的配置文件。
3.插入記錄信息(格式化日志信息)
當上兩個必要步驟執行完畢,您就可以輕松地使用不同優先級別的日志記錄語句插入到您想記錄日志的任何地方,其語法如下:
Logger.debug ( Object message ) ; Logger.info ( Object message ) ; Logger.warn ( Object message ) ; Logger.error ( Object message ) ;
?
本文給出了一些指導性的意見和建議,用于幫助用戶在產品開發中遵循自由軟件的許可證條款,并避免出現違反自由軟件許可證的情況發生。
1.如果您不接受 GPL/LGPL 許可證,請勿使用任何遵循該許可證條款發布的軟件。如果您在自己的產品中使用了 GPL/LGPL 軟件,則說明您已經接受了 GPL/LGPL 許可證中定義的所有條款,并有義務向產品的最終用戶提供源代碼——無論該源代碼是否經過您的修改。如果經過了您自己的修改,則必須公開“衍生作品”的源代碼,并以相同的許可證條款發布。
2.當您從 GPL/LGPL 軟件中拿出 10 行以上的源代碼用于自己的作品中時,則您的作品將成為該 GPL/LGPL 軟件的衍生作品,無論您的作品的整體代碼規模有多大。因此,如果您不打算將自己的作品作為自由軟件發布,則應該遠離自由軟件代碼,以免因為受到自由軟件代碼的影響而編寫出和這些軟件相類似的代碼。
3.如果在您的作品中使用了 GPL/LGPL 軟件,但沒有對這些軟件做任何修改,則可以在產品手冊或者其他類似的文檔中、程序界面上或者幫助信息中指明您使用的自由軟件名稱、版權擁有者以及能夠獲取該自由軟件全部源代碼的公共網站或第三方。如果因為某種原因,最終用戶無法從您提到的第三方或者公共網站上獲得該自由軟件的源代碼,您應該擔負提供源代碼的責任和義務。
4.GPL/LGPL 條款賦予您修改作品的權利,經修改之后的作品稱為“衍生作品”。當您的衍生作品以某種方式發布時(典型情況就是用于您的產品中),您必須依照 GPL/LGPL 許可證發布您的衍生作品。當然,一種更加可取的辦法是,將自己所做的修改提交給原始作品的維護者,并由該維護者負責發布,而您在產品中始終使用由維護者發布的作品。
5.自由軟件不等于免費。提供自由軟件的人可以要求您支付一定的費用,該費用通常有兩層含義:第一,自由軟件以某種介質發行時,該介質的制作、發布等費用;第二,當您希望獲得對某自由軟件的技術支持、缺陷修正等服務,要求某個人或組織提供相應的產品質量擔保時,該組織或個人可以要求您就質量擔保收取服務費用,甚至是專有軟件產品慣用的使用許可費用。這里提到的組織或個人是任何遵循上述自由軟件許可證條款發布自由軟件、并向您提供質量擔保的組織或個人,并不限于自由軟件作品的作者或主要的版權擁有人。
6.對 LGPL 條款的自由軟件(通常是函數庫)的“正常使用”,通常的理解是,始終以動態鏈接的形式鏈接這個函數庫——如果以靜態的方式鏈接,將使該函數庫成為您作品的一部分,從而使之成為該函數庫的衍生作品。但實質上,LGPL 許可證的宗旨和精神是禁止將自由軟件成為專用和獨享的軟件,而至少應該確保其他軟件也能通過某種途徑使用這個函數庫的接口。當然,靜態鏈接顯然違背了上述精神和宗旨,從而是不允許將私有作品和 LGPL 函數庫靜態鏈接在一起。但如果您的產品沒有提供任何擴展功能,而只能由您自己的私有作品使用其中包含的某 LGPL 函數庫,這無異于將該函數庫靜態鏈接到您自己的私有作品中。因此,我們認為這種情況下,您的作品是該函數庫的“衍生作品”——無論您的作品通過靜態鏈接還是通過動態鏈接的方式鏈接該 LGPL 函數庫。
上述這種情況經常會出現在嵌入式系統中。在這種情況下,您可以有如下選擇:
? * 以動態鏈接方式鏈接 LGPL 函數庫,并為您的產品提供擴展接口及程序上載接口, ??? 以便用戶或者其他人能夠對該產品進行擴展。
? * 最簡單的方式:將衍生作品置于 LGPL 條款下發布。
? * 和 LGPL 條款的版權擁有人聯系,看看是否能夠以其他許可證方式授權您 ??? 在自己的產品中使用該函數庫,而不必遵循 LGPL 條款使自己的作品成為 ??? 衍生作品。許多自由軟件為商業用戶提供另外一種可選的許可方式。
? * 當然,如果您覺得麻煩,可以選擇不使用任何自由軟件。
?
令狐沖十四歲那年進入華山,那年岳琳珊八歲,岳不群白天給兩人指點劍法,晚上令狐沖給小師妹講故事哄她入睡。后來,岳不群陸續收了勞德諾,陸大有等徒弟,又忙于修煉紫霞神功,就沒有時間指點徒弟。于是他做了一個HUB,從此華山派實現教育電子化,岳不群在網上同時給每個徒弟授課,這種方法很快在五岳劍派內部推廣。為了在五岳劍派之間互連,嵩山派掌門左冷禪研制出路由器,使得五岳劍派之間可以互聯互通。令狐沖晚上就通過網絡給小師妹講故事。 很快,岳琳珊已經十六歲,變成了一個亭亭玉立的小姑娘了。令狐沖發現自己的目光總是不由自主的在小師妹身上停留,每次和小師妹在一起的時候,總能聽到自己強烈的心跳聲,經過了一段時間的茶飯不思后,終于有一天晚上,令狐沖在網上給小師妹發了一首情意綿綿的詩:你是風兒我是沙,你是蜜蜂我是花,你是梳子我是頭發,你是牙膏我是牙刷。 第二天,華山派開例會,令狐沖懷著忐忑不安的心情來到了會議室,發現小師妹紅著臉躲在師父后面,而其它的師弟都在偷偷朝自己笑,開完會,一個調皮的師弟就過來叫牙刷師兄,趕緊蒙面逃走。問陸大有,才知道是勞德諾用一個叫NetXRay的工具把自己在網上的大作全抓了出來。令狐沖悔恨萬分,于是,閉門研究RFC,成功的研制出LanSwitch。它能夠識別設備MAC地址,這樣,令狐沖發送給小師妹的數據只有她一個人能夠收到。令狐沖晚上可以在網上放心的給小師妹講故事,偶爾手癢還能敲幾句平時心里想又說不出口的話來過癮,然后,紅著臉想象小師妹看到后的表情。 // LanSwitch是二層交換設備,它可以理解二層網絡協議地址MAC地址。二層交換機在操作過程中不斷的收集資料去建立它本身的地址表,這個表相當簡單,主要標明某個MAC地址是在哪個端口上被發現的,所以當交換機接收到一個數據封包時,它會檢查該封包的目的MAC地址,核對一下自己的地址表以決定從哪個端口發送出去。而不是象HUB那樣,任何一個發方數據都會出現在HUB的所有端口上(不管是否為你所需)。這樣,LanSwitch在提高效率的同時,也提高了系統的安全性。// 接下來的一年,岳不群大量招收門徒,華山派得以極大的壯大,所使用的LanSwitch也多次級連。但門徒中難免魚龍混雜,當時華山派一批三、四代弟子崇拜萬里獨行田伯光,成立了一個田協,經常廣播爭論比賽八百米還是一千米很合理的問題;第三代弟子中有一個叫xxx的,每天在華山派內部廣播xx大法;更讓令狐沖受不了的是,隨著師父年齡的增大,變得越來越羅嗦,每句話都要重復二十遍,然后在網上廣播。令狐沖想和小師妹,陸大有等人專門使用一個廣播域,但如果另外使用一個LanSwitch的話,師父肯定不會同意,于是,他修改了LanSwitch的軟件,把小師妹,陸大有等人和自己劃成一個虛擬網(VLAN),其它人使用另外的VLAN,廣播包只在VLAN內發送,VLAN間通過路由器連接。岳不群也深受田協,xxx其害,但為與左冷禪抗爭,用人之際,只能隱忍,知道了這件事,大為高興,但仍為令狐沖私自修改軟件一事,罰他到思過崖面壁一年,一年之內不得下山。 在華山派內重新使用VLAN進行子網劃分,分為五個子網,師父和師娘,小師妹還有林平之在一個VLAN,xx功弟子用一個VLAN;田協弟子用一個VLAN,其它弟子用一個VLAN,而思過崖上也有單獨的一個VLAN。令狐沖到了思過崖,并不難過,終于,世界安靜了,依靠左冷禪的路由器,令狐沖還可以每天在網上給小師妹講故事,聊天。 // 局域網交換機的引入,使得網絡節點間可獨享帶寬,但是,對于二層廣播報文,二層交換機會在各網絡節點上進行廣播;同時,對于二層交換機無法識別的MAC地址,也必須在廣播域內進行廣播。當多個二層交換機級連時,二層交換網絡上的所有設備都會收到廣播消息。在一個大型的二層廣播域內,大量的廣播使二層轉發的效率大大減低,為了避免在大型交換機上進行的廣播所引起的廣播風暴,需要在一個二層交換網絡內進一步劃分為多個虛擬網(VLAN)。在一個虛擬網(VLAN)內,由一個工作站發出的信息只能發送到具有相同虛擬網號(VLANID)的其他站點,其它虛擬網(VLAN)的成員收不到這些信息或廣播幀。采用虛擬網(VLAN)可以控制網絡上的廣播風暴和增加網絡的安全性。不同虛擬網(VLAN)之間的通信必須通過路由器進行。// ? 但是幸福永遠是短暫的,接下來總是無盡的煩惱。隨著整個五岳劍派勢力的增大,路由器的速度越來越慢。令狐沖發現每次給小師妹講故事時,小師妹的回答總是姍姍來遲,而且話也很少,總是"嗯","噢"或者"我聽著呢"。終于有一天,路由器再也PING不通的,令狐沖三天沒有得到小師妹的消息,對著空空的顯示屏,再也忍不住,在一個下著雪的晚上,偷偷下山找小師妹,到了小師妹窗前,發現小師妹正在網上和小林子熱烈的聊天,全沒注意一邊的自己,內心一陣酸痛,回到思過崖,大病一場。病好后潛心研究,終于有一天,做出來一個路由器,這時,令狐沖發現,此時華山派已經有了三十個VLAN,路由器必須為每個VLAN分配一個接口,接口不夠用,而且,兩個子網內通過路由器的交換速度遠遠低于二層交換的速度。 // 二層交換機劃分虛擬子網后,就出現了一個問題:不同虛擬子網之間的轉發需要通過其它路由器來實現。二層交換機的不同VLAN節點間的轉發需要通過路由器設備來實現大大浪費了端口,而路由器的高成本,低效率又使它無法滿足大量子網情況下的三層轉發需求,三層交換的概念就在這種情況下被提了出來。// 這天晚上,令狐沖心灰意懶,借酒消愁,這時,一個黑影出現在他的面前,原來是一個道風仙骨的老人,正是風清揚。風清揚聽了令狐沖的疑惑,說:路由器接口不夠,把路由器做在LanSwitch內部不就可以了;交換速度慢,是因為路由器查找的是網段路由,而LanSwitch直接查MAC對應出端口,當然速度快。為什么不能直接根據IP地址查到出端口呢?令狐沖一聽,大為仰慕,但還是不明白,IP地址那么多,而且經常變化,如何能夠直接查到出端口呢?風清揚說: "你先坐下,讓我來問你,華山派有多少弟子?" "一萬六千左右。" "你全知道他們住哪里嗎?" "不知道。" "岳不群要你找一個不知道住哪里的人,如何去找?" "查華山派電話號碼查詢系統,找到他的地址,然后去找他。" "如果你回來后再讓你找這個人,又如何去找?" "如何.... ,查華山派電話號碼查詢系統,找到他的地址,然后去找他。" "你不知道到這個人的地址嗎?" "知道,但師父說,華山派的地址那么多,而且經常變化,不用知道地址。" "岳不群這小子,把徒弟都教成木頭了!我問你,你自己認為應該如何找?" "直接去找!" "好!你這人還不算太苯。那你知道了一個人的地址后,是不是永遠記住了?" "有的人記住了。其它的都忘了。" "為什么忘了?" "因為我記不了那么多人,而且一段時間沒有去找他。" "華山派電話號碼查詢系統里的地址是如何獲得的?" "我在空曠處大喊一聲他的名字,他聽到后就會來找我,告訴我他的地址。" 風清揚又問了大把類似腦筋急轉彎的問題,然后風清揚說:"現在你明白根據IP地址直接查出端口的道理了嗎?等到你明白這個道理,你自然會做出三層交換機來",令狐沖仔細回憶了今天的話,終于明白了和二層轉發由MAC地址對應到出端口的道理一樣,三層轉發也可以直接由IP地址對應到出端口,IP地址的路由可以通過ARP來學習,同樣需要老化。這樣,VLAN間轉發除第一個包需要通過ARP獲得主機路由外,其它的報文直接根據IP地址就能夠查找到出端口,轉發速度遠遠高于路由器轉發的速度。抬頭看時,風清揚已經走了。 一年后,令狐沖下思過崖,成功的推出Quidway S8016路由交換機。實現了VLAN間的互通,并且與嵩山,黑木崖等路由器實現互通。 // 三層交換機是在二層交換機的基礎上增加三層交換功能,但它不是簡單的二層交換機加路由器,二而是采用了不同的轉發機制。路由器的轉發采用最長匹配的方式,實現復雜,通常使用軟件來實現,。而三層交換機的路由查找是針對流的,它利用CACHE技術,很容易采用ASIC實現,因此,可以大大的節約成本,并實現快速轉發。 很多文章會提及三層交換機和路由器的區別,一般的比較是三層交換機又快又便宜。這些話沒有錯,但場合是匯聚層。我們看到,在匯聚層,面向三層交換機直接下掛的主機,因為能夠獲得其主機路由,所以三層交換機能夠實現快速查找;而對于通過其它路由器連接多個子網后到達的主機,三層交換機和路由器的處理是一樣的,同樣采用最長匹配的方法查找到下一跳,由下一跳路由器進行轉發。 因此,通常的組網方式是在骨干層使用GSR,匯聚層使用三層交換機。當然,對于一個小型的城域網,也可以直接拿三層交換機組網,不需要GSR。//
|