学习别人 提高自己

玩玩罢了

 

2007年12月10日

自已写的动态二层web菜单

一、数据库为:menu(menuId<pk>、menuName、parentMenuId、pageUrl、remark);
二、左侧菜单:
    1、leftmenu.ascx
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="LeftMenu.ascx.cs"     Inherits="LeftMenu" %>
<link href="css/leftmenu.css" type="text/css" rel="stylesheet" />
<script src="js/leftmenu.js" type="text/javascript"></script>
<div id="divContain" runat="server" style="width:100px; vertical-align:top; display:block;">
</div>
    2、leftmenu.ascx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Common;
using BL;
using System.Text;

public partial class LeftMenu : System.Web.UI.UserControl
{
    private string _target="_top";//导航栏的目标
    public string Target
    {
        get { return _target; }
        set { _target = value; }
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        StringBuilder menuString = new StringBuilder();
        MenuBL menuBl = new MenuBL();
        //获取根结点,即父结点为0的结点
        List<MenuEntity> menus = menuBl.QueryMenu(0);
        //动态加载父菜单
        foreach (MenuEntity menu in menus)
        {
            menuString.Append("<div id='menu");
            menuString.Append(menu.MenuId);
            menuString.Append("' class='parentMenu' onmouseover='parentMenuOver(menu");
            menuString.Append(menu.MenuId);
            menuString.Append(")' onmouseout='parentMenuOut(menu");
            menuString.Append(menu.MenuId);
            menuString.Append(")' onClick='parentMenuClick(menu");
            menuString.Append(menu.MenuId);
            menuString.Append(")'>");
            menuString.Append(menu.MenuName);
            menuString.Append("</div>");

           
            //加载子菜单
            List<MenuEntity> sonMenus = menuBl.QueryMenu(menu.MenuId);
            if (sonMenus.Count > 0)
            {
                menuString.Append("<div id='sonmenu" + menu.MenuId + "' class='sonMenu'>");
                menuString.Append("<ul>");
                foreach (MenuEntity sonMenu in sonMenus)
                {
                    menuString.Append("<li id='li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append("' onmouseover='liOver(li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append(")' onmouseout='liOut(li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append(")' onclick=\"liClick('");
                    menuString.Append(sonMenu.PageUrl);
                    menuString.Append("','");
                    menuString.Append(Target);
                    menuString.Append("')\">");                   
                    //menuString.Append("<a href='");
                    //menuString.Append(sonMenu.PageUrl);
                    //menuString.Append("' id='");
                    //menuString.Append(sonMenu.MenuId);
                    //menuString.Append("' target='");
                    //menuString.Append(Target);
                    //menuString.Append("'>");
                    menuString.Append(sonMenu.MenuName);
                    //menuString.Append("</a>");
                    menuString.Append("</li>");

                }
                menuString.Append("</ul></div>");
            }
        }

        this.divContain.InnerHtml = menuString.ToString();
    }
}
    3、leftmenu.css
    

.parentMenu
{
  background-color:#CCCCCC;
  cursor:hand;
  width:100px;
}
.parentMenuOver
{
    background-color:#999999;
    cursor:hand;
}
.parentMenuOut
{
 background-color:#CCCCCC;
 cursor:hand;
}
.sonMenu
{
 background-color:#CCCCCC;
 display:none;
}
.sonMenuSel

 background-color:#999999;
}
.view
{
 display:block;
}
.hidden
{
 display:none;
}
ul
{
 margin:0px 0px 0px 0px;
}
li
{
 list-style-type:none;
 width:100px;
 cursor:hand;
}
div
{
 margin:0px 0px 0px 0px;
 padding:0px 0px  0px 0px;
}
.liOver
{
 background-color:#E8E8E8;
}
.liOut
{
 background-color:#F7F7F7;
}
a
{
 width:100px;
}

