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

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

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

            最近一個(gè)項(xiàng)目需要把報(bào)表的表格導(dǎo)入excel,在網(wǎng)上找了一些方法,比較研究了一下,記在這里,備忘。

            表格例子如下:

            <table id="tableExcel" width="100%" border="1" cellspacing="0" cellpadding="0">
            <tr>
            <td colspan="5" align="center">html 表格導(dǎo)出道Excel</td>
            </tr>
            <tr>
            <td>列標(biāo)題1</td>
            <td>列標(biāo)題2</td>
            <td>類標(biāo)題3</td>
            <td>列標(biāo)題4</td>
            <td>列標(biāo)題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、將整個(gè)表格拷貝到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、讀取表格中每個(gè)單元到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、把表格輸出到另一個(gè)頁面,然后存成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("你要導(dǎo)出的表不存在");
            return;
            }
            var fileName = getExcelFileName();
            doFileExport(fileName, allStr);
            }
            catch(e) {
            alert("導(dǎo)出發(fā)生異常:" + 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();
            }

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

            對(duì)于execl 對(duì)象無法關(guān)閉的問題,下面的方法是一個(gè)權(quán)宜方法:

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

             調(diào)用方法:

            idTmr = window.setInterval("Cleanup();",1);
            2、Asp.net(c#)中的方法
            這種方法其實(shí)類似上面的js的第3中方法(也可以在其他的web腳本來實(shí)現(xiàn),比如asp中vbscript,或者php),把表格用文件流的方式
            輸出為excel。實(shí)例代碼如下:
            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();
            }
            這種方法的從本質(zhì)上說并非標(biāo)準(zhǔn)的excel格式,不過把html格式的文件另存為excel的格式,然后用excel打開罷了。
            3、利用ExceL Application或者M(jìn)SOWC 或者ado.net
            這種方法都是利用服務(wù)器的組件來時(shí)實(shí)現(xiàn),要求服務(wù)端要安裝excel,具體的代碼可以看下面的鏈接:
            http://www.cnblogs.com/pucumt/archive/2006/09/13/503120.html
            http://support.microsoft.com/default.aspx?scid=kb;zh-cn;306023#top
            我不提倡用這種方法,因?yàn)樾枰加梅?wù)器的資源。
            posted @ 2010-10-11 11:02 wrh 閱讀(2085) | 評(píng)論 (-1)編輯 收藏
            簡(jiǎn)單明了比《Javascript之文件操作 (IE)》實(shí)用!


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

            format 參數(shù)可以是下列設(shè)置中的任一種:
            值              描述
            TristateTrue 以 Unicode 格式打開文件。
            TristateFalse 以 ASCII 格式打開文件。
            TristateUseDefault 使用系統(tǒng)默認(rèn)值打開文件。
            */

            //讀文件
            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 閱讀(732) | 評(píng)論 (0)編輯 收藏
            概述

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

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

            [Section2 Name]
            KeyName1=value1
            KeyName2=value2

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

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

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

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


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

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

            返回的字符串在緩沖區(qū)內(nèi),返回的 eax 值是返回的字符串的長(zhǎng)度(不包括尾部的0)


            GetProfileSection - 從 Win.ini 文件中讀出整個(gè) Section 的內(nèi)容,它的原形是:

            GetProfileSection(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPTSTR lpReturnedString, // 返回?cái)?shù)據(jù)的緩沖區(qū)地址
            DWORD nSize // 返回?cái)?shù)據(jù)的緩沖區(qū)長(zhǎng)度
            );


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

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

            如果 Win.ini 沒有指定的 Section,API 會(huì)新建立一個(gè)并寫入數(shù)據(jù),如果已經(jīng)存在,則先刪除原來 Seciton 中所有的 Key 值然后寫入新的。


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

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

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

            GetPrivateProfileInt - 從 ini 文件的某個(gè) Section 取得一個(gè) key 的整數(shù)值,它的原形是:

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

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


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

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


            GetPrivateProfileSection - 從 ini 文件中讀出整個(gè) Section 的內(nèi)容,它的原形是:

            GetPrivateProfileSection(
            LPCTSTR lpAppName, // 指向包含 Section 名稱的字符串地址
            LPTSTR lpReturnedString, // 返回?cái)?shù)據(jù)的緩沖區(qū)地址
            DWORD nSize // 返回?cái)?shù)據(jù)的緩沖區(qū)長(zhǎng)度
            LPCTSTR lpFileName // ini 文件的文件名
            );

            這個(gè) api 可以讀出整個(gè) section 的內(nèi)容,當(dāng)你不知道 section 中有哪些 key 的時(shí)候,可以使用這個(gè) api 將整個(gè) section 讀出后再處理。


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

            GetPrivateProfileSectionNames(
            LPTSTR lpszReturnBuffer, // 返回?cái)?shù)據(jù)的緩沖區(qū)地址
            DWORD nSize // 返回?cái)?shù)據(jù)的緩沖區(qū)長(zhǎng)度
            LPCTSTR lpFileName // ini 文件的文件名
            );

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


            WritePrivateProfileSection - 將一個(gè)整個(gè) Section 的內(nèi)容入 ini 文件的指定 Section 中,它的原形是:

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


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

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

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

            使用要點(diǎn):

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

            得到運(yùn)行程序所在路徑:(其實(shí)得到的是當(dāng)前執(zhí)行程序存放路徑)。

                   TCHAR szFilePath[MAX_PATH + 1];

                   GetModuleFileName(NULL, szFilePath, MAX_PATH);      

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

                   CString strtemp=szFilePath;

             

             

             

             

            函數(shù)說明:

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

            得到程序當(dāng)前工作路徑:(因?yàn)槌绦蛟谶\(yùn)行過程中,會(huì)改變工作路徑)

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

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

                   strcat(pBuf,"\\");

                   CString strtemp=pBuf;

             

             

            函數(shù)說明:

            GetCurrentDirectoryThe GetCurrentDirectory function retrieves the current directory for the current process

            posted @ 2010-08-21 13:43 wrh 閱讀(1800) | 評(píng)論 (0)編輯 收藏
            VC 移動(dòng),復(fù)制,刪除文件(SHFileOperation)

            總結(jié)一下SHFileOperation的用法,希望對(duì)大家有用

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

            //復(fù)制文件或文件夾
            bool CopyFile(char *pTo,char *pFrom)
            {
            SHFILEOPSTRUCT FileOp={0};
            FileOp.fFlags = FOF_NOCONFIRMATION|   //不出現(xiàn)確認(rèn)對(duì)話框
                  FOF_NOCONFIRMMKDIR ; //需要時(shí)直接創(chuàng)建一個(gè)文件夾,不需用戶確定
            FileOp.pFrom = pFrom;
            FileOp.pTo = pTo;
            FileOp.wFunc = FO_COPY;
            return SHFileOperation(&FileOp) == 0;
            }

            //移動(dòng)文件或文件夾
            bool MoveFile(char *pTo,char *pFrom)
            {
            SHFILEOPSTRUCT FileOp={0};
            FileOp.fFlags = FOF_NOCONFIRMATION|   //不出現(xiàn)確認(rèn)對(duì)話框
                  FOF_NOCONFIRMMKDIR ; //需要時(shí)直接創(chuàng)建一個(gè)文件夾,不需用戶確定
            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;   //不出現(xiàn)確認(rèn)對(duì)話框
            FileOp.pFrom = pFrom;
            FileOp.pTo = pTo;
            FileOp.wFunc = FO_RENAME;
            return SHFileOperation(&FileOp) == 0;   
            }

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

             

            下面這個(gè)類方便你復(fù)制多個(gè)文件或文件夾,僅作參考
            //連接多個(gè)路徑的類
            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;}
            };

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

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

            參數(shù)詳解:

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

              在這個(gè)結(jié)構(gòu)中,hWnd是指向發(fā)送消息的窗口句柄,pFrom與pTo是進(jìn)行文件操作的源文件名和目標(biāo)文件名,它包含文件的路徑,對(duì)應(yīng)單個(gè)文件的路徑字符串,或?qū)τ诙鄠€(gè)文件,必須以NULL作為字符串的結(jié)尾或文件路徑名之間的間隔,否則在程序運(yùn)行的時(shí)候會(huì)發(fā)生錯(cuò)誤。另外,pFrom和pTo都支持通配符*和?,這大大方便了開發(fā)人員的使用。例如,源文件或目錄有兩個(gè),則應(yīng)是:char pFrom[]="d:\\Test1\0d:\\Text.txt\0",它表示對(duì)要D:盤Test目錄下的所有文件和D:盤上的Text.txt文件進(jìn)行操作。字符串中的"\\"是C語言中的'\'的轉(zhuǎn)義符,'\0'則是NULL。wFunc 是結(jié)構(gòu)中的一個(gè)非常重要的成員,它代表著函數(shù)將要進(jìn)行的操作類型,它的取值為如下:

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

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

              FO_MOVE: 將pFrom的文件移動(dòng)到pTo的地方。

              FO_DELETE: 刪除pFrom指定的文件。

              使用該函數(shù)進(jìn)行文件拷貝、移動(dòng)或刪除時(shí),如果需要的時(shí)間很長(zhǎng),則程序會(huì)自動(dòng)在進(jìn)行的過程中出現(xiàn)一個(gè)無模式的對(duì)話框(Windows操作系統(tǒng)提供的文件操作對(duì)話框),用來顯示執(zhí)行的進(jìn)度和執(zhí)行的時(shí)間,以及正在拷貝、移動(dòng)或刪除的文件名,此時(shí)結(jié)構(gòu)中的成員lpszProgressTitle顯示此對(duì)話框的標(biāo)題。fFlags是在進(jìn)行文件操作時(shí)的過程和狀態(tài)控制標(biāo)識(shí)。它主要有如下一些標(biāo)識(shí),也可以是其組合:

              FOF_FILESONLY:執(zhí)行通配符,只執(zhí)行文件;

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

              FOF_NOCONFIRMATION:在出現(xiàn)目標(biāo)文件已存在的時(shí)候,如果不設(shè)置此項(xiàng),則它會(huì)出現(xiàn)確認(rèn)是否覆蓋的對(duì)話框,設(shè)置此項(xiàng)則自動(dòng)確認(rèn),進(jìn)行覆蓋,不出現(xiàn)對(duì)話框。

              FOF_NOERRORUI:設(shè)置此項(xiàng)后,當(dāng)文件處理過程中出現(xiàn)錯(cuò)誤時(shí),不出現(xiàn)錯(cuò)誤提示,否則會(huì)進(jìn)行錯(cuò)誤提示。

              FOF_RENAMEONCOLLISION:當(dāng)已存在文件名時(shí),對(duì)其進(jìn)行更換文提示。

              FOF_SILENT:不顯示進(jìn)度對(duì)話框。

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

              SHFILEOPSTRUCT結(jié)構(gòu)還包含一個(gè)SHNAMEMAPPING結(jié)構(gòu)的數(shù)組,此數(shù)組保存由SHELL計(jì)算的每個(gè)處于操作狀態(tài)的文件的新舊路徑。

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

            轉(zhuǎn)自http://blog.csdn.net/jhb92/archive/2007/04/13/1563452.aspx

            Shell的文件操作函數(shù)
            SHFileOperation
            功能:
            1.復(fù)制一個(gè)或多個(gè)文件
            2.刪除一個(gè)或多個(gè)
            3.重命名文件
            4.移動(dòng)一個(gè)或多個(gè)文件

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

            SHFileOperation
            的重要參數(shù)
            1.wFunc //對(duì)pFrom pTo要執(zhí)行的操作
            2.fFlags //影響對(duì)wFunx的操作
            3.hNameMappings   //有系統(tǒng)填充,和你也可以填充
            4.lpszProgressTitle

            pFrom pTo 在結(jié)尾是兩個(gè)'\0\0'
            通常用一個(gè)'\0',這樣會(huì)失敗的!!
            當(dāng)FOF_MULTIDESTFILES
            szPFrom[lstrlen(szPFrom)+1]=0

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


            Source and Target
            多個(gè)文件---> 一個(gè)文件夾
            許多單獨(dú)的文件---->一個(gè)文件夾
            單獨(dú)文件--->單獨(dú)文件
            許多單獨(dú)的文件---->許多單獨(dú)的文件

            單獨(dú)文件:知道名字的文件
            多個(gè)文件:帶有統(tǒng)配符的文件
            注意到source中沒有對(duì)文件夾的操作!!


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


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

            相關(guān)聯(lián)接:
            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 //不產(chǎn)生正在復(fù)制的對(duì)話框
            FOF_NOCONFIRMMKDIR//如果目的目錄不存在,就默認(rèn)創(chuàng)建
            FOF_NOCONFIRMATION //不出現(xiàn)確認(rèn)文件替換對(duì)話框(Confirmation Dialog)(默認(rèn)替換原來的文i件)
            FOF_NOERRORUI//不出現(xiàn)錯(cuò)誤對(duì)話框
            最好不要同時(shí)使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR
            因?yàn)镕OF_NOCONFIRMMKDIR屏蔽了missing directory Error
            但FOF_NOERROR又屏蔽了missing directory Error,那么在同時(shí)使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR
            時(shí)也阻止了新目錄安靜(沒有用戶確認(rèn)要產(chǎn)生新目錄的對(duì)話框)的產(chǎn)生!!
            那么如何同時(shí)使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR?
            就必須先確認(rèn)pTo所指定的目錄存在即可
            BOOL MakeSureDiretoryPathExists(LPCSTR DirPath);

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


            FOF_RENAMEONCOLLISION//有重復(fù)文件時(shí)自動(dòng)重命名


            能產(chǎn)生對(duì)話框的標(biāo)志:
            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     //將文件放入回收站,否則直接刪除,一般這個(gè)最好做默認(rèn)

            posted @ 2010-08-16 10:31 wrh 閱讀(3099) | 評(píng)論 (0)編輯 收藏
            C 標(biāo)準(zhǔn)提供一些函數(shù)用來檢查輸入輸出函數(shù)調(diào)用中的錯(cuò)誤。

            13.6.1 ferror 函數(shù)

            在調(diào)用各種輸入輸出函數(shù)(如 putc, getc , fread, fwrite 等)時(shí),日過出現(xiàn)錯(cuò)誤,除了函數(shù)返回值有所反映外,還可以用 ferror 函數(shù)檢查。它的一般調(diào)用形式為   ferror(fp);   如果 ferror 函數(shù)返回值為0(假),表示未出錯(cuò);如果返回一個(gè)非零值,表示出錯(cuò)。應(yīng)該注意,對(duì)同一個(gè)文件每一次調(diào)用輸入輸出函數(shù),均產(chǎn)生一個(gè)新的 ferror 函數(shù)值,因此,應(yīng)當(dāng)在調(diào)用一個(gè)輸入輸出函數(shù)后立即檢查 ferror 函數(shù)的值,否則信息會(huì)丟失。

               在執(zhí)行 fopen 函數(shù)時(shí),ferror 函數(shù)的初始值自動(dòng)置為0。


            13.6.2   clearerr (清除錯(cuò)誤) 函數(shù)

            clearerr 函數(shù)的作用是使文件錯(cuò)誤標(biāo)志和文件結(jié)束標(biāo)志置為0。假設(shè)在調(diào)用一個(gè)輸入輸出函數(shù)時(shí)出現(xiàn)錯(cuò)誤, ferror 函數(shù)值為一個(gè)非零值。在調(diào)用 clearerr
            (fp)后,ferror(fp)的值變成0。

            只要出現(xiàn)錯(cuò)誤標(biāo)志,就一直保留,直到對(duì)同一文件調(diào)用 clearerr 函數(shù)或(重新)rewind 函數(shù),或任何其它一個(gè)輸入輸出函數(shù)。


             

                                          13.7 文件輸入輸出小結(jié)

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

               分類             函數(shù)名                   功                                能

            打開文件         fopen()                        打開文件

            關(guān)閉文件         fclose()                        關(guān)閉文件

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

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

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

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

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

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

                                     fread()                        從指定文件中讀取數(shù)據(jù)項(xiàng)

                                     fwrite()                       把數(shù)據(jù)項(xiàng)寫到指定文件

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

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

               文                feof()                         若到文件末尾,函數(shù)值為“真”(非0)
               件                ferror()                      若對(duì)文件操作出錯(cuò),函數(shù)值為“真”(非0)
            狀態(tài)             clearerr()                   使 ferror 和 feof 函數(shù)值置零

             

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

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

             

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

            #include "stdio.h"
            main() /*先新建一個(gè)文件夾(file.txt),運(yùn)行該程序后,就有輸入到文件中.*/
            {
               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,準(zhǔn)備往文件中寫入數(shù)據(jù)*/
                {
                     printf("cann't open file");
                       exit(0);
                }
                fprintf(fp,"%d %d",x,y); /*將x,y的值寫入文件*/
                fclose(fp);   /*關(guān)閉文件*/
                if((fp=fopen("file.txt","r"))==NULL) /*打開文件file.txt,準(zhǔn)備從文件中讀出數(shù)據(jù)*/
                {
                       printf("cann't open file");
                       exit(0);

                }

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

            fclose(fp);   /*關(guān)閉文件*/

                z=x1+y1;    /*計(jì)算兩個(gè)數(shù)的和*/

                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(文本文檔里的內(nèi)容)

            11 12

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

            文件打開之后,就可以對(duì)它進(jìn)行讀寫了。常用的讀寫函數(shù)如下所述。

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

            1. fputc 函數(shù)

            把一個(gè)字符寫到磁盤文件上去。其一般調(diào)用形式為

            fputc (ch,fp);

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

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

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

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

            2.fgetc 函數(shù)

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

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

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

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

            如果想順序讀入一個(gè)二進(jìn)制文件中的數(shù)據(jù),可以用:

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

            當(dāng)未遇文件結(jié)束,feof(fp)的值為0,! feof(fp) 的值為1,讀入一個(gè)字節(jié)的數(shù)據(jù)賦給整型變量c,并接著對(duì)其進(jìn)行所需的處理。直到遇文件結(jié)束,feof(fp)值為1,! feof(fp) 值為0,不再執(zhí)行 while 循環(huán).

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

            3. fputc 和 fgetc函數(shù)使用舉例

            在掌握了以上幾種函數(shù)以后,可以編制一些簡(jiǎn)單的使用文件的程序。

            例13 .1 從鍵盤輸入一些字符,逐個(gè)把它們送到磁盤上去,直到輸入一個(gè)“#”為止。程序如下: (本例有錯(cuò)誤)
            #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);
            }
            運(yùn)行結(jié)果是:
            輸入:file1.c
            cannot open file
            (不能打開文件)

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

            例13.2 將一個(gè)磁盤文件中的信息復(fù)制到另一個(gè)磁盤文件中。
            (能運(yùn)行,不能復(fù)制 )
            #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);
            }

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

            程序運(yùn)行結(jié)果是將 file1.txt 文件中的內(nèi)容復(fù)制到 file2.txt 中去。

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

            也可以在輸入命令行時(shí)把兩個(gè)文件名一起輸入。這時(shí)要用到 main 函數(shù)的參數(shù)。程序可改為:
            #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 經(jīng)編譯連接后得到的可執(zhí)行文件名為 1.exe ,則在DOS命令工作方式下,可以輸入以下的命令行:C>1 file1.c file2.c 即在輸入可執(zhí)行文件名后,再輸入兩個(gè)參數(shù) file1.c 和 file2.c ,分別輸入到 argv[1]和 argv[2]中,argv[0]的內(nèi)容為a,argc 的值等于3(因?yàn)榇嗣钚泄灿?個(gè)參數(shù)) 。如果輸入的參數(shù)少于3個(gè),則程序會(huì)輸出:“You forgot to enter a filename”
            (你忘了輸入一個(gè)文件名)。程序執(zhí)行結(jié)果是將 file1.c 中的信息復(fù)制到 file2.c 中。可以用以下命令驗(yàn)證:
            C>type file1.c
            computer and c
            (這是 file1.c 文件中的信息)

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

            最后說明一點(diǎn),為了書寫方便,系統(tǒng)把 fputc 和 fgetc 定義為宏名putc 和getc:

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

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


             


               13.4.2 fead 函數(shù)和 fwrite 函數(shù)

            用 getc 和 putc 函數(shù)可以用來讀寫文件中的一個(gè)字符。但是常常要求一次讀入一組數(shù)據(jù)(例如,一個(gè)實(shí)數(shù)或一個(gè)結(jié)構(gòu)體變量的值),ANSI C 標(biāo)準(zhǔn)提出設(shè)置兩個(gè)函數(shù)(fead 函數(shù)和 fwrite 函數(shù)),用來讀寫一個(gè)數(shù)據(jù)塊。它們的一般調(diào)用形式為:

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

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

            size : 要讀寫的字節(jié)數(shù)。
            count: 要進(jìn)行讀寫多少個(gè) size 字節(jié)的數(shù)據(jù)項(xiàng)。
                  fp: 文件型指針。

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

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

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

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

            同樣,以下 for 語句和 fwrite 函數(shù)可以將內(nèi)存中的學(xué)生數(shù)據(jù)輸出到磁盤文件中去:

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

            如果 fead 和 fwrite 調(diào)用成功,則函數(shù)返回值為 count 的值,既輸入或輸出數(shù)據(jù)項(xiàng)的完整個(gè)數(shù)。

            下面寫出一個(gè)完整的程序。

            例13.3   從鍵盤輸入4個(gè)學(xué)生的有關(guān)數(shù)據(jù),然后把它們轉(zhuǎn)存到磁盤文件上去。
            #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 函數(shù)中,從終端鍵盤輸入4個(gè)學(xué)生的數(shù)據(jù),然后調(diào)用 save 函數(shù),將這些數(shù)據(jù)輸出到以 " stu_list "命名的磁盤文件中。fwrite 函數(shù)的作用是將一個(gè)
            長(zhǎng)度為29字節(jié)數(shù)據(jù)塊送到 stu_list 文件中(一個(gè) student_type 類型結(jié)構(gòu)體變量的長(zhǎng)度為它的成員長(zhǎng)度之和,即10+2+2+15=29)。
            運(yùn)行情況如下:
            輸入4個(gè)學(xué)生的姓名、學(xué)號(hào)、年齡和地址:

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

                程序運(yùn)行時(shí),屏幕上并無輸出任何信息,只是將從鍵盤輸入的數(shù)據(jù)送到此盤文件上。為了驗(yàn)證在磁盤文件 “ stu_list ”中是否已存在此數(shù)據(jù),可以用以下程序從 stu_list 文件中讀入數(shù)據(jù),然后在屏幕上輸出。
            #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);
            }

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

            如果企圖從 “ stu_list ”文件中以 “r ”方式讀入數(shù)據(jù)就會(huì)出錯(cuò)。

            fread 和 fwrire 函數(shù)一般用于二進(jìn)制文件的輸入輸出。因?yàn)樗鼈兪前磾?shù)據(jù)塊的長(zhǎng)度來處理輸入輸出的,在字符發(fā)生轉(zhuǎn)換的情況下很可能出現(xiàn)與原設(shè)想的情況不同。 例如,寫成:fread(&stud[i],sizeof(struct student_type),1,stdin);   企圖從終端鍵盤輸入數(shù)據(jù),這在語法上并不存在錯(cuò)誤,編譯能通過。如果用以下形式輸入數(shù)據(jù): Zhang 1001 18 room_101  
                                                       ……

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

            這個(gè)題目要求的是從鍵盤輸入數(shù)據(jù),如果已有的數(shù)據(jù)已經(jīng)以二進(jìn)制形式存儲(chǔ)在一個(gè)磁盤文件 stu_dat 中,要求從其中讀入數(shù)據(jù)并輸出到 stu_list 文件中,可以編寫一個(gè) load 函數(shù),從磁盤文件中讀二進(jìn)制數(shù)據(jù)。

            #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 (從文件中輸出) 函數(shù)和 fscanf (從文件中讀入) 函數(shù)

            fprintf 函數(shù)、fscanf 函數(shù) 與 printf 函數(shù)、scanf 函數(shù)作用相仿,都是格式讀寫函數(shù)。只有一點(diǎn)不同: fprintf 函數(shù)、fscanf 函數(shù)的讀寫對(duì)象不是終端而是磁盤文件。它們的一般調(diào)用方式為:

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

            例如:

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

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

            3, 4.50

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

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

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

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


             

                                                        13.4.4 其它讀寫函數(shù)
            1. putw 和 getw 函數(shù)

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

            如果所用的 C 編譯系統(tǒng)的庫函數(shù)中不包括 putw 和 getw 函數(shù),可以自己定義這兩個(gè)函數(shù)。putw 函數(shù)如下:

            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);
            }
            當(dāng)調(diào)用 putw 函數(shù)時(shí),如果用 putw(10,fp); 語句, 形參 i 得到實(shí)參傳來的值 10, 在 putw 函數(shù)中將 i 的地址賦予指針變量 s ,而 s 是指向字符變量的指針變量,因此 s 指向 i 的第 1 個(gè)字節(jié),s+1 指向 i 的第 2 個(gè)字節(jié)。由于 * (s+0)就是 s[0],* (s+1)就是 s[1],因此,s[0]、s[1]分別對(duì)應(yīng)的第 1 個(gè)字節(jié)和第 2 個(gè)字節(jié)。順序輸出s[0]、s[1]就相當(dāng)于輸出了 i 的兩個(gè)字節(jié)中的內(nèi)容,見圖1.
            getw 函數(shù)如下:

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

            putw 和 getw 函數(shù)并不是 ANSI C 標(biāo)準(zhǔn)定義的函數(shù)。許多 C 編譯系統(tǒng)都提供這兩個(gè),但有的不以 putw 和 getw 命名此兩函數(shù),而用其它函數(shù)名,用時(shí)要注意。

            2. 讀寫其它類型數(shù)據(jù)

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

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

            同樣可以編寫出讀寫任何類型數(shù)據(jù)的函數(shù)。

            3. fgets 函數(shù)和 fputs 函數(shù)

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

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

                 這兩個(gè)函數(shù)類似以前介紹過的 gets 和 puts 函數(shù), 只是 fgets 和 fputs 函數(shù)以指定的文件為讀寫對(duì)象。

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

            fputs(往文件中寫字符串)

             

            如果所用的 C 編譯系統(tǒng)的庫函數(shù)中不包括 putw 和 getw 函數(shù),可以自己定義這兩個(gè)函數(shù)。putw 函數(shù)如下:

            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);
            }
            當(dāng)調(diào)用 putw 函數(shù)時(shí),如果用 putw(10,fp); 語句, 形參 i 得到實(shí)參傳來的值 10, 在 putw 函數(shù)中將 i 的地址賦予指針變量 s ,而 s 是指向字符變量的指針變量,因此 s 指向 i 的第 1 個(gè)字節(jié),s+1 指向 i 的第 2 個(gè)字節(jié)。由于 * (s+0)就是 s[0],* (s+1)就是 s[1],因此,s[0]、s[1]分別對(duì)應(yīng)的第 1 個(gè)字節(jié)和第 2 個(gè)字節(jié)。順序輸出s[0]、s[1]就相當(dāng)于輸出了 i 的兩個(gè)字節(jié)中的內(nèi)容,見圖1.
            getw 函數(shù)如下:

            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函數(shù),讀寫任何類型數(shù)據(jù)都是十分方便的。如果所用的系統(tǒng)不提供這兩個(gè)函數(shù),用戶只好自己定義所需函數(shù)。例如,可以定義一個(gè)向磁盤文件寫一個(gè)實(shí)數(shù)(用二進(jìn)制方式)函數(shù) putfloat:

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

            同樣可以編寫出讀寫任何類型數(shù)據(jù)的函數(shù)。


            例13.1從鍵盤輸入一些字符,逐個(gè)把它們送到磁盤上,直到輸入一個(gè)"#"為止.程序如下:
            #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();/*接收輸入的一個(gè)字符*/
            ch=getchar();/*這一句可以省略.*/
            while(ch!='#')
            {
            fputc(ch,fp);putchar(ch);
            ch=getchar();
            }
            putchar(10);/*向屏幕輸出一個(gè)換行符*/
            fclose(fp);
            }
            運(yùn)行后的結(jié)果:輸入:is a c# 輸出 a c

             

             

                                                    13.5     文件的定位

            文件中有一個(gè)位置指針,指向當(dāng)前讀寫的位置。如果順序讀寫一個(gè)文件,每次讀寫一個(gè)字符,則讀寫完一個(gè)字符后,該位置指針自動(dòng)移動(dòng)指向下一個(gè)字符位置。如果想改變這樣的規(guī)律,強(qiáng)制使位置指針指向其它指定的位置,可以用后面介紹的有關(guān)函數(shù)。

            13.5.1 rewind 函數(shù)

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

            例13.4 有一個(gè)磁盤文件,第一次將它的內(nèi)容顯示在屏幕上,第二次把它復(fù)制到另一文件上。
            #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);
            }
            (先在某一個(gè)位置上新建立一個(gè)文本文件,命名為file1.txt然后運(yùn)行本程序(在vc編譯系統(tǒng)運(yùn)行過))如:“ file1.txt ”里面的內(nèi)容是:
                     Nu11              pointer              assignment
                  (無效的) ( 指示器)(分配、任務(wù)、作業(yè))
            運(yùn)行后的結(jié)果是:

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

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

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

            對(duì)流式文件可以進(jìn)行順序讀寫,也可以進(jìn)行隨機(jī)讀寫,關(guān)鍵在于控制文件的位置指針。如果位置指針是按字節(jié)位置順序移動(dòng)的,就是順序讀寫;如果能將位置指針按需要移動(dòng)到任意的位置,就可以實(shí)現(xiàn)隨機(jī)讀寫.所謂隨機(jī)讀寫,是指讀寫完上一個(gè)字符(字節(jié))后,并不一定要讀寫其后續(xù)的字符(字節(jié)),而可以讀寫文件中任意位置上所需要的字符(字節(jié))。

            用 fseek 函數(shù)可以實(shí)現(xiàn)改變文件的位置指針。

            fseek 函數(shù)的調(diào)用形式為: fseek (文件類型指針,位移量,起始點(diǎn))

            “起始點(diǎn) ”用0、1或 2 代替,0代表 “文件開始”,1 為“當(dāng)前位置”,2 為 “文件末尾”。 ANSI C 標(biāo)準(zhǔn)指定的名字如下表所示:

                    起始點(diǎn)                           名字                      用數(shù)字代表
                 文件開始                     SEEK_SET                          0
                 文件當(dāng)前位置            SEEK_ CUR                        1                                                       
                 文件末尾                     SEEK_END                         2

            “位移量”指以 “起始點(diǎn)” 為基點(diǎn),向前移動(dòng)的字節(jié)數(shù)。ANSI C 和大多數(shù)版本要求位移量是(long)長(zhǎng)整型數(shù)據(jù)。這樣當(dāng)文件的長(zhǎng)度大于64KB時(shí)不致出問題。ANSI C 標(biāo)準(zhǔn)規(guī)定在數(shù)字的末尾加一個(gè)字母 L,就表示是 long 型。

            fseek 函數(shù)一般用于二進(jìn)制文件,因?yàn)槲谋疚募l(fā)生字符轉(zhuǎn)換,計(jì)算位置時(shí)往往會(huì)發(fā)生混亂。

            下面是fseek 函數(shù)調(diào)用的幾個(gè)例子:

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

            fseek(fp,50L,1); /* 將位置指針移到離當(dāng)前位置50個(gè)字節(jié)處 */

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

            利用 fseek 函數(shù)就可以實(shí)現(xiàn)隨機(jī)讀寫了。

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

            #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);
            }
            (先新建一個(gè)文本文件名為“stud_dat.txt”(可以改其它名字),然后在里面輸入10學(xué)生的數(shù)據(jù)。接著再把本程序在VC編譯系統(tǒng)中運(yùn)行……)。


                                                    13.5.3 ftell 函數(shù)

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

            變量 a 存放當(dāng)前位置,如調(diào)用函數(shù)時(shí)出錯(cuò)(如不存在 fp 文件),則輸出“error”。


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

             

            例13.4 有一個(gè)磁盤文件,第一次將它的內(nèi)容顯示在屏幕上,第二次把它復(fù)制

            #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 個(gè)學(xué)生的數(shù)據(jù)。要求將第 1、3、5、7、9個(gè)學(xué)

            #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(文本文檔里的內(nèi)容)

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

             

            stud_dat(文本文檔里的內(nèi)容)

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

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

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

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

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

             

             

            posted @ 2010-08-13 08:49 wrh 閱讀(1913) | 評(píng)論 (0)編輯 收藏
            ASCII碼是7位編碼,字符在計(jì)算機(jī)中以其ASCII碼方式表示,其長(zhǎng)度為1個(gè)字節(jié), 有符號(hào)字符型數(shù)。編碼范圍是0x00-0x7F(0~127)。ASCII字符集包括英文字母、阿拉伯?dāng)?shù)字和標(biāo)點(diǎn)符號(hào)等字符。其中0x00-0x20和0x7F共33個(gè)控制字符。

            ASCII 十六進(jìn)制 控制字 代碼含義
            00           00            NUL      空
            01           01            SOH      標(biāo)題開始
            02           02            STX      正文開始
            03           03            ETX      正文結(jié)束
            04           04            EOT         傳輸結(jié)否
            05           05            ENQ        詢問
            06           06            ACK        確認(rèn)
            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         數(shù)據(jù)鏈擴(kuò)展
            17           11            DC1         設(shè)備控制1
            18           12            DC2         設(shè)備控制2
            19           13            DC3         設(shè)備控制3
            20            14            DC4         設(shè)備控制4
            21           15            NAK         不確認(rèn)
            22           16            SYN         同步字符
            23           17            ETB         傳輸塊結(jié)否
            24           18            CAN         作廢
            25           19            EM          介質(zhì)結(jié)束
            26           1A            SUB         置換
            27           1B            ESC         擴(kuò)展
            28           1C            FS             文件分隔符
            29           1D            GS          組分隔符
            30           1E            RS          記錄分隔符
            31           1F            US          單位分隔符

            ASCII碼對(duì)照表

            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碼的系統(tǒng)會(huì)忽略每個(gè)字節(jié)的最高位,只認(rèn)為低7位是有效位。HZ字符編碼就是早期為了在只支持7位ASCII系統(tǒng)中傳輸中文而設(shè)計(jì)的編碼。早期很多郵件系統(tǒng)也只支持ASCII編碼,為了傳輸中文郵件必須使用BASE64或者其他編碼方式。


            GB2312字符集編碼


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

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

            GB2312 將所收錄的字符分為 94 個(gè)區(qū),編號(hào)為 01 區(qū)至 94 區(qū);每個(gè)區(qū)收錄 94 個(gè)字符,編號(hào)為 01 位至 94 位。GB2312 的每一個(gè)字符都由與其唯一對(duì)應(yīng)的區(qū)號(hào)和位號(hào)所確定。例如:漢字“啊”,編號(hào)為 16 區(qū) 01 位。

            GB2312 字符集的區(qū)位分布表:

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

            這本手冊(cè)列出了 GB2312 的全部字符和它們的區(qū)位號(hào)。

            GB2312 編碼

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

            在區(qū)位號(hào)值上加 32 的原因大慨是為了避開低值字節(jié)區(qū)間。

            由于 GB2312 原始編碼與 ASCII 編碼的字節(jié)有重疊,現(xiàn)在通行的 GB2312 編碼是在原始編碼的兩個(gè)字節(jié)上各加 128 修改而形成。例如:漢字“啊”,編號(hào)為 16 區(qū) 01 位。它的原始編碼為 0x3021,通行編碼為 0xB0A1。

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

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

            上面這句有誤,應(yīng)該說GB2312的每一個(gè)漢字由兩個(gè)字節(jié)構(gòu)成,其中每一個(gè)字節(jié)的范圍都在0xA1 ~0xFE,正好每一個(gè)字節(jié)都有94個(gè)編碼范圍,與區(qū)位碼個(gè)數(shù)完全對(duì)應(yīng)。

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

            區(qū)位碼更應(yīng)該認(rèn)為是字符集的定義,定義了所收錄的字符和字符位置,而GB2312及EUC-CN是實(shí)際計(jì)算機(jī)環(huán)境中支持這種字符集的編碼。HZ和 ISO-2022-CN是對(duì)應(yīng)區(qū)位碼字符集的另外兩種編碼,都是用7位編碼空間來支持漢字。區(qū)位碼和GB2312編碼的關(guān)系有點(diǎn)像 Unicode和UTF-8。

            GBK字符集編碼

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

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

            低字節(jié)是0x40-0x7E的GBK字符有一定特殊性,因?yàn)檫@些字符占用了ASCII碼的位置,這樣會(huì)給一些系統(tǒng)帶來麻煩。

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

            GB18030字符集編碼

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

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

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

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

            unicode字符集編碼

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

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

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

            UTF-8字符集編碼

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

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

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

            GBK、GB2312--Unicode--UTF8

            UTF8--Unicode--GBK、GB2312

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

            導(dǎo)航

            <2010年2月>
            31123456
            78910111213
            14151617181920
            21222324252627
            28123456
            78910111213

            統(tǒng)計(jì)

            常用鏈接

            留言簿(19)

            隨筆檔案

            文章檔案

            收藏夾

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            看久久久久久a级毛片| 日韩久久久久中文字幕人妻| 1000部精品久久久久久久久| 亚洲日本va中文字幕久久| 天天躁日日躁狠狠久久| 国产精品久久久久国产A级| 99久久婷婷免费国产综合精品| 9999国产精品欧美久久久久久| 热久久国产欧美一区二区精品| 狠狠精品久久久无码中文字幕 | 久久精品免费一区二区三区| 很黄很污的网站久久mimi色| 97精品依人久久久大香线蕉97| 欧美精品一本久久男人的天堂| 午夜视频久久久久一区 | 欧美伊人久久大香线蕉综合69| AV无码久久久久不卡蜜桃| 日本免费一区二区久久人人澡| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 色婷婷久久久SWAG精品| 久久综合给合久久狠狠狠97色69| 亚洲一本综合久久| 精品久久久一二三区| 久久综合狠狠色综合伊人| 日韩欧美亚洲综合久久| 99久久亚洲综合精品成人| 久久亚洲美女精品国产精品| 亚洲婷婷国产精品电影人久久| 91久久九九无码成人网站| 日韩精品久久久久久久电影蜜臀 | 久久精品国产黑森林| 久久99精品久久久久久动态图| 亚洲人成无码久久电影网站| 日韩欧美亚洲综合久久影院d3| 亚洲欧美日韩久久精品第一区| 久久精品中文字幕第23页| 久久电影网2021| 97久久久久人妻精品专区| 午夜不卡久久精品无码免费| 久久天天婷婷五月俺也去| 久久久国产精华液|