• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            首先,我們要明白的是,VC是通過ODBC來訪問Excel表格的,也就是說,VC將Excel表格,當作數據庫來處理。當然了,也可以通過讀以tab鍵隔開的文件來處理這樣的文件,但是,我還是更加愿意用讀取數據庫的方式來訪問Excel表格。
            第二,既然是數據庫,那么,就需要建立一個與該庫對應的dsn,這個,而且,在建立dsn之前,首先要確定,已經安裝了Excel的驅動。
            第三,要訪問數據庫中的表格,就要先打開該表格,如此,就需要一個與之對應的RecordSet。如此,有如下代碼:
            void CRWExcel::ReadFromExcel()
            {
                  CDatabase database;
                  CString sSql;
                  CString sItem1, sItem2;
                  CString sDriver;
                  CString sDsn;
                  CString sFile = "Demo.xls";// 將被讀取的Excel文件名
                                                 
                // 檢索是否安裝有Excel驅動 "Microsoft Excel Driver (*.xls)"
                  sDriver = GetExcelDriver();
                  if (sDriver.IsEmpty())
                  {
                      // 沒有發現Excel驅動
                      AfxMessageBox("沒有安裝Excel驅動!");
                      return;
                  }
                  // 創建進行存取的字符串
                  sDsn.Format("ODBC;DRIVER={%s};DSN='''';DBQ=%s", sDriver, sFile);

                  TRY
                  {
            // 打開數據庫,建立與這個Excel對應的Database
                      database.Open(NULL, false, false, sDsn);
                      CRecordset recset(&database);
            // 設置讀取的查詢語句.demo.xls并非文件名,需要在excel中進行//設置,具體文章最后有講
                      sSql = "SELECT Age, Name FROM DEMO.XLS";
                  // 執行查詢語句,打開表格
                      recset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly);
                      // 獲取查詢結果
                      while (!recset.IsEOF())
                      {
                          //讀取Excel內部數值
                          recset.GetFieldValue("Name ", sItem1);
                          recset.GetFieldValue("Age", sItem2);
                          // 移到下一行
                          recset.MoveNext();
                      }
                      // 關閉數據庫
                      database.Close();
                  }
                  CATCH(CDBException, e)
                  {
                      // 數據庫操作產生異常時...
                      AfxMessageBox("數據庫錯誤: " + e->m_strError);
                  }
                  END_CATCH;
            }
            需要注意的是,我們對我們的Excel表格需要進行一些處理,需要先選定我們要讀取的數據,之后,選擇插入>>名字>>之后,在輸入框中輸入我們在select語句中用到的表名。第二,需要設置列名,為我們選定部分的最前面的一行的數據。

            posted @ 2010-10-11 11:15 wrh 閱讀(8473) | 評論 (1)編輯 收藏

            最近一個項目需要把報表的表格導入excel,在網上找了一些方法,比較研究了一下,記在這里,備忘。

            表格例子如下:

            <table id="tableExcel" width="100%" border="1" cellspacing="0" cellpadding="0">
            <tr>
            <td colspan="5" align="center">html 表格導出道Excel</td>
            </tr>
            <tr>
            <td>列標題1</td>
            <td>列標題2</td>
            <td>類標題3</td>
            <td>列標題4</td>
            <td>列標題5</td>
            </tr>
            <tr>
            <td>aaa</td>
            <td>bbb</td>
            <td>ccc</td>
            <td>ddd</td>
            <td>eee</td>
            </tr>
            <tr>
            <td>AAA</td>
            <td>BBB</td>
            <td>CCC</td>
            <td>DDD</td>
            <td>EEE</td>
            </tr>
            <tr>
            <td>FFF</td>
            <td>GGG</td>
            <td>HHH</td>
            <td>III</td>
            <td>JJJ</td>
            </tr>
            </table>

             

            1、js的方法

            A、將整個表格拷貝到EXCEL中

            function method1(tableid) {
            var curTbl = document.getElementById(tableid);
            var oXL = new ActiveXObject("Excel.Application");
            var oWB = oXL.Workbooks.Add();
            var oSheet = oWB.ActiveSheet;
            var sel = document.body.createTextRange();
            sel.moveToElementText(curTbl);
            sel.select();
            sel.execCommand("Copy");
            oSheet.Paste();
            oXL.Visible = true;
            }

             B、讀取表格中每個單元到EXCEL中:

            function method2(tableid)
            {
            var curTbl = document.getElementById(tableid);
            var oXL = new ActiveXObject("Excel.Application");
            var oWB = oXL.Workbooks.Add();
            var oSheet = oWB.ActiveSheet;
            var Lenr = curTbl.rows.length;
            for (i = 0; i < Lenr; i++)
            {
                    var Lenc = curTbl.rows(i).cells.length;
            for (j = 0; j < Lenc; j++)
            {
            oSheet.Cells(i + 1, j + 1).value = curTbl.rows(i).cells(j).innerText;
            }
            }
            oXL.Visible = true;
            }

             c、把表格輸出到另一個頁面,然后存成cvs格式

             

            function getXlsFromTbl(inTblId, inWindow)
            {
            try {
            var allStr = "";
            var curStr = "";
            if (inTblId != null && inTblId != "" && inTblId != "null") {
            curStr = getTblData(inTblId, inWindow);
            }
            if (curStr != null) {
            allStr += curStr;
            }
            else {
            alert("你要導出的表不存在");
            return;
            }
            var fileName = getExcelFileName();
            doFileExport(fileName, allStr);
            }
            catch(e) {
            alert("導出發生異常:" + e.name + "->" + e.description + "!");
            }
            }
            function getTblData(inTbl, inWindow) {
            var rows = 0;
            var tblDocument = document;
            if (!!inWindow && inWindow != "") {
            if (!document.all(inWindow)) {
            return null;
            }
            else {
            tblDocument = eval(inWindow).document;
            }
            }
            var curTbl = tblDocument.getElementById(inTbl);
            var outStr = "";
            if (curTbl != null) {
            for (var j = 0; j < curTbl.rows.length; j++) {
            for (var i = 0; i < curTbl.rows[j].cells.length; i++) {
            if (i == 0 && rows > 0) {
            outStr += " \t";
            rows -= 1;
            }
            outStr += curTbl.rows[j].cells[i].innerText + "\t";
            if (curTbl.rows[j].cells[i].colSpan > 1) {
            for (var k = 0; k < curTbl.rows[j].cells[i].colSpan - 1; k++) {
            outStr += " \t";
            }
            }
            if (i == 0) {
            if (rows == 0 && curTbl.rows[j].cells[i].rowSpan > 1) {
            rows = curTbl.rows[j].cells[i].rowSpan - 1;
            }
            }
            }
            outStr += "\r\n";
            }
            }
            else {
            outStr = null;
            alert(inTbl + "不存在 !");
            }
            return outStr;
            }
            function getExcelFileName() {
            var d = new Date();
            var curYear = d.getYear();
            var curMonth = "" + (d.getMonth() + 1);
            var curDate = "" + d.getDate();
            var curHour = "" + d.getHours();
            var curMinute = "" + d.getMinutes();
            var curSecond = "" + d.getSeconds();
            if (curMonth.length == 1) {
            curMonth = "0" + curMonth;
            }
            if (curDate.length == 1) {
            curDate = "0" + curDate;
            }
            if (curHour.length == 1) {
            curHour = "0" + curHour;
            }
            if (curMinute.length == 1) {
            curMinute = "0" + curMinute;
            }
            if (curSecond.length == 1) {
            curSecond = "0" + curSecond;
            }
            var fileName = "table" + "_" + curYear + curMonth + curDate + "_"
            + curHour + curMinute + curSecond + ".csv";
            return fileName;
            }
            function doFileExport(inName, inStr) {
            var xlsWin = null;
            if (!!document.all("glbHideFrm")) {
            xlsWin = glbHideFrm;
            }
            else {
            var width = 6;
            var height = 4;
            var openPara = "left=" + (window.screen.width / 2 - width / 2)
            + ",top=" + (window.screen.height / 2 - height / 2)
            + ",scrollbars=no,width=" + width + ",height=" + height;
            xlsWin = window.open("", "_blank", openPara);
            }
            xlsWin.document.write(inStr);
            xlsWin.document.close();
            xlsWin.document.execCommand('Saveas', true, inName);
            xlsWin.close();
            }

             總結:比較上面3種方法,感覺第一種方法比較完美一些,因為這種方法比較完整的輸出表格的格式。但,第一和第二種方法都用了ActiveX 對象,對客戶端的安全有要求,而且最大的問題還有一個,就是excel 對象無法關閉。第3中方法雖然沒有用ActiveX 對象,但是用了彈出窗口輸出, 如果禁止了彈出窗口則無法使用。

            對于execl 對象無法關閉的問題,下面的方法是一個權宜方法:

            function Cleanup() {
            window.clearInterval(idTmr);
            CollectGarbage();
            }

             調用方法:

            idTmr = window.setInterval("Cleanup();",1);
            2、Asp.net(c#)中的方法
            這種方法其實類似上面的js的第3中方法(也可以在其他的web腳本來實現,比如asp中vbscript,或者php),把表格用文件流的方式
            輸出為excel。實例代碼如下:
            public void OutPutExcel(string title)
            {
            Response.Clear();
            Response.Buffer = true;
            Response.Charset = "utf-8";
            Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(title + ".xls"));
            Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
            Response.ContentType = "application/ms-excel";
            Page.EnableViewState = false;
            System.IO.StringWriter oStringWriter = new System.IO.StringWriter();
            System.Web.UI.HtmlTextWriter oHtmlTextWriter = new System.Web.UI.HtmlTextWriter(oStringWriter);
            this.Page.RenderControl(oHtmlTextWriter);
            string temp = oStringWriter.ToString();
            Response.Write(temp);
            Response.End();
            }
            這種方法的從本質上說并非標準的excel格式,不過把html格式的文件另存為excel的格式,然后用excel打開罷了。
            3、利用ExceL Application或者MSOWC 或者ado.net
            這種方法都是利用服務器的組件來時實現,要求服務端要安裝excel,具體的代碼可以看下面的鏈接:
            http://www.cnblogs.com/pucumt/archive/2006/09/13/503120.html
            http://support.microsoft.com/default.aspx?scid=kb;zh-cn;306023#top
            我不提倡用這種方法,因為需要占用服務器的資源。
            posted @ 2010-10-11 11:02 wrh 閱讀(2092) | 評論 (-1)編輯 收藏
            簡單明了比《Javascript之文件操作 (IE)》實用!


            <script>
            /*
            object.OpenTextFile(filename[, iomode[, create[, format]]])
            參數
            object
            必選項。object 應為 FileSystemObject 的名稱。
            filename
            必選項。指明要打開文件的字符串表達式。
            iomode
            可選項。可以是三個常數之一:ForReading 、 ForWriting 或 ForAppending 。
            create
            可選項。Boolean 值,指明當指定的 filename 不存在時是否創建新文件。如果創建新文件則值為 True ,如果不創建則為 False 。如果忽略,則不創建新文件。
            format
            可選項。使用三態值中的一個來指明打開文件的格式。如果忽略,那么文件將以 ASCII 格式打開。
            設置
            iomode 參數可以是下列設置中的任一種:
            常數 值         描述
            ForReading 1 以只讀方式打開文件。不能寫這個文件。
            ForWriting 2 以寫方式打開文件
            ForAppending 8 打開文件并從文件末尾開始寫。

            format 參數可以是下列設置中的任一種:
            值              描述
            TristateTrue 以 Unicode 格式打開文件。
            TristateFalse 以 ASCII 格式打開文件。
            TristateUseDefault 使用系統默認值打開文件。
            */

            //讀文件
            function readFile(filename){
            var fso = new ActiveXObject("Scripting.FileSystemObject");
            var f = fso.OpenTextFile(filename,1);
            var s = "";
            while (!f.AtEndOfStream)
            s += f.ReadLine()+"\n";
            f.Close();
            return s;
            }

            //寫文件
            function writeFile(filename,filecontent){
                var fso, f, s ;
                fso = new ActiveXObject("Scripting.FileSystemObject");   
                f = fso.OpenTextFile(filename,8,true);
                f.WriteLine(filecontent);  
                f.Close();
            alert('ok');
            }

            </script>
            <html>
            <input type="text" id="in" name="in" />
            <input type="button" value="Write!" onclick="writeFile('c:/12.txt',document.getElementById('in').value);"/><br><br>
            <input type="button" value="Read!" onclick="document.getElementById('show').value=readFile('c:/12.txt');"/><br>
            <textarea id="show" name="show" cols="50" rows="8" >
            </textarea>
            </html>
            posted @ 2010-10-09 14:25 wrh 閱讀(734) | 評論 (0)編輯 收藏
            概述

            在程序中經常要用到設置或者其他少量數據的存盤,以便程序在下一次執行的時候可以使用,比如說保存本次程序執行時窗口的位置、大小、一些用戶設置的數據等等,在 Dos 下編程的時候,我們一般自己產生一個文件,由自己把這些數據寫到文件中,然后在下一次執行的時候再讀出來使用。在 Win32 編程中當然你也可以這樣干,但 Windows 已經為我們提供了兩種方便的辦法,那就是使用注冊表或者 ini 文件(Profile)來保存少量數據。本文中先介紹一下 .ini 文件的使用。

            ini 文件是文本文件,中間的數據格式一般為:
            [Section1 Name]
            KeyName1=value1
            KeyName2=value2
            ...

            [Section2 Name]
            KeyName1=value1
            KeyName2=value2

            ini 文件可以分為幾個 Section,每個 Section 的名稱用 [] 括起來,在一個 Section 中,可以有很多的 Key,每一個 Key 可以有一個值并占用一行,格式是 Key=value,Win32 對 ini 文件操作的 api 中,有一部分是對 win.ini 操作的,有一部分是對用戶自定義的 ini 文件操作的。Win.in 和 system.ini 是Windows的兩個非常重要的初始化文件,Windows將用戶所作的選擇以及各種變化的系統信息記錄在這兩個文件中。System.ini 描述了系統硬件的當前狀態,Win.ini 文件則包含了Windows 系統運行環境的當前配置。由于 Win.ini 文件的重要性和常用性,Win32 中有專門對 Win.ini 進行操作的 api,它們是:

            GetProfileInt - 從 Win.ini 文件的某個 Section 取得一個 key 的整數值,它的原形是:

            GetProfileInt(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPCTSTR lpKeyName, // 指向包含 Key 名稱的字符串地址
            INT nDefault // 如果 Key 值沒有找到,則返回缺省的值是多少
            );

            如果 Key 值沒有找到的話,返回值是 nDefault 指定的缺省值,如果 Key 中的值是負數,則返回 0,如果 Key 指定的是數字和字符串的混合,則返回數字部分的值,比如說 x=1234abcd,則返回 1234


            GetProfileString - 從 Win.ini 文件的某個 Section 取得一個 key 的字符串,它的原形是:

            GetProfileString(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPCTSTR lpKeyName, // 指向包含 Key 名稱的字符串地址
            LPCTSTR lpDefault, // 如果 Key 值沒有找到,則返回缺省的字符串的地址
            LPTSTR lpReturnedString, // 返回字符串的緩沖區地址
            DWORD nSize // 緩沖區的長度
            );

            返回的字符串在緩沖區內,返回的 eax 值是返回的字符串的長度(不包括尾部的0)


            GetProfileSection - 從 Win.ini 文件中讀出整個 Section 的內容,它的原形是:

            GetProfileSection(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPTSTR lpReturnedString, // 返回數據的緩沖區地址
            DWORD nSize // 返回數據的緩沖區長度
            );


            WriteProfileSection - 將一個整個 Section 的值 寫入 Win.ini 文件的指定 Section 中,它的原形是:

            WriteProfileSection(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPCTSTR lpString // 要寫入的數據的地址
            );

            如果 Win.ini 沒有指定的 Section,API 會新建立一個并寫入數據,如果已經存在,則先刪除原來 Seciton 中所有的 Key 值然后寫入新的。


            WriteProfileString - 將一個 Key 值寫入 Win.ini 文件的指定 Section 中,它的原形是:

            WriteProfileString(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPCTSTR lpKeyName, // 指向包含 Key 名稱的字符串地址
            LPCTSTR lpString // 要寫的字符串地址
            );

            如果 Win.ini 沒有指定的 Section,API 會新建 Section,如果沒有指定的 Key 則新建一個 Key 并寫入數據,如果已經存在,則用字符串代替原來的值。
            以上的 Api 是對 Win.ini 操作的,當然對于我們來說,用的更多的是在程序運行的目錄中建立自己的 ini 文件,如果需要對自己的 ini 文件操作,就要用到另一組 Api,這一組 api 和上面的很象,只要把上面一組的 Profile 換成 PrivateProfile(私有的)就可以了,參數中也相應的多了一個 ini 文件名的參數。例如 GetPrivateProfileInt、GetPrivateProfileSection、WritePrivateProfileString 等等, 下面分別介紹:

            GetPrivateProfileInt - 從 ini 文件的某個 Section 取得一個 key 的整數值,它的原形是:

            GetPrivateProfileInt(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPCTSTR lpKeyName, // 指向包含 Key 名稱的字符串地址
            INT nDefault // 如果 Key 值沒有找到,則返回缺省的值是多少
            LPCTSTR lpFileName // ini 文件的文件名
            );

            中間參數和返回值的定義和 GetProfileInt 是一樣的。


            GetPrivateProfileString - 從 ini 文件的某個 Section 取得一個 key 的字符串,它的原形是:

            GetPrivateProfileString(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPCTSTR lpKeyName, // 指向包含 Key 名稱的字符串地址
            LPCTSTR lpDefault, // 如果 Key 值沒有找到,則返回缺省的字符串的地址
            LPTSTR lpReturnedString, // 返回字符串的緩沖區地址
            DWORD nSize // 緩沖區的長度
            LPCTSTR lpFileName // ini 文件的文件名
            );


            GetPrivateProfileSection - 從 ini 文件中讀出整個 Section 的內容,它的原形是:

            GetPrivateProfileSection(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPTSTR lpReturnedString, // 返回數據的緩沖區地址
            DWORD nSize // 返回數據的緩沖區長度
            LPCTSTR lpFileName // ini 文件的文件名
            );

            這個 api 可以讀出整個 section 的內容,當你不知道 section 中有哪些 key 的時候,可以使用這個 api 將整個 section 讀出后再處理。


            GetPrivateProfileSectionNames - 從 ini 文件中獲得 Section 的名稱,它的原形是:

            GetPrivateProfileSectionNames(
            LPTSTR lpszReturnBuffer, // 返回數據的緩沖區地址
            DWORD nSize // 返回數據的緩沖區長度
            LPCTSTR lpFileName // ini 文件的文件名
            );

            如果 ini 中有兩個 Section: [sec1] 和 [sec2],則返回的是 'sec1',0,'sec2',0,0 ,當你不知道 ini 中有哪些 section 的時候可以用這個 api 來獲取名稱


            WritePrivateProfileSection - 將一個整個 Section 的內容入 ini 文件的指定 Section 中,它的原形是:

            WritePrivateProfileSection(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPCTSTR lpString // 要寫入的數據的地址
            LPCTSTR lpFileName // ini 文件的文件名
            );


            WritePrivateProfileString - 將一個 Key 值寫入 ini 文件的指定 Section 中,它的原形是:

            WritePrivateProfileString(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPCTSTR lpKeyName, // 指向包含 Key 名稱的字符串地址
            LPCTSTR lpString // 要寫的字符串地址
            LPCTSTR lpFileName // ini 文件的文件名
            );

            如果 ini 中沒有指定的 Section,API 會新建 Section,如果沒有指定的 Key 則新建一個 Key 并寫入數據,如果已經存在,則用字符串代替原來的值。當指定的 ini 也不存在的時候,API 會自動建立一個新的文件,所以使用 ini 的好處是我們不必為了保存少量的數據涉及到文件操作,就連查找文件是否存在的操作都不必要。

            使用要點:

            在我們實際使用的時候,用的最多的是 GetPrivateProfileString 和 WritePrivateProfileString,但在對自定義 ini 文件操作的時候要注意的是,如果 lpFileName 指定的文件沒有路徑的話,Api 會去 Windows 的安裝目錄去找而不會在當前目錄找,但是每次用到 ini 函數要獲取當前路徑顯然太麻煩了,這里有一個變通的辦法,你只要在 ini 文件名前面加上 .\ 就可以了,比如說要對本目錄下的 user.ini 操作,那么文件名就是 '.\user.ini' 這樣顯然比較方便。另外,當你要把一個 Key 清除的時候,可以使用把 lpString 指向一個空的字符串然后使用 WritePrivateProfileString。當你要把一個 section 的全部內容清空的時候,也不必把 key 一個個的清除,可以使用把 lpString 指向一個空的字符串然后使用 WritePrivateProfileSection。
            posted @ 2010-09-03 09:27 wrh 閱讀(384) | 評論 (0)編輯 收藏

            得到運行程序所在路徑:(其實得到的是當前執行程序存放路徑)。

                   TCHAR szFilePath[MAX_PATH + 1];

                   GetModuleFileName(NULL, szFilePath, MAX_PATH);      

                   (_tcsrchr(szFilePath, _T('\\')))[1] = 0;

                   CString strtemp=szFilePath;

             

             

             

             

            函數說明:

            GetModuleFileName:The GetModuleFileName function retrieves the full path and filename for the executable file containing the specified module.

            得到程序當前工作路徑:(因為程序在運行過程中,會改變工作路徑)

                   char pBuf[MAX_PATH];                                 //存放路徑的變量      

                   GetCurrentDirectory(MAX_PATH,pBuf);                   //獲取程序的當前目錄

                   strcat(pBuf,"\\");

                   CString strtemp=pBuf;

             

             

            函數說明:

            GetCurrentDirectoryThe GetCurrentDirectory function retrieves the current directory for the current process

            posted @ 2010-08-21 13:43 wrh 閱讀(1804) | 評論 (0)編輯 收藏
            VC 移動,復制,刪除文件(SHFileOperation)

            總結一下SHFileOperation的用法,希望對大家有用

            //刪除文件或者文件夾
            bool DeleteFile(char * lpszPath)
            {
            SHFILEOPSTRUCT FileOp={0};
            FileOp.fFlags = FOF_ALLOWUNDO |   //允許放回回收站
                  FOF_NOCONFIRMATION; //不出現確認對話框
            FileOp.pFrom = lpszPath;
            FileOp.pTo = NULL;      //一定要是NULL
            FileOp.wFunc = FO_DELETE;    //刪除操作
            return SHFileOperation(&FileOp) == 0;
            }

            //復制文件或文件夾
            bool CopyFile(char *pTo,char *pFrom)
            {
            SHFILEOPSTRUCT FileOp={0};
            FileOp.fFlags = FOF_NOCONFIRMATION|   //不出現確認對話框
                  FOF_NOCONFIRMMKDIR ; //需要時直接創建一個文件夾,不需用戶確定
            FileOp.pFrom = pFrom;
            FileOp.pTo = pTo;
            FileOp.wFunc = FO_COPY;
            return SHFileOperation(&FileOp) == 0;
            }

            //移動文件或文件夾
            bool MoveFile(char *pTo,char *pFrom)
            {
            SHFILEOPSTRUCT FileOp={0};
            FileOp.fFlags = FOF_NOCONFIRMATION|   //不出現確認對話框
                  FOF_NOCONFIRMMKDIR ; //需要時直接創建一個文件夾,不需用戶確定
            FileOp.pFrom = pFrom;
            FileOp.pTo = pTo;
            FileOp.wFunc = FO_MOVE;
            return SHFileOperation(&FileOp) == 0;   
            }


            //從命名文件或文件夾
            bool ReNameFile(char *pTo,char *pFrom)
            {
            SHFILEOPSTRUCT FileOp={0};
            FileOp.fFlags = FOF_NOCONFIRMATION;   //不出現確認對話框
            FileOp.pFrom = pFrom;
            FileOp.pTo = pTo;
            FileOp.wFunc = FO_RENAME;
            return SHFileOperation(&FileOp) == 0;   
            }

            應用舉例:
            DeleteFile("d:\\PID\0\0");    //刪除一個文件夾
            DeleteFile("d:\\PID.dsp\0d:\\PID.dsw\0\0"); //刪除多個文件
            CopyFile("d:\0\0","D:\\MyProjects\\臨時程序\0\0");    //把"臨時程序"文件夾放到d盤下面
            CopyFile("d:\0\0","D:\\MyProjects\\臨時程序\\PID.dsp\0D:\\MyProjects\\臨時程序\\PID.dsw\0"); //把PID.dsp和PID.dsw倆個文件放到d盤下面
            ReNameFile("d:\\NewName","d:\\PID\0\0"); \\把PID文件夾從命名為NewName
            注意:,如果你想把"D:\\MyProjects\\臨時程序\0\0"的文件夾復制到D盤下,并從命名為NewName,應該這樣
            CopyFile("d:\\NewName\0\0","D:\\MyProjects\\臨時程序\\*.*\0\0"); //把"臨時程序"文件夾復制到d盤下并從命名為"NewName"  

             

            下面這個類方便你復制多個文件或文件夾,僅作參考
            //連接多個路徑的類
            class JOINFILEPATH
            {
            private:
            int pos;
            char* MultipleFilePath;
            public:
            JOINFILEPATH()
            {
               pos=0;
               MultipleFilePath=new char[MAX_PATH*10];
               memset(MultipleFilePath,0,MAX_PATH*10);
            }
            ~JOINFILEPATH() { delete []MultipleFilePath; }
            void join(char *FilePath)
            {
               while(*FilePath!='\0')
                MultipleFilePath[pos++]=*FilePath++;
               pos++;
            }
            char * GetMultipleFilePath() {return MultipleFilePath;}
            };

            //應用舉例:
            JOINFILEPATH FilePath;
            FilePath.join("D:\\MyProjects\\臨時程序\\PID\\PID.dsp");
            FilePath.join("D:\\MyProjects\\臨時程序\\PID\\PID.dsw");
            CopyFile("d:\0\0",FilePath.GetMultipleFilePath());

            1 pFrom和pTo最好以\0\0結尾(把存放路徑的字符串初始化為0),不然有可能會出錯,中間的每一個路徑用\0隔開
            2 pFrom所指向的文件或文件夾(可以多個)會被復制或移動到pTo所指向的文件夾下面(假如文件夾不存在會詢問是否創建,當然你也可以選擇直接創建)

            參數詳解:

            Typedef struct _ShFILEOPSTRUCT
            {
            HWND hWnd; //消息發送的窗口句柄;
            UINT wFunc; //操作類型
            LPCSTR pFrom; //源文件及路徑
            LPCSTR pTo; //目標文件及路徑
            FILEOP_FLAGS fFlags; //操作與確認標志
            BOOL fAnyOperationsAborted; //操作選擇位
            LPVOID hNameMappings; //文件映射
            LPCSTR lpszProgressTitle; //文件操作進度窗口標題
            }SHFILEOPSTRUCT, FAR * LPSHFILEOPSTRUCT;

              在這個結構中,hWnd是指向發送消息的窗口句柄,pFrom與pTo是進行文件操作的源文件名和目標文件名,它包含文件的路徑,對應單個文件的路徑字符串,或對于多個文件,必須以NULL作為字符串的結尾或文件路徑名之間的間隔,否則在程序運行的時候會發生錯誤。另外,pFrom和pTo都支持通配符*和?,這大大方便了開發人員的使用。例如,源文件或目錄有兩個,則應是:char pFrom[]="d:\\Test1\0d:\\Text.txt\0",它表示對要D:盤Test目錄下的所有文件和D:盤上的Text.txt文件進行操作。字符串中的"\\"是C語言中的'\'的轉義符,'\0'則是NULL。wFunc 是結構中的一個非常重要的成員,它代表著函數將要進行的操作類型,它的取值為如下:

              FO_COPY: 拷貝文件pFrom到pTo 的指定位置。

              FO_RENAME: 將pFrom的文件名更名為pTo的文件名。

              FO_MOVE: 將pFrom的文件移動到pTo的地方。

              FO_DELETE: 刪除pFrom指定的文件。

              使用該函數進行文件拷貝、移動或刪除時,如果需要的時間很長,則程序會自動在進行的過程中出現一個無模式的對話框(Windows操作系統提供的文件操作對話框),用來顯示執行的進度和執行的時間,以及正在拷貝、移動或刪除的文件名,此時結構中的成員lpszProgressTitle顯示此對話框的標題。fFlags是在進行文件操作時的過程和狀態控制標識。它主要有如下一些標識,也可以是其組合:

              FOF_FILESONLY:執行通配符,只執行文件;

              FOF_ALLOWUNDO:保存UNDO信息,以便在回收站中恢復文件;

              FOF_NOCONFIRMATION:在出現目標文件已存在的時候,如果不設置此項,則它會出現確認是否覆蓋的對話框,設置此項則自動確認,進行覆蓋,不出現對話框。

              FOF_NOERRORUI:設置此項后,當文件處理過程中出現錯誤時,不出現錯誤提示,否則會進行錯誤提示。

              FOF_RENAMEONCOLLISION:當已存在文件名時,對其進行更換文提示。

              FOF_SILENT:不顯示進度對話框。

              FOF_WANTMAPPINGHANDLE:要求SHFileOperation()函數返回正處于操作狀態的實際文件列表,文件列表名柄保存在hNameMappings成員中。

              SHFILEOPSTRUCT結構還包含一個SHNAMEMAPPING結構的數組,此數組保存由SHELL計算的每個處于操作狀態的文件的新舊路徑。

              在使用該函數刪除文件時必須設置SHFILEOPSTRUCT結構中的神秘FOF_ALLOWUNDO標志,這樣才能將待刪除的文件拷到Recycle Bin,從而使用戶可以撤銷刪除操作。需要注意的是,如果pFrom設置為某個文件名,用FO_DELETE標志刪除這個文件并不會將它移到Recycle Bin,甚至設置FOF_ALLOWUNDO標志也不行,在這里你必須使用全路徑名,這樣SHFileOperation才會將刪除的文件移到Recycle Bin。

            轉自http://blog.csdn.net/jhb92/archive/2007/04/13/1563452.aspx

            Shell的文件操作函數
            SHFileOperation
            功能:
            1.復制一個或多個文件
            2.刪除一個或多個
            3.重命名文件
            4.移動一個或多個文件

            有一樣的Win32API功能函數是:
            CopyFile(),DeleteFile(),MoveFile()
            MoveFile可以對文件重命名!
            Win32 API 的層次比SHFileOperation低

            SHFileOperation
            的重要參數
            1.wFunc //對pFrom pTo要執行的操作
            2.fFlags //影響對wFunx的操作
            3.hNameMappings   //有系統填充,和你也可以填充
            4.lpszProgressTitle

            pFrom pTo 在結尾是兩個'\0\0'
            通常用一個'\0',這樣會失敗的!!
            當FOF_MULTIDESTFILES
            szPFrom[lstrlen(szPFrom)+1]=0

            szPFrom:必須先確定他所指定的文件存在!
            可以是單個文件名,*.*,或包含統配符的文件名
            注意必須是文件名,不是文件所在的文件夾名
            szSource:可以是一個目錄,如果不是目錄,但又有
            多個文件,那么必須和szPFrom的每一個文件對應,還要指定
            FOF_MULTIDETFILES標志


            Source and Target
            多個文件---> 一個文件夾
            許多單獨的文件---->一個文件夾
            單獨文件--->單獨文件
            許多單獨的文件---->許多單獨的文件

            單獨文件:知道名字的文件
            多個文件:帶有統配符的文件
            注意到source中沒有對文件夾的操作!!


            !!!!
            SHFileOperation能操作網絡上的文件
            如果你想將本地文件復制到192.168.1.99
            那么只要在192.168.1.99上共享123目錄
            然后將pTo設置為\\192.168.1.99\123
            就可以了
            但不要設置為\\192.168.1.99


            對hNameMappings操作是Undocumented!!
            如果沒有指定hNameMappings
            那么hNameMappings一直是NULL
            只有當某種操作(copy,move,rename)引起了文件名沖突了,hNameMappings才不是NULL!!!
            當第一次copy某些文件到空目錄中時hNameMappings一定是NULL
            所以hNameMappings只是內存中的一塊地區用來讓Explorer.exe保存被重命名的文件,以避免文件名沖突!
            上面知道了如何才能使hNameMappings有效
            現在如何使用hNameMappings,及其所指的結構大小?并取得這個內存塊的內容呢?
            hNameMappings 是簡單LPVOID無法使用loop
            要使用hNameMappings,必須定義一個結構體
            struct HANDLETOMAPPINGS {
                UINT              uNumberOfMappings; // number of mappings in array
                LPSHNAMEMAPPING   lpSHNameMapping;    // pointer to array of mappings
            };
            但是可以寫一個Enumerate function to enumerate lpSHNameMapping指向的內存塊,并且是讓Window自己調用我的,不是我主動調用,象Loop

            相關聯接:
            Q154123:File Name Mapping with Windows NT 4.0 Shell
            Q133326:SHFILEOPSTRUCT pFrom and pTo Fields Incorrect
            Q142066:PRB: SHGetNameMappingPtr() and SHGetNameMappingCount()
            Manipulating Files with the SHFileOperation Function in Visual Basic 4.0

             

            FOF_SILENT //不產生正在復制的對話框
            FOF_NOCONFIRMMKDIR//如果目的目錄不存在,就默認創建
            FOF_NOCONFIRMATION //不出現確認文件替換對話框(Confirmation Dialog)(默認替換原來的文i件)
            FOF_NOERRORUI//不出現錯誤對話框
            最好不要同時使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR
            因為FOF_NOCONFIRMMKDIR屏蔽了missing directory Error
            但FOF_NOERROR又屏蔽了missing directory Error,那么在同時使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR
            時也阻止了新目錄安靜(沒有用戶確認要產生新目錄的對話框)的產生!!
            那么如何同時使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR?
            就必須先確認pTo所指定的目錄存在即可
            BOOL MakeSureDiretoryPathExists(LPCSTR DirPath);

            使用它要包含imagehlp.h和imagehlp.lib
            如何判斷同時存在FOF_NOERRORUI,FOF_NOCONFIRMMKDIR


            FOF_RENAMEONCOLLISION//有重復文件時自動重命名


            能產生對話框的標志:
            FOF_SILENT             //progress dialog           
            FOF_RENAMEONCOLLISION //replace dialog
            FOF_NOCONFIRMATION     //confirmation dialog
            FOF_NOCONFIRMMKDIR     //asks for your permission to create a new folder
            FOF_NOERRORUI          //error message


            FOF_ALLOWUNDO     //將文件放入回收站,否則直接刪除,一般這個最好做默認

            posted @ 2010-08-16 10:31 wrh 閱讀(3116) | 評論 (0)編輯 收藏
            C 標準提供一些函數用來檢查輸入輸出函數調用中的錯誤。

            13.6.1 ferror 函數

            在調用各種輸入輸出函數(如 putc, getc , fread, fwrite 等)時,日過出現錯誤,除了函數返回值有所反映外,還可以用 ferror 函數檢查。它的一般調用形式為   ferror(fp);   如果 ferror 函數返回值為0(假),表示未出錯;如果返回一個非零值,表示出錯。應該注意,對同一個文件每一次調用輸入輸出函數,均產生一個新的 ferror 函數值,因此,應當在調用一個輸入輸出函數后立即檢查 ferror 函數的值,否則信息會丟失。

               在執行 fopen 函數時,ferror 函數的初始值自動置為0。


            13.6.2   clearerr (清除錯誤) 函數

            clearerr 函數的作用是使文件錯誤標志和文件結束標志置為0。假設在調用一個輸入輸出函數時出現錯誤, ferror 函數值為一個非零值。在調用 clearerr
            (fp)后,ferror(fp)的值變成0。

            只要出現錯誤標志,就一直保留,直到對同一文件調用 clearerr 函數或(重新)rewind 函數,或任何其它一個輸入輸出函數。


             

                                          13.7 文件輸入輸出小結

               在本節中將以上介紹過的輸入輸出函數作一概括性的小結,以一目了然,便于查閱。下表列出常用的緩沖文件系統函數。

               分類             函數名                   功                                能

            打開文件         fopen()                        打開文件

            關閉文件         fclose()                        關閉文件

            文                    fseek()                         改變文件位置指針的位置
               件                   rewind()                       使文件位置指針重新置于文件開頭
            定位                ftell()                            返回文件位置指針的當前值
                                         
                    文           fgetc(),getc()                從指定文件取得一個字符

                   件           fputc(),putc()                把字符輸出到指定文件

                   讀               fgets()                           從指定文件讀取字符串

                   寫              fputs()                           把字符串輸出到指定文件

                                      getw()                           從指定文件讀取一個字(int)型

                                     putw()                          把一個字(int)型輸出到指定文件

                                     fread()                        從指定文件中讀取數據項

                                     fwrite()                       把數據項寫到指定文件

                                     fscanf()                        從指定文件按格式輸入數據

                                    fprintf()                         按指定格式將數據寫到指定文件中

               文                feof()                         若到文件末尾,函數值為“真”(非0)
               件                ferror()                      若對文件操作出錯,函數值為“真”(非0)
            狀態             clearerr()                   使 ferror 和 feof 函數值置零

             

            文件這一章的內容是很重要的,許多可供實際使用的 C 程序都包含文件處理
            .

            本章只介紹一些最基本的概念,由于篇幅所限,不可能舉復雜的例子。

             

            如何進行文件操作(程序如下)

            #include "stdio.h"
            main() /*先新建一個文件夾(file.txt),運行該程序后,就有輸入到文件中.*/
            {
               FILE *fp;
                int x,y,x1,y1,z;
                printf("please input two integer numbers:");
                scanf("%d %d",&x,&y);
                if((fp=fopen("file.txt","w"))==NULL) /*打開文件file.txt,準備往文件中寫入數據*/
                {
                     printf("cann't open file");
                       exit(0);
                }
                fprintf(fp,"%d %d",x,y); /*將x,y的值寫入文件*/
                fclose(fp);   /*關閉文件*/
                if((fp=fopen("file.txt","r"))==NULL) /*打開文件file.txt,準備從文件中讀出數據*/
                {
                       printf("cann't open file");
                       exit(0);

                }

            fscanf(fp,"%d %d",&x1,&y1); /*將剛才寫入的兩個整數分別讀到變量x1,y1中*/

            fclose(fp);   /*關閉文件*/

                z=x1+y1;    /*計算兩個數的和*/

                printf("z=%d",z);   /*顯示在屏幕上*/
            }

             

             

            file2.c 程序

            #include<stdlib.h>
            #include<stdio.h>
            void main()
            {
            FILE*in,*out;
            char ch,infile[10],outfile[10];
            printf("Enter the infile name:\n");
            scanf("%s",infile);
            printf("Enter the infile name:\n");
            scanf("%s",outfile);
            if((in=fopen(infile,"r"))==NULL)
            {
            printf("can not open infile\n");
            exit(0);
            }
            if((out=fopen(outfile,"w"))==NULL)
            {
            printf("can not open outfile\n");
            exit(0);
            }
            while(! feof(in)) fputc(fgetc(in),out);
            fclose(in);
            fclose(out);

            }

             

            file1(文本文檔里的內容)

            11 12

            posted @ 2010-08-13 08:51 wrh 閱讀(226) | 評論 (0)編輯 收藏

            文件打開之后,就可以對它進行讀寫了。常用的讀寫函數如下所述。

            13.4.1 fputc 函數和 fgetc 函數(putc 函數和 getc 函數)

            1. fputc 函數

            把一個字符寫到磁盤文件上去。其一般調用形式為

            fputc (ch,fp);

            其中ch 是要輸出的字符,它可以是一個字符常量,也可以是一個字符變量.
            fp 是文件指針變量。fputc (ch,fp) 函數的作用是將字符(ch的值)輸出到所指向的文件中去。fputc 函數也帶回一個值:如果輸出成功,則返回值就是輸出的字符;如果輸出失敗,則返回一個EOF(即—1)。EOF 是在 stdio.h 文件中定義的符號常量,值為—1。

                   在第4章介紹過 putchar 函數,其實 putchar 是從 fputc 函數派生出來的。putchar(c) 是在 stdio.h 文件中用預處理命令 #define 定義的宏:

                    #define   putchar(c)   fputc(c,stdout)

                前面已敘述,stdout   是系統定義的文件指針變量,它與終端輸出相聯.
            fputc(c,stdout)的作用是將 c 的值輸出到終端.用宏putchar(c)比寫fputc(c,stdout)
            簡單一些。從用戶的角度,可以把 putchar(c) 看作函數而不必嚴格地稱它為宏。

            2.fgetc 函數

            從指定的文件讀入一個字符,該文件必須是以讀或讀寫方式打開的。fgetc 函數的調用形式為: ch=fgetc(fp);

            fp 為文件型指針變量,ch 為字符變量。fgetc 函數帶回一個字符,賦給 ch。
            如果在執行 fgetc 函數讀字符時遇到文件結束符,函數返回一個文件結束標志EOF(即—1)。如果想從一個磁盤文件順序讀入字符并在屏幕上顯示出來,可以用:

            ch=fgetc(fp);
            while(ch!=EOF)
            {
            putchar(ch);
            ch=fgetc(fp);
            }

            注意:EOF 不是可輸出字符,因此不能在屏幕上顯示。由于字符的 ASCII 碼不可能出現—1,因此 EOF 定義為—1是合適的。當讀入的字符值等于—1(即EOF)時,表示讀入的已不是正常的字符而是文件結束符。但以上只適用于讀文本文件的情況。現在 ANSI C 已允許用緩沖文件系統處理二進制文件,而讀入某一個字節中的二進制數據的值有可能是—1,而這又恰好是EOF的值.
            這就出現了需要讀入有用數據而卻被處理為“文件結束”的情況。為了解決這個問題,ANSI C 提供一個 feof 函數來判斷文件是否真的結束。feof(fp)用來測試 fp 所指向的文件當前狀態是否“文件結束”。如果是文件結束,函數feof(fp)的值為1(真);否則為0(假)。

            如果想順序讀入一個二進制文件中的數據,可以用:

            while(! feof(fp))
            {
            c=fgetc(fp);
            ……
            }

            當未遇文件結束,feof(fp)的值為0,! feof(fp) 的值為1,讀入一個字節的數據賦給整型變量c,并接著對其進行所需的處理。直到遇文件結束,feof(fp)值為1,! feof(fp) 值為0,不再執行 while 循環.

            這種方法也適用于文本文件。

            3. fputc 和 fgetc函數使用舉例

            在掌握了以上幾種函數以后,可以編制一些簡單的使用文件的程序。

            例13 .1 從鍵盤輸入一些字符,逐個把它們送到磁盤上去,直到輸入一個“#”為止。程序如下: (本例有錯誤)
            #include "stdio.h"
            #include "stdlib.h"
            void main()
            {
                FILE * fp;
                char ch,filename[10];
                scanf("%s",filename);
                if((fp=fopen(filename,"W"))==NULL)
                 {
                 printf("cannot open file\n");
                 exit(0);
                 }
                 ch=getchar();
                 ch=getchar();
                 while(ch!='#')
                 {
                 fputc(ch,fp);
                 putchar(ch);
                 ch=getchar();
                 }
                 putchar(10);
                 fclose(fp);
            }
            運行結果是:
            輸入:file1.c
            cannot open file
            (不能打開文件)

            文件名由鍵盤輸入,賦給字符數組 filename。 fopen 函數中的第一個參數“文件名” 可以直接寫成字符串常量形式(如file1.c),也可以用字符數組名,在字符數組中存放文件名(如本例所用的方法)。本例運行時,從鍵盤輸入磁盤文件名 “file1.c” ,然后輸入要寫入該磁盤文件的字符“ computer and c”, '#' 是表示輸入結束,程序將 “ computer and c” 寫到以命名的磁盤文件中,同時在屏幕上顯示這些字符 ,以便核對。exit 是標準 C 的庫函數,作用是使程序終止,用此函數應當加入 stdlib 頭文件。

            例13.2 將一個磁盤文件中的信息復制到另一個磁盤文件中。
            (能運行,不能復制 )
            #include<stdlib.h>
            #include<stdio.h>
            void main()
            {
            FILE*in,*out;
            char ch,infile[10],outfile[10];
            printf("Enter the infile name:\n");
            scanf("%s",infile);
            printf("Enter the infile name:\n");
            scanf("%s",outfile);
            if((in=fopen(infile,"r"))==NULL)
            {
            printf("can not open infile\n");
            exit(0);
            }
            if((out=fopen(outfile,"w"))==NULL)
            {
            printf("can not open outfile\n");
            exit(0);
            }
            while(! feof(in)) fputc(fgetc(in),out);
            fclose(in);
            fclose(out);
            }

            運行情況如下:
            Enter the infile name:
            file1.txt      (輸入原有磁盤文件名)
            Enter the infile name:
            file2.txt      (輸入新復制的磁盤文件名)

            程序運行結果是將 file1.txt 文件中的內容復制到 file2.txt 中去。

            以上程序是按文本文件方式處理的。也可以用此程序來復制一個二進制文件,只需將兩個 fopen 函數中的 r 和 w 分別改為 rb 和 wb 即可。

            也可以在輸入命令行時把兩個文件名一起輸入。這時要用到 main 函數的參數。程序可改為:
            #include<stdlib.h>
            #include<stdio.h>
            void main(int agc,char *argv[])
            {
            FILE * in,* out;
            char ch;
            if(argc !=3)
            {
            printf("You forgot to enter a filename\n");
            exit(0);
            }
            if((in=fopen(argv[1],"r"))==NULL)
            {
               printf("cannot open infile\n");
            exit(0);
            }
            if((out=fopen(argv[2],"w"))==NULL)
            {
               printf("cannot open infile\n");
            exit(0);
            }
            while(! feof(in)) fputc(fgetc(in),out);
            fclose(in);
            fclose(out);
            }


            假若本程序的原文件名為 1.c 經編譯連接后得到的可執行文件名為 1.exe ,則在DOS命令工作方式下,可以輸入以下的命令行:C>1 file1.c file2.c 即在輸入可執行文件名后,再輸入兩個參數 file1.c 和 file2.c ,分別輸入到 argv[1]和 argv[2]中,argv[0]的內容為a,argc 的值等于3(因為此命令行共有3個參數) 。如果輸入的參數少于3個,則程序會輸出:“You forgot to enter a filename”
            (你忘了輸入一個文件名)。程序執行結果是將 file1.c 中的信息復制到 file2.c 中。可以用以下命令驗證:
            C>type file1.c
            computer and c
            (這是 file1.c 文件中的信息)

            C>type file2.c
            computer and c
            (這是 file2.c 文件中的信息。可見 file1.c已復制到 file2.c 中了)。

            最后說明一點,為了書寫方便,系統把 fputc 和 fgetc 定義為宏名putc 和getc:

            #define putc(ch,fp) fputc(ch,fp)
            #define getc(fp) fgetc(fp)

            這是在 stdio.h 中定義的。因此,用 putc 和 fputc 及用 getc 和 fgetc 是一樣的。一般可以把它們作為相同的函數來對待。


             


               13.4.2 fead 函數和 fwrite 函數

            用 getc 和 putc 函數可以用來讀寫文件中的一個字符。但是常常要求一次讀入一組數據(例如,一個實數或一個結構體變量的值),ANSI C 標準提出設置兩個函數(fead 函數和 fwrite 函數),用來讀寫一個數據塊。它們的一般調用形式為:

            fread(buffer,size,count,fp);
            fwrite(buffer,size,count,fp);

            其中:buffer:是一個指針.對 fread 來說,它是讀入數據的存放地址. 對fwrite 來說,
            是要輸出數據的地址(以上指的是起始地址)。

            size : 要讀寫的字節數。
            count: 要進行讀寫多少個 size 字節的數據項。
                  fp: 文件型指針。

            如果文件以二進制形式打開,用 fead 和 fwrite 函數就可以讀寫任何類型的信息,例如: fead(f,4,2,fp);      其中 f 是一個實型數組名。一個實型變量占4個字節。這個函數從所指向的文件讀入2個4個字節的數據,存儲到數組 f 中。
            如果有一個如下的結構體類型:

            struct student_type
            {
            char   name[10];
            int   num;
            int   age;
            char   addr[30];
            }stud[40];

            結構體數組 stud 有40個元素,每一個元素用來存放一個學生的數據(包括姓名、學號、年齡、地址)。假設學生的數據已存放在磁盤文件中,可以用下面的 for 語句和 fread 函數讀入40個學生的數據:

            for(i=0;i<40;i++)
            fread(&stud[i],sizeof(struct student_type),1,fp);

            同樣,以下 for 語句和 fwrite 函數可以將內存中的學生數據輸出到磁盤文件中去:

            for(i=0;i<40;i++)
            fwrite(&stud[i],sizeof(struct student_type),1,fp);

            如果 fead 和 fwrite 調用成功,則函數返回值為 count 的值,既輸入或輸出數據項的完整個數。

            下面寫出一個完整的程序。

            例13.3   從鍵盤輸入4個學生的有關數據,然后把它們轉存到磁盤文件上去。
            #include "stdio.h"
            #define SIZE 4
            struct student_type
            {char name[10];
            int age;
            int num;
            char addr[15];

            }stud[SIZE];
            void save()
            {
               FILE * fp;
               int i;
               if((fp=fopen("stu_list","wb"))==NULL)
               {
               printf("cannot open file\n");
               return;
               }
               for(i=0;i<SIZE;i++)
               if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)
                printf("file write error\n");
                fclose(fp);
            }
            void main()
            {
            int i;
            for(i=0;i<SIZE;i++)
            scanf("%s%d%d%s",stud[i].name,&stud[i].age,&stud[i].num,stud[i].addr);
            save();
            }

            在main 函數中,從終端鍵盤輸入4個學生的數據,然后調用 save 函數,將這些數據輸出到以 " stu_list "命名的磁盤文件中。fwrite 函數的作用是將一個
            長度為29字節數據塊送到 stu_list 文件中(一個 student_type 類型結構體變量的長度為它的成員長度之和,即10+2+2+15=29)。
            運行情況如下:
            輸入4個學生的姓名、學號、年齡和地址:

            Zhang 1001 18 room_101  
            Fun    1002 18   room_102        
            Tan      1003 18   room_103              
                Lin 1004   21   room_104

                程序運行時,屏幕上并無輸出任何信息,只是將從鍵盤輸入的數據送到此盤文件上。為了驗證在磁盤文件 “ stu_list ”中是否已存在此數據,可以用以下程序從 stu_list 文件中讀入數據,然后在屏幕上輸出。
            #include "stdio.h"
            #define SIZE 4
            struct student_type
            {
            int age;
            int num;
            char addr[15];
            char name[10];
            }stud[SIZE];
            void main()
            {
            int i;
            FILE * fp;
            fp=fopen("stu_list","rb");
            for(i=0;i<SIZE;i++)
            {
               fread(&stud[i],sizeof(struct student_type),1,fp);
            printf("%-10s %4d %4d %-15s\n",stud[i].name,&stud[i].age,&stud[i].num,stud[i].addr);
            }
            fclose(fp);
            }

            請注意:輸入輸出數據的狀況。從鍵盤輸入4個學生的數據是 ASCII 碼,也就是文本文件。在送到計算機內存時,回車和換行符轉換成一個換行符。再從內存以 “wb”方式(二進制寫)輸出到 stu_list 文件,此時不發生字符轉換,按內存中存儲形式原樣輸出到磁盤文件上。在上面驗證程序中,又用“fread ”函數從 stu_list 文件向內存讀入數據,注意此時用的是“rb” 方式,即二進制方式,數據按原樣輸入,也不發生字符轉換。也就是這時候內存中的數據恢復到第一個程序向 “ stu_list ” 輸出以前的情況。最后在驗證程序中,用printf 函數輸出到屏幕,printf 是格式輸出函數,輸出 ASCII 碼,在屏幕上顯示字符。換行符又轉換為回車加換行符。

            如果企圖從 “ stu_list ”文件中以 “r ”方式讀入數據就會出錯。

            fread 和 fwrire 函數一般用于二進制文件的輸入輸出。因為它們是按數據塊的長度來處理輸入輸出的,在字符發生轉換的情況下很可能出現與原設想的情況不同。 例如,寫成:fread(&stud[i],sizeof(struct student_type),1,stdin);   企圖從終端鍵盤輸入數據,這在語法上并不存在錯誤,編譯能通過。如果用以下形式輸入數據: Zhang 1001 18 room_101  
                                                       ……

            由于 fread 函數要求一次輸入29個字節(而不問這些字節的內容),因此輸入數據中的空格也作為輸入數據而不作為數據間的分隔符了。連空格也存儲到 stud[i] 中了,顯然是不對的。

            這個題目要求的是從鍵盤輸入數據,如果已有的數據已經以二進制形式存儲在一個磁盤文件 stu_dat 中,要求從其中讀入數據并輸出到 stu_list 文件中,可以編寫一個 load 函數,從磁盤文件中讀二進制數據。

            #include "stdio.h"
            #define SIZE 4
            struct student_type
            {
            int age;
            int num;
            char addr[15];
            char name[10];
            }stud[SIZE];
            void load()
            {
                              FILE * fp;
            int i;
            if((fp=fopen("stu_dat","rb"))==NULL)
            {
               printf("cannot open file\n");
               return;
                          }
               for(i=0;i<SIZE;i++)
               if(fread(&stud[i],sizeof(struct student_type),1,fp)!=1)
            { if(feof(fp))
            { fclose(fp);
                return;
            }
                printf("file write error\n");
            }
                fclose(fp);
            }
            main()
            {
            load();
            save();
            }

             


            13.4.3   fprintf (從文件中輸出) 函數和 fscanf (從文件中讀入) 函數

            fprintf 函數、fscanf 函數 與 printf 函數、scanf 函數作用相仿,都是格式讀寫函數。只有一點不同: fprintf 函數、fscanf 函數的讀寫對象不是終端而是磁盤文件。它們的一般調用方式為:

            fprintf (文件指針,格式字符串,輸出表列);
            fscanf (文件指針,格式字符串,輸入表列);

            例如:

            fprintf(fp,"%d,%6.2f",a,b);

            它的作用是將整型變量 a 和實型變量 b 的值按 %d 和 %6.2f 的格式輸出到 fp 指向的文件上。如果 i=3,t=4.5 則輸出到磁盤文件上的是以下的字符串:

            3, 4.50

            同樣,用以下函數可以從磁盤文件上讀入 ASCII 字符:

            fscanf(fp,"%d,%f",&a,&b);

            磁盤文件上如果有這樣的字符:3, 4.5   即將磁盤文件中的數據 3送給變量 a,4.5 送給變量 b。

            用 fprintf 和 fscanf 函數對磁盤文件讀寫,使用方便,容易理解,但由于在輸入時要將 ASCII 碼轉換為二進制形式,在輸出時又要將二進制形式轉換成字符,花費時間比較多。因此,在內存與磁盤頻繁交換數據的情況下,最好不用 fprintf 和 fscanf 函數,而用 fread(從文件中讀) 和 fwrite(往文件中寫) 函數。


             

                                                        13.4.4 其它讀寫函數
            1. putw 和 getw 函數

            大多數 C 編譯系統都提供另外兩個數:putw 和 getw 函數 ,用來對磁盤文件讀寫一個字(整數)。例如: putw(10,fp);     它的作用是將整數 10 輸出到 fp指向的文件。而 i=getw(fp);     的作用是從磁盤文件讀一個整數到內存,賦給整型變量 i。

            如果所用的 C 編譯系統的庫函數中不包括 putw 和 getw 函數,可以自己定義這兩個函數。putw 函數如下:

            putw(int i,FILE * fp)
            {
            char * s;                                      圖1:                     i
            s=&i;                                                       00000000    00001010
            putc(s[0],fp);                                                s[0]               s[1]
            putw(s[1],fp);
            return(i);
            }
            當調用 putw 函數時,如果用 putw(10,fp); 語句, 形參 i 得到實參傳來的值 10, 在 putw 函數中將 i 的地址賦予指針變量 s ,而 s 是指向字符變量的指針變量,因此 s 指向 i 的第 1 個字節,s+1 指向 i 的第 2 個字節。由于 * (s+0)就是 s[0],* (s+1)就是 s[1],因此,s[0]、s[1]分別對應的第 1 個字節和第 2 個字節。順序輸出s[0]、s[1]就相當于輸出了 i 的兩個字節中的內容,見圖1.
            getw 函數如下:

            getw(FILE * fp)
            {
            char * s;
            int   i;
            s=char * &i; /*使 s 指向 i 的起始地址 */
            s[0]=getc(fp);
            s[1]=getc(fp);
            return(i);
            }

            putw 和 getw 函數并不是 ANSI C 標準定義的函數。許多 C 編譯系統都提供這兩個,但有的不以 putw 和 getw 命名此兩函數,而用其它函數名,用時要注意。

            2. 讀寫其它類型數據

            如果用 ANSI C 提供的 fread 和 fwrite函數,讀寫任何類型數據都是十分方便的。如果所用的系統不提供這兩個函數,用戶只好自己定義所需函數。例如,可以定義一個向磁盤文件寫一個實數(用二進制方式)函數 putfloat:

            putfloat(float num,FILE * fp)
            {
            char * s;
            int count;
            s=(char *) &num;
            for(count=0;count<4,count++)
                putc(s[count],fp);
            }

            同樣可以編寫出讀寫任何類型數據的函數。

            3. fgets 函數和 fputs 函數

            fgets 函數的作用是從指定文件讀入一個字符串。例如:fgets (str,a,fp);   a 為要求得到的字符,但只從 fp指向的文件輸入 a-1 個字符,然后在最后加一個‘ \0 ’字符,因此得到的字符串共有 a 個字符,把它們放到字符數組 str 中.如果
            在讀完 a-1個字符之前遇到換行符或 EOF ,讀入即結束。 fgets 函數返回值為 str 的首地址。

               fputs 函數的作用是從指定文件輸出一個字符串。例如:fputs("Wolong",fp);
            把字符串 “ Wolong ” 輸出到 fp 指向的文件。fputs 函數中第一個參數可以是字符串常量、字符數組名或字符指針。 字符串末尾的‘ \0 ’ 不輸出。若輸出成功,函數值為 0;失敗時,為 EOF 。

                 這兩個函數類似以前介紹過的 gets 和 puts 函數, 只是 fgets 和 fputs 函數以指定的文件為讀寫對象。

            fgets(從文件中獲取字符串)

            fputs(往文件中寫字符串)

             

            如果所用的 C 編譯系統的庫函數中不包括 putw 和 getw 函數,可以自己定義這兩個函數。putw 函數如下:

            putw(int i,FILE * fp)
            {
            char * s;                                      圖1:                     i
            s=&i;                                                       00000000    00001010
            putc(s[0],fp);                                                s[0]               s[1]
            putw(s[1],fp);
            return(i);
            }
            當調用 putw 函數時,如果用 putw(10,fp); 語句, 形參 i 得到實參傳來的值 10, 在 putw 函數中將 i 的地址賦予指針變量 s ,而 s 是指向字符變量的指針變量,因此 s 指向 i 的第 1 個字節,s+1 指向 i 的第 2 個字節。由于 * (s+0)就是 s[0],* (s+1)就是 s[1],因此,s[0]、s[1]分別對應的第 1 個字節和第 2 個字節。順序輸出s[0]、s[1]就相當于輸出了 i 的兩個字節中的內容,見圖1.
            getw 函數如下:

            getw(FILE * fp)
            {
            char * s;
            int   i;
            s=char * &i; /*使 s 指向 i 的起始地址 */
            s[0]=getc(fp);
            s[1]=getc(fp);
            return(i);
            }


            如果用 ANSI C 提供的 fread 和 fwrite函數,讀寫任何類型數據都是十分方便的。如果所用的系統不提供這兩個函數,用戶只好自己定義所需函數。例如,可以定義一個向磁盤文件寫一個實數(用二進制方式)函數 putfloat:

            putfloat(float num,FILE * fp)
            {
            char * s;
            int count;
            s=(char *) &num;
            for(count=0;count<4,count++)
                putc(s[count],fp);
            }

            同樣可以編寫出讀寫任何類型數據的函數。


            例13.1從鍵盤輸入一些字符,逐個把它們送到磁盤上,直到輸入一個"#"為止.程序如下:
            #include<stdlib.h>
            #include<stdio.h>
            void main()
            {
            FILE*fp;
            char ch,filename[10];
            scanf("%s",filename);
            if((fp=fopen(filename,"w"))==NULL)
            {
            printf("can not open file\n");
            exit(0);/*終止程序*/
            }
            ch=getchar();/*接收輸入的一個字符*/
            ch=getchar();/*這一句可以省略.*/
            while(ch!='#')
            {
            fputc(ch,fp);putchar(ch);
            ch=getchar();
            }
            putchar(10);/*向屏幕輸出一個換行符*/
            fclose(fp);
            }
            運行后的結果:輸入:is a c# 輸出 a c

             

             

                                                    13.5     文件的定位

            文件中有一個位置指針,指向當前讀寫的位置。如果順序讀寫一個文件,每次讀寫一個字符,則讀寫完一個字符后,該位置指針自動移動指向下一個字符位置。如果想改變這樣的規律,強制使位置指針指向其它指定的位置,可以用后面介紹的有關函數。

            13.5.1 rewind 函數

            rewind 函數的作用是使位置指針重新返回文件的開頭,此函數沒有返回值。

            例13.4 有一個磁盤文件,第一次將它的內容顯示在屏幕上,第二次把它復制到另一文件上。
            #include "stdio.h"
            void main()
            {
            FILE * fp1,* fp2;
            fp1=fopen("file1.txt","r");
            fp2=fopen("file2.txt","w");
            while(! feof(fp1))
            putchar(getc(fp1));
            rewind(fp1);
            while(! feof(fp1))
            putc(getc(fp1),fp2);
            fclose(fp1);
            fclose(fp2);
            }
            (先在某一個位置上新建立一個文本文件,命名為file1.txt然后運行本程序(在vc編譯系統運行過))如:“ file1.txt ”里面的內容是:
                     Nu11              pointer              assignment
                  (無效的) ( 指示器)(分配、任務、作業)
            運行后的結果是:

            在第一次將內容顯示在屏幕上,file1.txt 的位置指針已指到文件末尾,feof 的值為零(真)。執行 rewind 函數 ,使文件的位置指針重新定位于文件開頭,并使 feof 函數的值恢復為0(假)。

            fopen (打開文件) fclose(文件關閉) rewind(重新) putchar(寫一個字符的函數)feof=end of file (文件末尾)   putc (輸出字符)

            posted @ 2010-08-13 08:50 wrh 閱讀(653) | 評論 (0)編輯 收藏

            對流式文件可以進行順序讀寫,也可以進行隨機讀寫,關鍵在于控制文件的位置指針。如果位置指針是按字節位置順序移動的,就是順序讀寫;如果能將位置指針按需要移動到任意的位置,就可以實現隨機讀寫.所謂隨機讀寫,是指讀寫完上一個字符(字節)后,并不一定要讀寫其后續的字符(字節),而可以讀寫文件中任意位置上所需要的字符(字節)。

            用 fseek 函數可以實現改變文件的位置指針。

            fseek 函數的調用形式為: fseek (文件類型指針,位移量,起始點)

            “起始點 ”用0、1或 2 代替,0代表 “文件開始”,1 為“當前位置”,2 為 “文件末尾”。 ANSI C 標準指定的名字如下表所示:

                    起始點                           名字                      用數字代表
                 文件開始                     SEEK_SET                          0
                 文件當前位置            SEEK_ CUR                        1                                                       
                 文件末尾                     SEEK_END                         2

            “位移量”指以 “起始點” 為基點,向前移動的字節數。ANSI C 和大多數版本要求位移量是(long)長整型數據。這樣當文件的長度大于64KB時不致出問題。ANSI C 標準規定在數字的末尾加一個字母 L,就表示是 long 型。

            fseek 函數一般用于二進制文件,因為文本文件要發生字符轉換,計算位置時往往會發生混亂。

            下面是fseek 函數調用的幾個例子:

            fseek(fp,100L,0);/* 將位置指針移到離文件頭100個字節處 */

            fseek(fp,50L,1); /* 將位置指針移到離當前位置50個字節處 */

            fseek(fp,--10L,2);/* 將位置指針從文件末尾處向后退 10 個字節 */

            利用 fseek 函數就可以實現隨機讀寫了。

            例13.5 在磁盤文件上存有 10 個學生的數據。要求將第 1、3、5、7、9個學生數據輸入計算機,并在屏幕上顯示出來。程序如下:

            #include "stdlib.h"
            #include "stdio.h"
            struct student_type
            {
            char name[10];
            int num;
            int age;
            char sex;
            }stud[10];
            void main()
            {
                int a;
                FILE * fp;
                if((fp=fopen("stud_dat.txt","rb"))==NULL)
                {
                printf("can not open file\n");
                exit(0);
                }
                for(a=0;a<10;a+=2)
                {
                fseek(fp,a * sizeof(struct student_type),0);
                fread(&stud[a],sizeof(struct student_type),1,fp);
                printf("%s %d %d %c\n",stud[a].name,stud[a].num,stud[a].age,stud[a].sex);
                }
                fclose(fp);
            }
            (先新建一個文本文件名為“stud_dat.txt”(可以改其它名字),然后在里面輸入10學生的數據。接著再把本程序在VC編譯系統中運行……)。


                                                    13.5.3 ftell 函數

               ftell 函數的作用是得到流式文件中的當前位置,用相對文件開頭的位移量來表示。由于文件中的位置指針經常移動,人們往往不容易知道其當前位置。
            用 ftell 函數可以得到當前位置 。如果 ftell 函數返回值為--1L,表示出錯。例如:
            a=ftell(fp);
            if(a==--1L)
            printf("error\n");

            變量 a 存放當前位置,如調用函數時出錯(如不存在 fp 文件),則輸出“error”。


                tell(告訴,吩咐,斷定,知道,)

             

            例13.4 有一個磁盤文件,第一次將它的內容顯示在屏幕上,第二次把它復制

            #include "stdio.h"
            void main()
            {
            FILE * fp1,* fp2;
            fp1=fopen("file1.txt","r");
            fp2=fopen("file2.txt","w");
            while(! feof(fp1))
            putchar(getc(fp1));
            rewind(fp1);
            while(! feof(fp1))
            putc(getc(fp1),fp2);
            fclose(fp1);
            fclose(fp2);
            }

             

            例13.5 在磁盤文件上存有 10 個學生的數據。要求將第 1、3、5、7、9個學

            #include "stdlib.h"
            #include "stdio.h"
            struct student_type
            {
            char name[10];
            int num;
            int age;
            char sex;
            }stud[10];
            void main()
            {
                int a;
                FILE * fp;
                if((fp=fopen("stud_dat.txt","rb"))==NULL)
                {
                printf("can not open file\n");
                exit(0);
                }
                for(a=0;a<10;a+=2)
                {
                fseek(fp,a * sizeof(struct student_type),0);
                fread(&stud[a],sizeof(struct student_type),1,fp);
                printf("%s %d %d %c\n",stud[a].name,stud[a].num,stud[a].age,stud[a].sex);
                }
                fclose(fp);
            }

             

             

            file1(文本文檔里的內容)

            Nu11              pointer              assignment
            (無效的) ( 指示器)(分配、任務、作業)

             

            stud_dat(文本文檔里的內容)

            Nu11              pointer              assignment
            (無效的) ( 指示器)(分配、任務、作業)

            Nu11              pointer              assignment
            (無效的) ( 指示器)(分配、任務、作業)

            Nu11              pointer              assignment
            (無效的) ( 指示器)(分配、任務、作業)

            Nu11              pointer              assignment
            (無效的) ( 指示器)(分配、任務、作業)

            Nu11              pointer              assignment
            (無效的) ( 指示器)(分配、任務、作業)

             

             

            posted @ 2010-08-13 08:49 wrh 閱讀(1925) | 評論 (0)編輯 收藏
            ASCII碼是7位編碼,字符在計算機中以其ASCII碼方式表示,其長度為1個字節, 有符號字符型數。編碼范圍是0x00-0x7F(0~127)。ASCII字符集包括英文字母、阿拉伯數字和標點符號等字符。其中0x00-0x20和0x7F共33個控制字符。

            ASCII 十六進制 控制字 代碼含義
            00           00            NUL      空
            01           01            SOH      標題開始
            02           02            STX      正文開始
            03           03            ETX      正文結束
            04           04            EOT         傳輸結否
            05           05            ENQ        詢問
            06           06            ACK        確認
            07           07            BEL         響鈴
            08           08            BS          退格
            09           09            HT          橫向列表
            10           0A            LF          換行
            11           0B             VT          縱向列表
            12           0C            FF             換頁
            13           0D            CR            回車
            14           0E            SO             換檔(Shift-Out)
            15           0F            SI             換檔(Shift-In)
            16           10            DLE         數據鏈擴展
            17           11            DC1         設備控制1
            18           12            DC2         設備控制2
            19           13            DC3         設備控制3
            20            14            DC4         設備控制4
            21           15            NAK         不確認
            22           16            SYN         同步字符
            23           17            ETB         傳輸塊結否
            24           18            CAN         作廢
            25           19            EM          介質結束
            26           1A            SUB         置換
            27           1B            ESC         擴展
            28           1C            FS             文件分隔符
            29           1D            GS          組分隔符
            30           1E            RS          記錄分隔符
            31           1F            US          單位分隔符

            ASCII碼對照表

            ASCII碼 鍵盤 ASCII 碼 鍵盤 ASCII 碼 鍵盤 ASCII 碼 鍵盤
            27 ESC 32 SPACE 33 ! 34 "
            35 # 36 $ 37 % 38 &
            39 ' 40 ( 41 ) 42 *
            43 + 44 ' 45 - 46 .
            47 / 48 0 49 1 50 2
            51 3 52 4 53 5 54 6
            55 7 56 8 57 9 58 :
            59 ; 60 < 61 = 62 >
            63 ? 64 @ 65 A 66 B
            67 C 68 D 69 E 70 F
            71 G 72 H 73 I 74 J
            75 K 76 L 77 M 78 N
            79 O 80 P 81 Q 82 R
            83 S 84 T 85 U 86 V
            87 W 88 X 89 Y 90 Z
            91 [ 92 \ 93 ] 94 ^
            95 _ 96 ` 97 a 98 b
            99 c 100 d 101 e 102 f
            103 g 104 h 105 i 106 j
            107 k 108 l 109 m 110 n
            111 o 112 p 113 q 114 r
            115 s 116 t 117 u 118 v
            119 w 120 x 121 y 122 z
            123 { 124 | 125 } 126 ~

            只支持ASCII碼的系統會忽略每個字節的最高位,只認為低7位是有效位。HZ字符編碼就是早期為了在只支持7位ASCII系統中傳輸中文而設計的編碼。早期很多郵件系統也只支持ASCII編碼,為了傳輸中文郵件必須使用BASE64或者其他編碼方式。


            GB2312字符集編碼


            GB2312 是漢字字符集和編碼的代號,中文全稱為“信息交換用漢字編碼字符集”,由中華人民共和國國家標準總局發布,一九八一年五月一日實施。GB 是“國標” 二字的漢語拼音縮寫。

            GB2312 字符集 (character set) 只收錄簡化字漢字,以及一般常用字母和符號,主要通行于中國大陸地區和新加坡等地。GB2312 共收錄有 7445 個字符,其中簡化漢字 6763 個,字母和符號 682 個。

            GB2312 將所收錄的字符分為 94 個區,編號為 01 區至 94 區;每個區收錄 94 個字符,編號為 01 位至 94 位。GB2312 的每一個字符都由與其唯一對應的區號和位號所確定。例如:漢字“啊”,編號為 16 區 01 位。

            GB2312 字符集的區位分布表:

            區號    字數    字符類別
            01      94    一般符號
            02      72    順序號碼
            03      94    拉丁字母
            04      83    日文假名
            05      86    Katakana
            06      48    希臘字母
            07      66    俄文字母
            08      63    漢語拼音符號
            09      76    圖形符號
            10-15            備用區
            16-55    3755    一級漢字,以拼音為序
            56-87    3008    二級漢字,以筆劃為序
            88-94            備用區

            這本手冊列出了 GB2312 的全部字符和它們的區位號。

            GB2312 編碼

            GB2312 原始編碼 (encoding) 是對所收錄的每個字符都用兩個字節 (byte) 表示。第一字節為“高字節”,由字符的區號值加上 32 而形成;第二字節為“低字節”,由字符的位號值加上 32 而形成。例如:漢字“啊”,編號為 16 區 01 位。它的高字節為 16 + 32 = 48 (0x30),低字節為 01 + 32 = 33 (0x21),合并而成的編碼為 0x3021。

            在區位號值上加 32 的原因大慨是為了避開低值字節區間。

            由于 GB2312 原始編碼與 ASCII 編碼的字節有重疊,現在通行的 GB2312 編碼是在原始編碼的兩個字節上各加 128 修改而形成。例如:漢字“啊”,編號為 16 區 01 位。它的原始編碼為 0x3021,通行編碼為 0xB0A1。

            如果不另加說明,GB2312 常指這種修改過的編碼。

            GB2312的編碼范圍是0xA1A1-0x7E7E,去掉未定義的區域之后可以理解為實際編碼范圍是0xA1A1-0xF7FE。

            上面這句有誤,應該說GB2312的每一個漢字由兩個字節構成,其中每一個字節的范圍都在0xA1 ~0xFE,正好每一個字節都有94個編碼范圍,與區位碼個數完全對應。

            EUC-CN可以理解為GB2312的別名,和GB2312完全相同。

            區位碼更應該認為是字符集的定義,定義了所收錄的字符和字符位置,而GB2312及EUC-CN是實際計算機環境中支持這種字符集的編碼。HZ和 ISO-2022-CN是對應區位碼字符集的另外兩種編碼,都是用7位編碼空間來支持漢字。區位碼和GB2312編碼的關系有點像 Unicode和UTF-8。

            GBK字符集編碼

            GBK 編碼是GB2312編碼的超集,向下完全兼容GB2312,同時GBK收錄了Unicode基本多文種平面中的所有CJK漢字。同 GB2312一樣,GBK也支持希臘字母、日文假名字母、俄語字母等字符,但不支持韓語中的表音字符(非漢字字符)。GBK還收錄了GB2312不包含的 漢字部首符號、豎排標點符號等字符。

            GBK的整體編碼范圍是為高字節范圍是0×81-0xFE,低字節范圍是0x40-7E和0x80-0xFE,不包括低字節是0×7F的組合。

            低字節是0x40-0x7E的GBK字符有一定特殊性,因為這些字符占用了ASCII碼的位置,這樣會給一些系統帶來麻煩。

            有些系統中用0x40-0x7E中的字符(如“|”)做特殊符號,在定位這些符號時又沒有判斷這些符號是不是屬于某個 GBK字符的低字節,這樣就會造成錯誤判斷。在支持GB2312的環境下就不存在這個問題。需要注意的是支持GBK的環境中小于0x80的某個字節未必就 是ASCII符號;另外就是最好選用小于0×40的ASCII符號做一些特殊符號,這樣就可以快速定位,且不用擔心是某個漢字的另一半。Big5編碼中也 存在相應問題。
            CP936和GBK的有些許差別,絕大多數情況下可以把CP936當作GBK的別名。

            GB18030字符集編碼

            GB18030編碼向下兼容GBK和GB2312,兼容的含義是不僅字符兼容,而且相同字符的編碼也相同。GB18030收錄了所有Unicode3.1中的字符,包括中國少數民族字符,GBK不支持的韓文字符等等,也可以說是世界大多民族的文字符號都被收錄在內。

            GBK和GB2312都是雙字節等寬編碼,如果算上和ASCII兼容所支持的單字節,也可以理解為是單字節和雙字節混合的變長編碼。GB18030編碼是變長編碼,有單字節、雙字節和四字節三種方式。

            GB18030 的單字節編碼范圍是0x00-0x7F,完全等同與ASCII;雙字節編碼的范圍和GBK相同,高字節是0x81-0xFE,低字節的編碼范圍是0x40 -0x7E和0x80-FE;四字節編碼中第一、三字節的編碼范圍是0x81-0xFE,二、四字節是0x30-0x39。

            Windows 中CP936代碼頁使用0x80來表示歐元符號,而在GB18030編碼中沒有使用0x80編碼位,用其他位置來表示歐元符號。這可以理解為是 GB18030向下兼容性上的一點小問題;也可以理解為0x80是CP936對GBK的擴展,而GB18030只是和GBK兼容良好。

            unicode字符集編碼

               每一種語言的不同的編碼頁,增加了那些需要支持不同語言的軟件的復雜度。因而人們制定了一個世界標準,叫做unicode。unicode為每個字符 提供 了唯一的特定數值,不論在什么平臺上、不論在什么軟件中,也不論什么語言。也就是說,它世界上使用的所有字符都列出來,并給每一個字符一個唯一特定數值。

            Unicode的最初目標,是用1個16位的編碼來為超過65000字符提供映射。但這還不夠,它不能覆蓋全部歷史上的文字,也不能解決傳輸的問題 (implantation head-ache's),尤其在那些基于網絡的應用中。已有的軟件必須做大量的工作來程序16位的數據。
            因 此,Unicode用一些基本的保留字符制定了三套編碼方式。它們分別是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是 以8位序列來編碼的,用一個或幾個字節來表示一個字符。這種方式的最大好處,是UTF-8保留了ASCII字符的編碼做為它的一部分,例如,在UTF-8 和ASCII中,“A”的編碼都是0x41.

            UTF-16和UTF-32分別是Unicode的16位和32位編碼方式。考慮到最初的目的,通常說的Unicode就是指UTF-16。在討論Unicode時,搞清楚哪種編碼方式非常重要。

            UTF-8字符集編碼

            Unicode Transformation Format-8bit,允許含BOM,但通常不含BOM。是用以解決國際上字符的一種多字節編碼,它對英文使用8位(即一個字節),中文使用24為(三 個字節)來編碼。UTF-8包含全世界所有國家需要用到的字符,是國際編碼,通用性強。UTF-8編碼的文字可以在各國支持UTF8字符集的瀏覽器上顯 示。如,如果是UTF8編碼,則在外國人的英文IE上也能顯示中文,他們無需下載IE的中文語言支持包。

            GBK的文字編碼是用雙字節來表示的,即不論中、英文字符均使用雙字節來表示,為了區分中文,將其最高位都設定成1。GBK包含全部中文字符,是國家編碼,通用性比UTF8差,不過UTF8占用的數據庫比GBD大。

            GBK、GB2312等與UTF8之間都必須通過Unicode編碼才能相互轉換

            GBK、GB2312--Unicode--UTF8

            UTF8--Unicode--GBK、GB2312

            對于一個網站、論壇來說,如果英文字符較多,則建議使用UTF-8節省空間。不過現在很多論壇的插件一般只支持GBK。
            posted @ 2010-08-06 10:25 wrh 閱讀(1243) | 評論 (0)編輯 收藏
            僅列出標題
            共25頁: First 6 7 8 9 10 11 12 13 14 Last 

            導航

            <2011年3月>
            272812345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            統計

            常用鏈接

            留言簿(19)

            隨筆檔案

            文章檔案

            收藏夾

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久免费精品视频| 久久久久亚洲AV无码永不| 久久WWW免费人成—看片| 九九久久精品国产| 伊人久久大香线蕉av不卡| 国产精品国色综合久久| 国产综合精品久久亚洲| 三级三级久久三级久久| 精品综合久久久久久97超人| 热综合一本伊人久久精品| 久久夜色精品国产欧美乱| 久久亚洲av无码精品浪潮| 久久精品一本到99热免费| 亚洲国产精品成人久久蜜臀| 精品久久久久久亚洲精品 | 97精品国产91久久久久久| 久久93精品国产91久久综合| 性欧美丰满熟妇XXXX性久久久| 久久久久国产日韩精品网站| 久久婷婷成人综合色综合| 久久久久亚洲AV无码专区首JN | 亚洲а∨天堂久久精品9966| 精品久久8x国产免费观看| 久久婷婷五月综合色奶水99啪| 国产一区二区精品久久凹凸| 国产精品一区二区久久| 99久久精品国产一区二区| 久久久噜噜噜久久| 精品久久久久久无码人妻蜜桃 | 久久亚洲中文字幕精品一区| 久久久久久久99精品免费观看| 天天躁日日躁狠狠久久| 久久人人爽人人人人片av| 国产精品久久久久久久久软件| 中文字幕久久精品| 狠狠色丁香婷婷久久综合五月| 伊人久久大香线蕉成人| 狠狠色丁香婷婷久久综合五月| 亚洲人成无码久久电影网站| 亚洲综合久久久| 亚洲AV无码久久精品成人|