    4、leftmenu.js
    

//当点击父菜单时调用的函数
function parentMenuClick(menuId)
{  
    if(document.getElementById("son"+menuId.id).className=="view")
    {
     document.getElementById("son"+menuId.id).className="hidden";
 }
 else
 {
     document.getElementById("son"+menuId.id).className="view";
 }
}
//移动到父菜单时调用
function parentMenuOver(menuId)
{
    document.getElementById(menuId.id).className="parentMenuOver";
}
//移出父菜单时调用
function parentMenuOut(menuId)
{
    document.getElementById(menuId.id).className="parentMenuOut";
}
////移动到子菜单时调用
//function sonMenuOver(sonMenuId)
//{
//    document.getElementById(sonMenuId.id).className="view";
//}
////移出子菜单时调用
//function sonMenuOut(sonMenuId)
//{
//    document.getElementById(sonMenuId.id).className="hidden";
//}

//移动到子菜单项时调用
function liOver(liId)
{
    document.getElementById(liId.id).className="liOver";
}
//移出子菜单项时调用
function liOut(liId)
{
    document.getElementById(liId.id).className="liOut";
}
//点击子菜单时调用
function liClick(pageUrl,target)
{
    target.location.href=pageUrl;
}

三、顶部菜单
    1、topmenu.ascx
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="TopMenu.ascx.cs" Inherits="TopMenu" %>
<link href="css/topmenu.css" type="text/css" rel="stylesheet" />
<script src="js/topmenu.js" type="text/javascript"></script>
<div id="divContain_top" runat="server" style="width:100px; vertical-align:top; display:block;">
</div>
    2、topmenu.ascx.cs
    

using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Common;
using BL;
using System.Text;

public partial class TopMenu : System.Web.UI.UserControl
{
    private string _target = "_top";//导航栏的目标
    public string Target
    {
        get { return _target; }
        set { _target = value; }
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        StringBuilder menuString = new StringBuilder();
        StringBuilder jsArray = new StringBuilder();
        jsArray.Append("<script type='text/javascript'>");
        jsArray.Append("var parentArray=new Array();");
        MenuBL menuBl = new MenuBL();
        //获取根结点,即父结点为0的结点
        List<MenuEntity> menus = menuBl.QueryMenu(0);
        menuString.Append("<table id='menu'><tr>");
        //动态加载父菜单
        int count = 0;
        foreach (MenuEntity menu in menus)
        {
           
            menuString.Append("<td id='menu");
            menuString.Append(menu.MenuId);
            menuString.Append("_top' class='parentMenu_top' onmouseover='parentMenuOver_top(menu");
            menuString.Append(menu.MenuId);
            menuString.Append("_top)' onmouseout='parentMenuOut_top(menu");
            menuString.Append(menu.MenuId);
            menuString.Append("_top)'>");
            menuString.Append(menu.MenuName);
            menuString.Append("</td>");
           
            jsArray.Append("parentArray[");
            jsArray.Append(count);
            jsArray.Append("]='sonmenu");
            jsArray.Append(menu.MenuId);
            jsArray.Append("_top';");
          
            count++;
        }
        menuString.Append("</tr></table>");

        //加载子菜单
        foreach (MenuEntity menu in menus)
        {
            List<MenuEntity> sonMenus = menuBl.QueryMenu(menu.MenuId);
            if (sonMenus.Count > 0)
            {
                menuString.Append("<div id='sonmenu" + menu.MenuId + "_top' class='sonMenu_top'");
                menuString.Append("style=' z-index:1;position:absolute;'");
                menuString.Append(">");
                menuString.Append("<ul>");
                foreach (MenuEntity sonMenu in sonMenus)
                {
                    menuString.Append("<li  id='li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append("_top'  class='li_top' onmouseover='liOver_top(li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append("_top)' onmouseout='liOut_top(li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append("_top)' onclick=\"liClick_top('");
                    menuString.Append(sonMenu.PageUrl);
                    menuString.Append("','");
                    menuString.Append(Target);
                    menuString.Append("')\">");
                    menuString.Append(sonMenu.MenuName);
                    menuString.Append("</li>");

                }
                menuString.Append("</ul></div>");
            }
        }
        jsArray.Append("</script>");

        menuString.Append(jsArray.ToString());
        this.divContain_top.InnerHtml = menuString.ToString();
    }
}

    3、css
    .parentMenu_top
{
  background-color:#CCCCCC;
  cursor:hand;
  width:100px;
}
.parentMenuOver_top
{
    background-color:#999999;
    cursor:hand;
}
.parentMenuOut_top
{
 background-color:#CCCCCC;
}
.sonMenu_top
{
 display:none;
}
.li_top
{
 background-color:#E8E8E8;
}
.sonMenuSel_top

 background-color:#999999;
}
.view_top
{
   display:inline-block;
}
.hidden_top
{
  display:none;
}
.liOver_top
{
 background-color:#E8E8E8;
}
.liOut_top
{
 background-color:#F7F7F7;
}
li
{
 height:20px;
 width:100px;
}
    4、topmenu.js
    

//当点击父菜单时调用的函数
function parentMenuClick_top(menuId)
{
     var len=parentArray.length;   
    for( i=0;i<len;i++)
    {
        document.getElementById(parentArray[i]).className="hidden_top";
    }
    document.getElementById("son"+menuId.id).className="view_top";
}
//移动到父菜单时调用
function parentMenuOver_top(menuId)
{
    document.getElementById(menuId.id).className="parentMenuOver";
    parentMenuClick_top(menuId);
}
//移出父菜单时调用
function parentMenuOut_top(menuId)
{
    document.getElementById(menuId.id).className="parentMenuOut";
}

//移动到子菜单项时调用
function liOver_top(liId)
{
    document.getElementById(liId.id).className="liOver";
   
}
//移出子菜单项时调用
function liOut_top(liId)
{
    document.getElementById(liId.id).className="liOut";
}
//点击子菜单时调用
function liClick_top(pageUrl,target)
{
    if(target!="_top"&&target!="_self"&&target!="_parent"&&target!="_blank")
    {
        eval(target).location.href=pageUrl;
    }
}
//控件的加载事件,用于子菜单的位置
function load()
{
    var len=parentArray.length;   
    for( i=0;i<len;i++)
    {
        var left=0;
        var top=0;
        //获取父菜单的位置
        var obj=document.getElementById(parentArray[i].substring(3,parentArray[i].length));
        left+=obj.offsetLeft;
        top+=obj.offsetTop;
        while(obj = obj.offsetParent){
             left += obj.offsetLeft;
             top +=obj.offsetTop;
        }
        document.getElementById(parentArray[i]).style.left=left;
        document.getElementById(parentArray[i]).style.top=top+20;
    }
}
//自动加载
window.onload=load;


 


posted @ 2007-12-10 00:39 拐子 阅读(83) | 评论 (0)编辑

自已写的动态二层web菜单

一、数据库为:menu(menuId<pk>、menuName、parentMenuId、pageUrl、remark);
二、左侧菜单:
    1、leftmenu.ascx
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="LeftMenu.ascx.cs"     Inherits="LeftMenu" %>
<link href="css/leftmenu.css" type="text/css" rel="stylesheet" />
<script src="js/leftmenu.js" type="text/javascript"></script>
<div id="divContain" runat="server" style="width:100px; vertical-align:top; display:block;">
</div>
    2、leftmenu.ascx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Common;
using BL;
using System.Text;

public partial class LeftMenu : System.Web.UI.UserControl
{
    private string _target="_top";//导航栏的目标
    public string Target
    {
        get { return _target; }
        set { _target = value; }
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        StringBuilder menuString = new StringBuilder();
        MenuBL menuBl = new MenuBL();
        //获取根结点,即父结点为0的结点
        List<MenuEntity> menus = menuBl.QueryMenu(0);
        //动态加载父菜单
        foreach (MenuEntity menu in menus)
        {
            menuString.Append("<div id='menu");
            menuString.Append(menu.MenuId);
            menuString.Append("' class='parentMenu' onmouseover='parentMenuOver(menu");
            menuString.Append(menu.MenuId);
            menuString.Append(")' onmouseout='parentMenuOut(menu");
            menuString.Append(menu.MenuId);
            menuString.Append(")' onClick='parentMenuClick(menu");
            menuString.Append(menu.MenuId);
            menuString.Append(")'>");
            menuString.Append(menu.MenuName);
            menuString.Append("</div>");

           
            //加载子菜单
            List<MenuEntity> sonMenus = menuBl.QueryMenu(menu.MenuId);
            if (sonMenus.Count > 0)
            {
                menuString.Append("<div id='sonmenu" + menu.MenuId + "' class='sonMenu'>");
                menuString.Append("<ul>");
                foreach (MenuEntity sonMenu in sonMenus)
                {
                    menuString.Append("<li id='li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append("' onmouseover='liOver(li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append(")' onmouseout='liOut(li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append(")' onclick=\"liClick('");
                    menuString.Append(sonMenu.PageUrl);
                    menuString.Append("','");
                    menuString.Append(Target);
                    menuString.Append("')\">");                   
                    //menuString.Append("<a href='");
                    //menuString.Append(sonMenu.PageUrl);
                    //menuString.Append("' id='");
                    //menuString.Append(sonMenu.MenuId);
                    //menuString.Append("' target='");
                    //menuString.Append(Target);
                    //menuString.Append("'>");
                    menuString.Append(sonMenu.MenuName);
                    //menuString.Append("</a>");
                    menuString.Append("</li>");

                }
                menuString.Append("</ul></div>");
            }
        }

        this.divContain.InnerHtml = menuString.ToString();
    }
}
    3、leftmenu.css
    

.parentMenu
{
  background-color:#CCCCCC;
  cursor:hand;
  width:100px;
}
.parentMenuOver
{
    background-color:#999999;
    cursor:hand;
}
.parentMenuOut
{
 background-color:#CCCCCC;
 cursor:hand;
}
.sonMenu
{
 background-color:#CCCCCC;
 display:none;
}
.sonMenuSel

 background-color:#999999;
}
.view
{
 display:block;
}
.hidden
{
 display:none;
}
ul
{
 margin:0px 0px 0px 0px;
}
li
{
 list-style-type:none;
 width:100px;
 cursor:hand;
}
div
{
 margin:0px 0px 0px 0px;
 padding:0px 0px  0px 0px;
}
.liOver
{
 background-color:#E8E8E8;
}
.liOut
{
 background-color:#F7F7F7;
}
a
{
 width:100px;
}

    4、leftmenu.js
    

//当点击父菜单时调用的函数
function parentMenuClick(menuId)
{  
    if(document.getElementById("son"+menuId.id).className=="view")
    {
     document.getElementById("son"+menuId.id).className="hidden";
 }
 else
 {
     document.getElementById("son"+menuId.id).className="view";
 }
}
//移动到父菜单时调用
function parentMenuOver(menuId)
{
    document.getElementById(menuId.id).className="parentMenuOver";
}
//移出父菜单时调用
function parentMenuOut(menuId)
{
    document.getElementById(menuId.id).className="parentMenuOut";
}
////移动到子菜单时调用
//function sonMenuOver(sonMenuId)
//{
//    document.getElementById(sonMenuId.id).className="view";
//}
////移出子菜单时调用
//function sonMenuOut(sonMenuId)
//{
//    document.getElementById(sonMenuId.id).className="hidden";
//}

//移动到子菜单项时调用
function liOver(liId)
{
    document.getElementById(liId.id).className="liOver";
}
//移出子菜单项时调用
function liOut(liId)
{
    document.getElementById(liId.id).className="liOut";
}
//点击子菜单时调用
function liClick(pageUrl,target)
{
    target.location.href=pageUrl;
}

三、顶部菜单
    1、topmenu.ascx
    <%@ Control Language="C#" AutoEventWireup="true" CodeFile="TopMenu.ascx.cs" Inherits="TopMenu" %>
<link href="css/topmenu.css" type="text/css" rel="stylesheet" />
<script src="js/topmenu.js" type="text/javascript"></script>
<div id="divContain_top" runat="server" style="width:100px; vertical-align:top; display:block;">
</div>
    2、topmenu.ascx.cs
    

using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Common;
using BL;
using System.Text;

public partial class TopMenu : System.Web.UI.UserControl
{
    private string _target = "_top";//导航栏的目标
    public string Target
    {
        get { return _target; }
        set { _target = value; }
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        StringBuilder menuString = new StringBuilder();
        StringBuilder jsArray = new StringBuilder();
        jsArray.Append("<script type='text/javascript'>");
        jsArray.Append("var parentArray=new Array();");
        MenuBL menuBl = new MenuBL();
        //获取根结点,即父结点为0的结点
        List<MenuEntity> menus = menuBl.QueryMenu(0);
        menuString.Append("<table id='menu'><tr>");
        //动态加载父菜单
        int count = 0;
        foreach (MenuEntity menu in menus)
        {
           
            menuString.Append("<td id='menu");
            menuString.Append(menu.MenuId);
            menuString.Append("_top' class='parentMenu_top' onmouseover='parentMenuOver_top(menu");
            menuString.Append(menu.MenuId);
            menuString.Append("_top)' onmouseout='parentMenuOut_top(menu");
            menuString.Append(menu.MenuId);
            menuString.Append("_top)'>");
            menuString.Append(menu.MenuName);
            menuString.Append("</td>");
           
            jsArray.Append("parentArray[");
            jsArray.Append(count);
            jsArray.Append("]='sonmenu");
            jsArray.Append(menu.MenuId);
            jsArray.Append("_top';");
          
            count++;
        }
        menuString.Append("</tr></table>");

        //加载子菜单
        foreach (MenuEntity menu in menus)
        {
            List<MenuEntity> sonMenus = menuBl.QueryMenu(menu.MenuId);
            if (sonMenus.Count > 0)
            {
                menuString.Append("<div id='sonmenu" + menu.MenuId + "_top' class='sonMenu_top'");
                menuString.Append("style=' z-index:1;position:absolute;'");
                menuString.Append(">");
                menuString.Append("<ul>");
                foreach (MenuEntity sonMenu in sonMenus)
                {
                    menuString.Append("<li  id='li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append("_top'  class='li_top' onmouseover='liOver_top(li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append("_top)' onmouseout='liOut_top(li");
                    menuString.Append(sonMenu.MenuId);
                    menuString.Append("_top)' onclick=\"liClick_top('");
                    menuString.Append(sonMenu.PageUrl);
                    menuString.Append("','");
                    menuString.Append(Target);
                    menuString.Append("')\">");
                    menuString.Append(sonMenu.MenuName);
                    menuString.Append("</li>");

                }
                menuString.Append("</ul></div>");
            }
        }
        jsArray.Append("</script>");

        menuString.Append(jsArray.ToString());
        this.divContain_top.InnerHtml = menuString.ToString();
    }
}

    3、topmenu.css
    

.parentMenu_top
{
  background-color:#CCCCCC;
  cursor:hand;
  width:100px;
  margin:0px 0px 0px 0px;
}
.parentMenuOver_top
{
    background-color:#999999;
    cursor:hand;
}
.parentMenuOut_top
{
 background-color:#CCCCCC;
 cursor:hand;
}
.sonMenu_top
{
 display:none;
}
.sonMenuSel_top

 background-color:#999999;
}
.view_top
{
   display:inline-block;
}
.hidden_top
{
  display:none;
}
.liOver_top
{
 background-color:#E8E8E8;
}
.liOut_top
{
 background-color:#F7F7F7;
}

li
{
 background-color:#F7F7F7;
 height:20px;
 width:100px;
}

4、topmenu.js
    

//移动到父菜单时调用
function parentMenuOver_top(menuId)
{
     var len=parentArray.length;
    document.getElementById(menuId.id).className="parentMenuOver_top";   
    for( i=0;i<len;i++)
    {
        document.getElementById(parentArray[i].substring(3,parentArray[i].length)).className="parentMenuOut_top";
        document.getElementById(parentArray[i]).className="hidden_top";
    }
    document.getElementById(menuId.id).className="parentMenuOver_top";
    document.getElementById("son"+menuId.id).className="view_top";
}
//移出菜单1秒后自动关闭
var smId;
var hiddenTime;
function autoClose()
{  
     document.getElementById(smId.id.substring(3,smId.length)).className="parentMenuOut_top";
     document.getElementById(smId.id).className="sonMenu_top";
}

//移出父菜单时调用
function parentMenuOut_top(menuId,sonMenuId)
{
    //document.getElementById(menuId.id).className="parentMenuOut_top";   
    //document.getElementById(sonMenuId.id).className="sonMenu_top";
    smId=sonMenuId;
    if(hiddenTime!=null)
    {
        clearTimeout(hiddenTime);
    }
     hiddenTime=setTimeout("autoClose()",1000);
   
}
//移出子菜单时调用
function sonMenuOut_top(sonMenuId)
{
   // document.getElementById(sonMenuId.id).className="sonMenu_top"; 
     smId=sonMenuId;
     if(hiddenTime!=null)
     {
        clearTimeout(hiddenTime);
     }
     hiddenTime=setTimeout("autoClose()",1000);
}
//移动到子菜单项时调用
function liOver_top(liId)
{
    document.getElementById(liId.id).className="liOver_top";
   
}
//移出子菜单项时调用
function liOut_top(liId)
{
    document.getElementById(liId.id).className="liOut_top";
}
//点击子菜单时调用
function liClick_top(pageUrl,target)
{
    if(target!="_top"&&target!="_self"&&target!="_parent"&&target!="_blank")
    {
        eval(target).location.href=pageUrl;
    }
}
//控件的加载事件,用于子菜单的位置
function load()
{
    var len=parentArray.length;   
    for( i=0;i<len;i++)
    {
        var left=0;
        var top=0;
        //获取父菜单的位置
        var obj=document.getElementById(parentArray[i].substring(3,parentArray[i].length));
        left+=obj.offsetLeft;
        top+=obj.offsetTop;
        while(obj = obj.offsetParent){
             left += obj.offsetLeft;
             top +=obj.offsetTop;
        }
        document.getElementById(parentArray[i]).style.left=left;
        document.getElementById(parentArray[i]).style.top=top+20;
    }
}
//自动加载
window.onload=load;

posted @ 2007-12-10 00:39 拐子 阅读(23) | 评论 (0)编辑

2007年6月20日

Session与Cookie(转载)

一、cookie机制和session机制的区别 *************************************************************************************
具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于才服务器端保持状态的方案在客户端也需要保存一个标识,所以session 机制可能需要借助于cookie机制来达到保存标识的目的,但实际上还有其他选择 *************************************************************************************
 二、会话cookie和持久cookie的区别 *************************************************************************************
如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。  如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。  存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。 *************************************************************************************
三、如何利用实现自动登录 *************************************************************************************   
当用户在某个网站注册后,就会收到一个惟一用户ID的cookie。客户后来重新连接时,这个用户ID会自动返回,服务器对它进行检查,确定它是否为注册用户且选择了自动登录,从而使用户务需给出明确的用户名和密码,就可以访问服务器上的资源。 *************************************************************************************
四、如何根据用户的爱好定制站点 *************************************************************************************   
网站可以使用cookie记录用户的意愿。对于简单的设置,网站可以直接将页面的设置存储在cookie中完成定制。然而对于更复杂的定制,网站只需仅将一个惟一的标识符发送给用户,由服务器端的数据库存储每个标识符对应的页面设置。 *************************************************************************************
五、cookie的发送 *************************************************************************************
1.创建Cookie对象 2.设置最大时效 3.将Cookie放入到HTTP响应报头如果你创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie:存储在浏览器的内存中,用户退出浏览器之后被删除。如果你希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。发送cookie需要使用HttpServletResponse的addCookie方法,将cookie插入到一个Set-Cookie HTTP请求报头中。由于这个方法并不修改任何之前指定的Set-Cookie报头,而是创建新的报头,因此我们将这个方法称为是addCookie,而非setCookie。同样要记住响应报头必须在任何文档内容发送到客户端之前设置。
*************************************************************************************
六、cookie的读取 *************************************************************************************
1.调用request.getCookie 要获取有浏览器发送来的cookie,需要调用HttpServletRequest的getCookies方法,这个调用返回Cookie对象的数组,对应由HTTP请求中Cookie报头输入的值。 2.对数组进行循环,调用每个cookie的getName方法,直到找到感兴趣的cookie为止 cookie与你的主机(域)相关,而非你的servlet或JSP页面。因而,尽管你的servlet可能只发送了单个cookie,你也可能会得到许多不相关的cookie。例如:  String cookieName = “userID”; Cookie cookies[] = request.getCookies(); if (cookies!=null){ for(int i=0;i<cookies.length;i++){ Cookie cookie = cookies[i]; if (cookieName.equals(cookie.getName())){ doSomethingWith(cookie.getValue()); } } } *************************************************************************************
七、如何使用cookie检测初访者 *************************************************************************************
 A.调用HttpServletRequest.getCookies()获取Cookie数组 B.在循环中检索指定名字的cookie是否存在以及对应的值是否正确 C.如果是则退出循环并设置区别标识 D.根据区别标识判断用户是否为初访者从而进行不同的操作 ************************************************************************************* 八、使用cookie检测初访者的常见错误 *************************************************************************************
不能仅仅因为cookie数组中不存在在特定的数据项就认为用户是个初访者。如果cookie数组为null,客户可能是一个初访者,也可能是由于用户将cookie删除或禁用造成的结果。但是,如果数组非null,也不过是显示客户曾经到过你的网站或域,并不能说明他们曾经访问过你的servlet。其它servlet、JSP页面以及非Java Web应用都可以设置cookie,依据路径的设置,其中的任何cookie都有可能返回给用户的浏览器。正确的做法是判断cookie数组是否为空且是否存在指定的Cookie对象且值正确。 *************************************************************************************
九、使用cookie属性的注意问题 *************************************************************************************   
属性是从服务器发送到浏览器的报头的一部分;但它们不属于由浏览器返回给服务器的报头。   因此除了名称和值之外,cookie属性只适用于从服务器输出到客户端的cookie;服务器端来自于浏览器的cookie并没有设置这些属性。   因而不要期望通过request.getCookies得到的cookie中可以使用这个属性。这意味着,你不能仅仅通过设置cookie的最大时效,发出它,在随后的输入数组中查找适当的cookie,读取它的值,修改它并将它存回Cookie,从而实现不断改变的cookie值。 *************************************************************************************
十、如何使用cookie记录各个用户的访问计数 *************************************************************************************
1.获取cookie数组中专门用于统计用户访问次数的cookie的值 2.将值转换成int型 3.将值加1并用原来的名称重新创建一个Cookie对象 4.重新设置最大时效 5.将新的cookie输出 *************************************************************************************
十一、session在不同环境下的不同含义 *************************************************************************************
session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话是从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义。  session在Web开发环境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案。有时候Session也用来指这种解决方案的存储结构。 *************************************************************************************
十二、session的机制 *************************************************************************************   session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。但程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否包含了一个session标识-称为session id,如果已经包含一个session id则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。如果客户请求不包含session id,则为此客户创建一个session并且生成一个与此session相关联的session id,这个session id将在本次响应中返回给客户端保存。 *************************************************************************************
十三、保存session id的几种方式 *************************************************************************************
A.保存session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。 B.由于cookie可以被人为的禁止,必须有其它的机制以便在cookie被禁止时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。 C.另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。 ************************************************************************************* 十四、session什么时候被创建 *************************************************************************************
一个常见的错误是以为session在有客户端访问时就被创建,然而事实是直到某server端程序(如Servlet)调用HttpServletRequest.getSession(true)这样的语句时才会被创建。 *************************************************************************************
十五、session何时被删除 *************************************************************************************
session在下列情况下被删除: A.程序调用HttpSession.invalidate() B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间 C.服务器进程被停止 再次注意关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效。 *************************************************************************************
十六、URL重写有什么缺点 *************************************************************************************    
对所有的URL使用URL重写,包括超链接,form的action,和重定向的URL。每个引用你的站点的URL,以及那些返回给用户的URL(即使通过间接手段,比如服务器重定向中的Location字段)都要添加额外的信息。   这意味着在你的站点上不能有任何静态的HTML页面(至少静态页面中不能有任何链接到站点动态页面的链接)。因此,每个页面都必须使用servlet或JSP动态生成。即使所有的页面都动态生成,如果用户离开了会话并通过书签或链接再次回来,会话的信息都会丢失,因为存储下来的链接含有错误的标识信息-该URL后面的SESSION ID已经过期了。   *************************************************************************************
十七、使用隐藏的表单域有什么缺点 *************************************************************************************
仅当每个页面都是有表单提交而动态生成时,才能使用这种方法。单击常规的超文本链接并不产生表单提交,因此隐藏的表单域不能支持通常的会话跟踪,只能用于一系列特定的操作中,比如在线商店的结账过程 *************************************************************************************
十八、会话跟踪的基本步骤 *************************************************************************************
1.访问与当前请求相关的会话对象 2.查找与会话相关的信息 3.存储会话信息 4.废弃会话数据 *************************************************************************************
十九、getSession()/getSession(true)、getSession(false)的区别 *************************************************************************************
getSession()/getSession(true):当session存在时返回该session,否则新建一个session并返回该对象 getSession(false):当session存在时返回该session,否则不会新建session,返回null *************************************************************************************
 二十、如何将信息于会话关联起来 *************************************************************************************   setAttribute会替换任何之前设定的值;如果想要在不提供任何代替的情况下移除某个值,则应使用removeAttribute。这个方法会触发所有实现了HttpSessionBindingListener接口的值的valueUnbound 方法。 *************************************************************************************
二十一、会话属性的类型有什么限制吗 *************************************************************************************
通常会话属性的类型只要是Object就可以了。除了null或基本类型,如int,double,boolean。如果要使用基本类型的值作为属性,必须将其转换为相应的封装类对象 *************************************************************************************
 二十二、如何废弃会话数据 *************************************************************************************
A.只移除自己编写的servlet创建的数据: 调用removeAttribute(“key”)将指定键关联的值废弃 B.删除整个会话(在当前Web应用中): 调用invalidate,将整个会话废弃掉。这样做会丢失该用户的所有会话数据,而非仅仅由我们 servlet或JSP页面创建的会话数据 C.将用户从系统中注销并删除所有属于他(或她)的会话 调用logOut,将客户从Web服务器中注销,同时废弃所有与该用户相关联的会话(每个Web应用至多一个)。这个操作有可能影响到服务器上多个不同的Web应用 *************************************************************************************
二十三、使用isNew来判断用户是否为新旧用户的错误做法 *************************************************************************************
public boolean isNew()方法如果会话尚未和客户程序(浏览器)发生任何联系,则这个方法返回true,这一般是因为会话是新建的,不是由输入的客户请求所引起的。但如果isNew返回false,只不过是说明他之前曾经访问该Web应用,并不代表他们曾访问过我们的servlet或JSP页面。因为session是与用户相关的,在用户之前访问的每一个页面都有可能创建了会话。因此isNew为false只能说用户之前访问过该Web应用,session可以是当前页面创建,也可能是由用户之前访问过的页面创建的。正确的做法是判断某个session中是否存在某个特定的key且其value是否正确 *************************************************************************************
二十四、Cookie的过期和Session的超时有什么区别 *************************************************************************************
会话的超时由服务器来维护,它不同于Cookie的失效日期。首先,会话一般基于驻留内存的cookie 不是持续性的cookie,因而也就没有截至日期。即使截取到JSESSIONID cookie,并为它设定一个失效日期发送出去。浏览器会话和服务器会话也会截然不同。 *************************************************************************************
二十五、session cookie和session对象的生命周期是一样的吗 *************************************************************************************
当用户关闭了浏览器虽然session cookie已经消失,但session对象仍然保存在服务器端 *************************************************************************************
二十六、是否只要关闭浏览器,session就消失了 *************************************************************************************
程序一般都是在用户做log off的时候发个指令去删除session,然而浏览器从来不会主动在关闭之前通知服务器它将要被关闭,因此服务器根本不会有机会知道浏览器已经关闭。服务器会一直保留这个会话对象直到它处于非活动状态超过设定的间隔为止。之所以会有这种错误的认识,是因为大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接到服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求报头,把原来的session id发送到服务器,则再次打开浏览器仍然能够找到原来的session。恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为session设置了一个失效时间,当距离客户上一次使用session的时间超过了这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。  由此我们可以得出如下结论:  关闭浏览器,只会是浏览器端内存里的session cookie消失,但不会使保存在服务器端的session对象消失,同样也不会使已经保存到硬盘上的持久化cookie消失。 *************************************************************************************
二十七、打开两个浏览器窗口访问应用程序会使用同一个session还是不同的session *************************************************************************************
通常session cookie是不能跨窗口使用的,当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的session id,这样我们信息共享的目的就达不到了。此时我们可以先把session id保存在persistent cookie中(通过设置session的最大有效时间),然后在新窗口中读出来,就可以得到上一个窗口的session id了,这样通过session cookie和persistent cookie的结合我们就可以实现了跨窗口的会话跟踪。 *************************************************************************************
 二十八、如何使用会话显示每个客户的访问次数 *************************************************************************************
由于客户的访问次数是一个整型的变量,但session的属性类型中不能使用int,double,boolean等基本类型的变量,所以我们要用到这些基本类型的封装类型对象作为session对象中属性的值  但像Integer是一种不可修改(Immutable)的数据结构:构建后就不能更改。这意味着每个请求都必须创建新的Integer对象,之后使用setAttribute来代替之前存在的老的属性的值。例如: HttpSession session = request.getSession(); SomeImmutalbeClass value = (SomeImmutableClass)session.getAttribute(“SomeIdentifier”); if (value= =null){ value = new SomeImmutableClass(…); // 新创建一个不可更改对象 }else{ value = new SomeImmutableClass(calculatedFrom(value)); // 对value重新计算后创建新的对象 } session.setAttribute(“someIdentifier”,value); // 使用新创建的对象覆盖原来的老的对象 *************************************************************************************
二十九、如何使用会话累计用户的数据 *************************************************************************************
使用可变的数据结构,比如数组、List、Map或含有可写字段的应用程序专有的数据结构。通过这种方式,除非首次分配对象,否则不需要调用setAttribute。例如 HttpSession session = request.getSession(); SomeMutableClass value = (SomeMutableClass)session.getAttribute(“someIdentifier”); if(value = = null){ value = new SomeMutableClass(…); session.setAttribute(“someIdentifier”,value); }else{ value.updateInternalAttribute(…); // 如果已经存在该对象则更新其属性而不需重新设置属性 } *************************************************************************************
三十、不可更改对象和可更改对象在会话数据更新时的不同处理 *************************************************************************************
不可更改对象因为一旦创建之后就不能更改,所以每次要修改会话中属性的值的时候,都需要调用setAttribute(“someIdentifier”,newValue)来代替原有的属性的值,否则属性的值不会被更新可更改对象因为其自身一般提供了修改自身属性的方法,所以每次要修改会话中属性的值的时候,只要调用该可更改对象的相关修改自身属性的方法就可以了。这意味着我们就不需要调用setAttribute方法了 *************************************************************************************

posted @ 2007-06-20 22:24 拐子 阅读(113) | 评论 (0)编辑

2007年6月7日

存储过程优化(转载)

一、适合读者对象:数据库开发程序员,数据库的数据量很多,涉及到对SP(存储过程)的优化的项目开发人员,对数据库有浓厚兴趣的人。  

  二、介绍:在数据库的开发过程中,经常会遇到复杂的业务逻辑和对数据库的操作,这个时候就会用SP来封装数据库操作。如果项目的SP较多,书写又没有一定的规范,将会影响以后的系统维护困难和大SP逻辑的难以理解,另外如果数据库的数据量大或者项目对SP的性能要求很,就会遇到优化的问题,否则速度有可能很慢,经过亲身经验,一个经过优化过的SP要比一个性能差的SP的效率甚至高几百倍。  

  三、内容:  

  1、开发人员如果用到其他库的Table或View,务必在当前库中建立View来实现跨库操作,最好不要直接使用“databse.dbo.table_name”,因为sp_depends不能显示出该SP所使用的跨库table或view,不方便校验。  

  2、开发人员在提交SP前,必须已经使用set showplan on分析过查询计划,做过自身的查询优化检查。  

  3、高程序运行效率,优化应用程序,在SP编写过程中应该注意以下几点:   

  a)SQL的使用规范:

   i. 尽量避免大事务操作,慎用holdlock子句,提高系统并发能力。

   ii. 尽量避免反复访问同一张或几张表,尤其是数据量较大的表,可以考虑先根据条件提取数据到临时表中,然后再做连接。

   iii. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该改写;如果使用了游标,就要尽量避免在游标循环中再进行表连接的操作。

   iv. 注意where字句写法,必须考虑语句顺序,应该根据索引顺序、范围大小来确定条件子句的前后顺序,尽可能的让字段顺序与索引顺序相一致,范围从大到小。

   v. 不要在where子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

   vi. 尽量使用exists代替select count(1)来判断是否存在记录,count函数只有在统计表中所有行数时使用,而且count(1)比count(*)更有效率。

   vii. 尽量使用“>=”,不要使用“>”。

   viii. 注意一些or子句和union子句之间的替换

   ix. 注意表之间连接的数据类型,避免不同类型数据之间的连接。

   x. 注意存储过程中参数和数据类型的关系。

   xi. 注意insert、update操作的数据量,防止与其他应用冲突。如果数据量超过200个数据页面(400k),那么系统将会进行锁升级,页级锁会升级成表级锁。   

  b)索引的使用规范:

   i. 索引的创建要与应用结合考虑,建议大的OLTP表不要超过6个索引。

   ii. 尽可能的使用索引字段作为查询条件,尤其是聚簇索引,必要时可以通过index index_name来强制指定索引

   iii. 避免对大表查询时进行table scan,必要时考虑新建索引。

   iv. 在使用索引字段作为条件时,如果该索引是联合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用。

   v. 要注意索引的维护,周期性重建索引,重新编译存储过程。  

  c)tempdb的使用规范:

   i. 尽量避免使用distinct、order by、group by、having、join、cumpute,因为这些语句会加重tempdb的负担。

   ii. 避免频繁创建和删除临时表,减少系统表资源的消耗。

   iii. 在新建临时表时,如果一次性插入数据量很大,那么可以使用select into代替create table,避免log,提高速度;如果数据量不大,为了缓和系统表的资源,建议先create table,然后insert。

   iv. 如果临时表的数据量较大,需要建立索引,那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中,这样才能保证系统能够很好的使用到该临时表的索引。

    v. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先truncate table,然后drop table,这样可以避免系统表的较长时间锁定。

    vi. 慎用大的临时表与其他大表的连接查询和修改,减低系统表负担,因为这种操作会在一条语句中多次使用tempdb的系统表。  

  d)合理的算法使用:   

  根据上面已提到的SQL优化技术和ASE Tuning手册中的SQL优化内容,结合实际应用,采用多种算法进行比较,以获得消耗资源最少、效率最高的方法。具体可用ASE调优命令:set statistics io on, set statistics time on , set showplan on 等

posted @ 2007-06-07 08:53 拐子 阅读(136) | 评论 (1)编辑

2007年6月5日

C#中处定义事件

 

 1/*
 2 * C#的一个自定义的事件
 3 */

 4using System;
 5namespace DefaultNamespace
 6{
 7    class DelegateClass
 8    {
 9        public delegate bool Comparator(int one,int two);//声明代理
10        public event Comparator onComparator;//定义事件
11        public void StartComparator()//事件触发方法,只要调用此方法,就会触发所有注册的事件
12        {
13            onComparator(3,4);
14        }

15    }

16    
17    class DelegateDemo
18    {
19        //??????
20        public bool SortAsceding(int one,int two)
21        {
22            //return one>two;
23            Console.WriteLine("SortAsceding:"+one+","+two);
24            return true;
25        }

26        //??????
27        public bool SortDescending(int one,int two)
28        {
29            //return two>one;
30            Console.WriteLine("SortDescending"+one+","+two);
31            return true;
32        }

33        
34        public static void Main(string[] args)
35        {
36            //代理类对象
37            DelegateClass dc=new DelegateClass();
38            //客户类对象
39            DelegateDemo dd=new DelegateDemo();
40            //注册事件
41            dc.onComparator+=new DelegateClass.Comparator(dd.SortAsceding);
42            dc.onComparator+=new DelegateClass.Comparator(dd.SortDescending);
43            dc.onComparator+=new DelegateClass.Comparator(dd.SortDescending);
44            dc.onComparator+=new DelegateClass.Comparator(dd.SortDescending);
45            //事件触发
46            dc.StartComparator();
47            
48        }

49    }

50}
    
51

posted @ 2007-06-05 09:23 拐子 阅读(62) | 评论 (0)编辑

2007年5月31日

.NET中的命名空间

A、以下两种形式相同:
      

namespace A

//-----------------------------------
namespace A.B
{
    
public class Demo
    
{}
}
但推荐使用第一种,这种形式正确反应了类的逻辑层次;
B、引入命名空间时,可以定义别名,如
using Alias=System.Xml
就可以使用Alias.类名来替代System.Xml.类名操作
C、引入命名空间分为全局引用和局部引用
using A;//全局引用,不包括在任何命名空间之中
namespace Demo
{
   
using B;//局部引用,只在当前Demo命名空间中引用有效,且必须置于开始位置
}

posted @ 2007-05-31 10:57 拐子 阅读(21) | 评论 (0)编辑

2007年2月1日

Unicode编码规范(摘抄)

http://www.aoxiang.org 2006-4-2 10:48:02
Unicode是一种字符编码规范 。

  先从ASCII说起。ASCII是用来表示英文字符的一种编码规范,每个ASCII字符占用1个字节(8bits)

  因此,ASCII编码可以表示的最大字符数是256,其实英文字符并没有那么多,一般只用前128个(最高位为0),其中包括了控制字符、数字、大小写字母和其他一些符号


  而最高位为1的另128个字符被成为“扩展ASCII”,一般用来存放英文的制表符、部分音标字符等等的一些其他符号,这种字符编码规范显然用来处理英文没有什么问题。(实际上也可以用来处理法文、德文等一些其他的西欧字符,但是不能和英文通用),但是面对中文、阿拉伯文之类复杂的文字,255个字符显然不够用

  于是,各个国家纷纷制定了自己的文字编码规范,其中中文的文字编码规范叫做“GB2312-80”,它是和ASCII兼容的一种编码规范,其实就是利用扩展ASCII没有真正标准化这一点,把一个中文字符用两个扩展ASCII字符来表示。

  但是这个方法有问题,最大的问题就是,中文文字没有真正属于自己的编码,因为扩展ASCII码虽然没有真正的标准化,但是PC里的ASCII码还是有一个事实标准的(存放着英文制表符),所以很多软件利用这些符号来画表格。这样的软件用到中文系统中,这些表格符就会被误认作中文字,破坏版面。而且,统计中英文混合字符串中的字数,也是比较复杂的,我们必须判断一个ASCII码是否扩展,以及它的下一个ASCII是否扩展,然后才“猜”那可能是一个中文字


  总之当时处理中文是很痛苦的。而更痛苦的是GB2312是国家标准,台湾当时有一个Big5编码标准,很多编码和GB是相同的,所以……,嘿嘿。

  这时候,我们就知道,要真正解决中文问题,不能从扩展ASCII的角度入手,也不能仅靠中国一家来解决。而必须有一个全新的编码系统,这个系统要可以将中文、英文、法文、德文……等等所有的文字统一起来考虑,为每个文字都分配一个单独的编码,这样才不会有上面那种现象出现。

  于是,Unicode诞生了。

  Unicode有两套标准,一套叫UCS-2(Unicode-16),用2个字节为字符编码,另一套叫UCS-4(Unicode-32),用4个字节为字符编码。

  以目前常用的UCS-2为例,它可以表示的字符数为2^16=65535,基本上可以容纳所有的欧美字符和绝大部分的亚洲字符


  UTF-8的问题后面会提到 。

  在Unicode里,所有的字符被一视同仁。汉字不再使用“两个扩展ASCII”,而是使用“1个Unicode”,注意,现在的汉字是“一个字符”了,于是,拆字、统计字数这些问题也就自然而然的解决了


  但是,这个世界不是理想的,不可能在一夜之间所有的系统都使用Unicode来处理字符,所以Unicode在诞生之日,就必须考虑一个严峻的问题:和ASCII字符集之间的不兼容问题。

  我们知道,ASCII字符是单个字节的,比如“A”的ASCII是65。而Unicode是双字节的,比如“A”的Unicode是0065,这就造成了一个非常大的问题:以前处理ASCII的那套机制不能被用来处理Unicode了


  另一个更加严重的问题是,C语言使用'\0'作为字符串结尾,而Unicode里恰恰有很多字符都有一个字节为0,这样一来,C语言的字符串函数将无法正常处理Unicode,除非把世界上所有用C写的程序以及他们所用的函数库全部换掉


  于是,比Unicode更伟大的东东诞生了,之所以说它更伟大是因为它让Unicode不再存在于纸上,而是真实的存在于我们大家的电脑中。那就是:UTF。

  UTF= UCS Transformation Format UCS转换格式,它是将Unicode编码规则和计算机的实际编码对应起来的一个规则。现在流行的UTF有2种:UTF-8和UTF-16


  其中UTF-16和上面提到的Unicode本身的编码规范是一致的,这里不多说了。而UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容


  UTF-8有点类似于Haffman编码,它将Unicode编码为00000000-0000007F的字符,用单个字节来表示;

    00000080-000007FF的字符用两个字节表示

    00000800-0000FFFF的字符用3字节表示

  因为目前为止Unicode-16规范没有指定FFFF以上的字符,所以UTF-8最多是使用3个字节来表示一个字符。但理论上来说,UTF-8最多需要用6字节表示一个字符。

  在UTF-8里,英文字符仍然跟ASCII编码一样,因此原先的函数库可以继续使用。而中文的编码范围是在0080-07FF之间,因此是2个字节表示(但这两个字节和GB编码的两个字节是不同的),用专门的Unicode处理类可以对UTF编码进行处理。

  下面说说中文的问题。

  由于历史的原因,在Unicode之前,一共存在过3套中文编码标准。

  GB2312-80,是中国大陆使用的国家标准,其中一共编码了6763个常用简体汉字。Big5,是台湾使用的编码标准,编码了台湾使用的繁体汉字,大概有8千多个。HKSCS,是中国香港使用的编码标准,字体也是繁体,但跟Big5有所不同。

  这3套编码标准都采用了两个扩展ASCII的方法,因此,几套编码互不兼容,而且编码区间也各有不同

  因为其不兼容性,在同一个系统中同时显示GB和Big5基本上是不可能的。当时的南极星、RichWin等等软件,在自动识别中文编码、自动显示正确编码方面都做了很多努力。

  他们用了怎样的技术我就不得而知了,我知道好像南极星曾经以同屏显示繁简中文为卖点。

  后来,由于各方面的原因,国际上又制定了针对中文的统一字符集GBK和GB18030,其中GBK已经在Windows、Linux等多种操作系统中被实现。

  GBK兼容GB2312,并增加了大量不常用汉字,还加入了几乎所有的Big5中的繁体汉字。但是GBK中的繁体汉字和Big5中的几乎不兼容。

  GB18030相当于是GBK的超集,比GBK包含的字符更多。据我所知目前还没有操作系统直接支持GB18030。

  谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词
  这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题:

  问题一:
  使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big
endian和UTF-8这几种编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢?

  我很早前就发现Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但这些标记是基于什么标准呢?

  问题