日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

磁盘文件的正常读写与异步读写

發布時間:2025/3/17 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 磁盘文件的正常读写与异步读写 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

磁盤文件的正常讀寫與異步讀寫

轉自:http://222.30.226.10/hhcmc/study/teach_vc/teach_sp_52.htm

在Win32系統下文件可以支持平常的同步讀寫和異步讀寫(但在Win9X下,Win32系統不支持磁盤文件的異步讀寫)。本節在后面部分將會介紹文件的異步讀寫,最后一段內容將向大家講解一下文件的區域加鎖。

在Win32系統中支持64位長度的文件,所以在很多文件操作函數中需要兩個DWORD參數來表示文件長度,一個DWORD用來表示低32位,另一個用來表示高32位。

文件的讀寫進行在文件被正確打開后,但請確認在打開文件時設置了正確的讀寫標記。在Win32的文件操作中沒有了以前類似與以前ANSI C中的fputs fgets fprintf fscanf等函數,只有類似于fread和fwrite的ReadFile和WriteFile函數。

ReadFile用于文件讀,函數原型為:

BOOL ReadFile(HANDLE hFile, // handle to fileLPVOID lpBuffer, // data bufferDWORD nNumberOfBytesToRead, // number of bytes to readLPDWORD lpNumberOfBytesRead, // number of bytes readLPOVERLAPPED lpOverlapped // overlapped buffer );

其中各項參數的含義為:

  • hFile:文件句柄,為CreateFile時返回的句柄
  • lpBuffer:保存讀入的數據的指針
  • nNumberOfBytesToRead:指定需要讀入的字節數
  • lpNumberOfBytesRead:返回實際讀入的字節數
  • lpOverlapped:在文件異步讀寫時使用的數據,在同步讀寫中全部都設置為NULL,在Win9X中只支持對串口的異步操作。

如果返回值為FALSE并且讀入的字節數也返回為0,則表示文件到達了末尾。

WriteFile用于文件寫,函數原型為: BOOL WriteFile(HANDLE hFile, // handle to fileLPCVOID lpBuffer, // data bufferDWORD nNumberOfBytesToWrite, // number of bytes to writeLPDWORD lpNumberOfBytesWritten, // number of bytes writtenLPOVERLAPPED lpOverlapped // overlapped buffer );

參數的含義和ReadFile類似。

如果需要移動文件指針到相關位置(和文件讀寫不同,這個函數沒有異步版本),使用

DWORD SetFilePointer(HANDLE hFile, // handle to fileLONG lDistanceToMove, // bytes to move pointerPLONG lpDistanceToMoveHigh, // bytes to move pointerDWORD dwMoveMethod // starting point );

其中各項參數的含義為:

  • hFile:文件句柄,為CreateFile時返回的句柄
  • lpBuffer:保存讀入的數據的指針
  • lDistanceToMove:移動的字節數低DWORD
  • lpDistanceToMoveHigh:移動的字節數高DWORD,為了支持64位(2的64次方字節)長度的大文件,而用來指定64字節的高32位,如果文件大小只需要32位就可以表示,則設置為NULL
  • ldwMoveMethod:移動方法,可以選擇下面的值。
    FILE_BEGIN 從文件開始處開始移動
    FILE_CURRENT 從文件開始除開始移動
    FILE_END 從文件末尾開始移動

函數返回值和參數lpDistanceToMoveHigh(當該參數不為NULL時)表明文件指針當前的位置(從文件頭到當前的字節數),但當參數lpDistanceToMoveHigh為NULL時如果返回INVALID_SET_FILE_POINTER表明執行失敗,當參數 lpDistanceToMoveHigh不為NULL時如果返回INVALID_SET_FILE_POINTER還需要判斷GetLastError 的返回值是否不為NO_ERROR。下面是兩種情況下判斷錯誤。

//第一種情況 DWORD dwPtr = SetFilePointer (hFile, lDistance, NULL, FILE_BEGIN) ; if (dwPtr == INVALID_SET_FILE_POINTER) // Test for failure { // Obtain the error code. dwError = GetLastError() ; // 處理錯誤// . . . } // End of error handler //第二種情況 dwPtrLow = SetFilePointer (hFile, lDistLow, & lDistHigh, FILE_BEGIN) ; // Test for failure if (dwPtrLow == INVALID_SET_FILE_POINTER && (dwError = GetLastError()) != NO_ERROR ) { // 處理錯誤 // . . . } // End of error handler

在Win32中沒有提供得到文件當前指針位置的函數,但通過SetFilePointer也可以確定文件指針當前的位置。在MSDN中提供了兩個宏來得到當前文件的指針位置:

//對32位長度的文件#define GetFilePointer(hFile) SetFilePointer(hFile, 0, NULL, FILE_CURRENT) //對超過32位長度的文件#define GetVLFilePointer(hFile, lpPositionHigh) /(*lpPositionHigh = 0, /SetFilePointer(hFile, 0, lpPositionHigh, FILE_CURRENT))

對了可以通過SetFilePointer來得到文件長度,方法就是從文件位結束處移動0字節,返回值就是文件的長度。

HANDLE hFile = CreateFile(...);//打開文件進行讀 DWORD dwLen; dwLen = SetFilePointer (hFile, 0, NULL, FILE_END) ; CloseHandle( hFile ) ;

當然Win32中也提供了專門的函數來得到文件的大小

BOOL GetFileSizeEx(HANDLE hFile, // handle to filePLARGE_INTEGER lpFileSize // file size ); typedef union _LARGE_INTEGER { struct {DWORD LowPart; LONG HighPart; };LONGLONG QuadPart; } LARGE_INTEGER, *PLARGE_INTEGER;

其中lpFileSize是一個聯合數據,用來表明文件的大小。

文件的異步讀寫主要是用在大文件的讀寫上,當使用異步讀寫時,ReadFile和WriteFile會馬上返回,并在讀寫完成時通知應用程序。

要使用異步功能首先需要在打開文件時指定FILE_FLAG_OVERLAPPED作為標記(dwFlagsAndAttributes),在讀寫文件時可以使用ReadFile/WriteFile或者ReadFileEx /WriteFileEx來進行讀寫,當調用不同的函數時讀寫完成后通知應用程序的方法有所不同的,。下面分別介紹這兩種方法:

第一種方法,利用ReadFile/WriteFile,這對函數使用事件信號來進行讀寫完成的通知,由于磁盤讀寫是一個比較耗費時間的操作,而且現在的磁盤子系統可以在磁盤讀寫時脫離CPU而單獨進行,例如使用DMA方式,所以在磁盤讀寫時可以進行其他一些操作以充分利用CPU。關于事件信號相關內容請參考4.4節 進程/線程間同步中事件部分內容。并且在文件讀寫時提供OVERLAPPED數據。

結構定義如下: typedef struct _OVERLAPPED { ULONG_PTR Internal; //系統使用ULONG_PTR InternalHigh; //系統使用DWORD Offset; // 文件讀或寫的開始位置低32位,對于命名管道和其他通信設備必須設置為0DWORD OffsetHigh; // 文件讀或寫的開始位置高32位,對于命名管道和其他通信設備必須設置為0HANDLE hEvent; // 事件量,當操作完成時,這個時間會變為有信號狀態 } OVERLAPPED; //下面的代碼演示了文件異步讀取 //并且比較了同步和異步之間的性能差異 void DoDataDeal(BYTE *pbData,int iLen) {//對字節進行操作Sleep(3*1000);//假設每次計算需要2秒鐘 } //下面是使用異步讀的示范代碼,假設c:/temp/large_file.dat文件有130MB大小() //每次讀入10MB字節,并且對文件中每個字節進行操作,由于可以使用異步操作所以可以在下一次讀入數據的同時進行計算 void ReadM1(void) {HANDLE hFile = CreateFile("c://temp//large_file.dat",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL,NULL);if( INVALID_HANDLE_VALUE != hFile ){HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,"read_event");BYTE *pbRead = new BYTE[1024*1024*10];//10MB字節BYTE *pbBuf = new BYTE[1024*1024*10];DWORD dwRead,dwCount=0;OVERLAPPED overlap;overlap.Offset = 0;overlap.OffsetHigh =0;overlap.hEvent = hEvent;DWORD dwBegin= GetTickCount();//記錄開始時間ReadFile(hFile,pbRead,1024*1024*10,&dwRead,&overlap);{//開始計算for(int i=1;i<13;i++){printf("M1 i=%d/n",i);WaitForSingleObject(hEvent,INFINITE);//等待上一次完成memcpy(pbBuf,pbRead,1024*1024*10);overlap.Offset = i * (1024*1024*10);overlap.OffsetHigh =0;overlap.hEvent = hEvent;ReadFile(hFile,pbRead,1024*1024*10,&dwRead,&overlap);//在文件進行讀的同時進行計算DoDataDeal(pbBuf,1024*1024*10);}WaitForSingleObject(hEvent,INFINITE);//等待最后一次完成memcpy(pbBuf,pbRead,1024*1024*10);//數據處理DoDataDeal(pbBuf,1024*1024*10);}//結束計算printf("耗時 %d/n",GetTickCount()-dwBegin);//操作完成CloseHandle(hEvent);CloseHandle(hFile);delete pbRead;delete pbBuf;} } //下面是上面功能的文件同步讀版本 void ReadM2(void) {HANDLE hFile = CreateFile("c://temp//large_file.dat",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if( INVALID_HANDLE_VALUE != hFile ){DWORD dwRead,dwCount=0;BYTE *pbRead = new BYTE[1024*1024*10];//10MB字節BYTE *pbBuf = new BYTE[1024*1024*10];//10MB字節DWORD dwBegin= GetTickCount();//記錄開始時間for(int i=0;i<13;i++){printf("M2 i=%d/n",i);if(!ReadFile(hFile,pbRead,1024*1024*10,&dwRead,NULL)){printf("error read");break;}memcpy(pbBuf,pbRead,1024*1024*10);//計算DoDataDeal(pbBuf,1024*1024*10);}printf("耗時 %d/n",GetTickCount()-dwBegin);//操作完成CloseHandle(hFile);delete pbRead;delete pbBuf;} }

在文件的異步讀寫中,如果ReadFile/WriteFile返回FALSE,則需要通過LastError來進一步確認是否發生錯誤,例如下面的錯誤檢測代碼:

bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, &gOverlapped) ; if (!bResult) switch (dwError = GetLastError()) { case ERROR_HANDLE_EOF: { //到達文件尾} case ERROR_IO_PENDING: { //正在進行異步操作} // end case } // end switch } // end if 此外可以通過GetOverlappedResult函數來得到異步函數的執行情況 BOOL GetOverlappedResult(HANDLE hFile, // handle to file, pipe, or deviceLPOVERLAPPED lpOverlapped, // overlapped structureLPDWORD lpNumberOfBytesTransferred, // bytes transferredBOOL bWait // wait option );

如果函數調用返回FALSE則可以用GetLastError來得到錯誤,如果返回成功則可以通過lpNumberOfBytesTransferred 參數來確定當前有多少數據已經被讀或寫。lpOverlapped參數必須與調用ReadFile或WriteFile時使用同一個數據區。最后一個參數 bWait表明是否等待異步操作結束時才返回,如果設置為TRUE就可以等待文件讀寫完成時返回,否則就會馬上返回,利用這個特點可以利用它來等待異步文件操作的結束(就如同等待事件變為有信號狀態一樣起到相同的作用)。

在上面的例子中沒有過多的進行錯誤檢查,如果大家有興趣可以自己運行一下這個例子,看看異步文件讀寫對性能的影響。在我自己的計算機PII 450 IBM 30GB硬盤上同步讀比異步讀慢了大約10%左右,這主要時因為數據處理時間我設置為兩秒鐘,如果設置得足夠長,會顯示出異步和同步處理時的差異極限。此外由于磁盤緩存得作用也會影響結果,所以如果讀入的數據量更大將會產生更明顯的差異,這是因為雖然異步讀寫會在調用等待函數上也會耗費一些時間,所以如果數據量小就無法分辨出差異。

請記住OVERLAPPED參數在文件操作執行完以前不要手工修改結構內的值,因為系統會使用結構中的數據。

對于WriteFile操作也可以用相同方法,在WriteFile中磁盤操作將耗費更多的時間,所以使用異步寫更能體現優勢,你可以將這個例子改為磁盤寫后自己測試一下。

下載利用ReadFile進行異步文件讀的示范代碼

第二種方法,利用ReadFileEx/WriteFileEx,這對函數使用回調函數來進行讀寫完成的通知。

BOOL ReadFileEx(HANDLE hFile, // handle to fileLPVOID lpBuffer, // data bufferDWORD nNumberOfBytesToRead, // number of bytes to readLPOVERLAPPED lpOverlapped, // offsetLPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // completion routine );
  • hFile為文件句柄。
  • lpBuffer指明了寫入數據的內存區指針。
  • nNumberOfBytesToRead為要求讀入的數據字節數。
  • lpOverlapped為一個OVERLAPPED的結構,這個結構hEvent字段將被系統忽略,但是通過Offset和OffsetHigh字段來表明開始讀文件的位置。
  • lpCompletionRoutine為一個通知用的回調函數。

函數的最后一個參數指明了一個回調函數,這個回調函數稱為一個告警函數。函數必須具有這樣的原型:

VOID CALLBACK FileIOCompletionRoutine(DWORD dwErrorCode, // completion codeDWORD dwNumberOfBytesTransfered, // number of bytes transferredLPOVERLAPPED lpOverlapped // I/O information buffer );
  • dwErrorCode為錯誤代碼,如果為0表示正確,為ERROR_HANDLE_EOF表示到達文件的末尾。
  • dwNumberOfBytesTransfered為成功傳送的字節數,如果發生錯誤,這個值為0。
  • lpOverlapped為一個OVERLAPPED的結構,這個結構必須與調用ReadFileEx時指向相同的數據區,并且在調用ReadFileEx后不能手工更改這個結構中的字段。

那么如何檢測回調函數已經被調用了(文件操作已經完成),你可以設置一個全局的同步量來進行通知,但是系統提供了其他簡便的方法供開發者使用,這就是SleepEx WaitForMultipleObjectsEx 和WaitForSingleObjectEx。

當線程調用ReadFileEx或WriteFileEx時,提供了一個告警函數,這個告警函數會被放入一個隊列,當操作完成時操作系統會從隊列中取出這些函數進行調用。所以對于屬于本進程內部所產生的需要等待被調用的告警函數來說可以直接使用SleepEx對當前線程進行休眠并等待當前提交所有的告警函數被執行。如果希望等待指定文件操作上的告警函數被調用你可以使用WaitForMultipleObjectsEx或 WaitForSingleObjectEx。這三個函數的原型為:

DWORD SleepEx(DWORD dwMilliseconds, // time-out intervalBOOL bAlertable // early completion option ); DWORD WaitForSingleObjectEx(HANDLE hHandle, // handle to objectDWORD dwMilliseconds, // time-out intervalBOOL bAlertable // alertable option ); DWORD WaitForMultipleObjectsEx(DWORD nCount, // number of handles in arrayCONST HANDLE *lpHandles, // object-handle arrayBOOL fWaitAll, // wait optionDWORD dwMilliseconds, // time-out intervalBOOL bAlertable // alertable option );

這三個函數和Sleep WaitForSingleObject WaitForMultipleObjects的差別就在于多了最后一個參數bAlertable,這個參數需要設置為TRUE表明等待文件異步操作的完成。通過檢測函數返回值可以得知文件操作是否完成,例如下面的代碼:

ReadFileEx(hFile,pbRead,1024*1024*50,&overlap,MyIORoutine);while(WAIT_IO_COMPLETION != SleepEx(1,TRUE) )//檢測文件操作是否完成//while (WaitForSingleObjectEx(hFile,1,TRUE) != WAIT_OBJECT_0 ) //在這里WaitForSingleObjectEx和SleepEx具有相同作用{DoSomething();}

對于SleepEx來說如果返回WAIT_IO_COMPLETION則表示異步操作完成,而對于文件對象來說如果異步操作完成文件對象就會變為有信號狀態。下面的例子是一個利用告警回調函數實現的文件異步讀寫。

VOID CALLBACK MyIORoutine(DWORD dwErrorCode, // completion codeDWORD dwNumberOfBytesTransfered, // number of bytes transferredLPOVERLAPPED lpOverlapped // I/O information buffer ) {//定義一個簡單的回調函數printf("文件讀完成/n"); }void DoSomething(void) {printf("current time %d/n",GetTickCount());Sleep(2000);//假設耗時的操作需要兩秒鐘 }//下面是使用異步讀的示范代碼,假設c:/temp/large_file.dat文件有130MB大小() //一次性讀入50MB字節,在讀入的過程中進行一些其他操作 void ReadM(void) {HANDLE hFile = CreateFile("c://temp//large_file.dat",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL,NULL);if( INVALID_HANDLE_VALUE != hFile ){BYTE *pbRead = new BYTE[1024*1024*50];//50MB字節OVERLAPPED overlap;overlap.Offset = 0;overlap.OffsetHigh =0;overlap.hEvent = NULL; //使用告警函數時無需要使用事件DWORD dwBegin= GetTickCount();//記錄開始時間printf("begin time %d/n",dwBegin);ReadFileEx(hFile,pbRead,1024*1024*50,&overlap,MyIORoutine);while(WAIT_IO_COMPLETION != SleepEx(1,TRUE) )//檢測文件操作是否完成//while (WaitForSingleObjectEx(hFile,1,TRUE) != WAIT_OBJECT_0 ) //在這里WaitForSingleObjectEx和SleepEx具有相同作用{DoSomething();//在文件讀的執行過程中進行其他操作}printf("耗時 %d/n",GetTickCount()-dwBegin);//操作完成CloseHandle(hFile);delete pbRead;} }

WriteFileEx的用法與ReadFileEx的用法是類似的。

下載利用ReadFileEx進行異步文件讀的示范代碼

在磁盤操作中磁盤寫比讀需要花更多的時間,并且大文件的異步寫可以更加有效的提高CPU利用率。但是異步操作會給開發和調試帶來一些麻煩,所以我建議除非在非常必要(性能要求非常高,文件非常大)的情況下才使用異步的磁盤讀寫。再提一點,對于磁盤文件的異步操作的方式同樣可以用于上章所講的命名管道,或者是串口的異步操作。

文件加鎖時在打開文件后對文件的某個區域加鎖,加鎖后可以防止其他進程對該區域數據進行讀取。相關的函數為:

BOOL LockFile(HANDLE hFile, // 文件句柄DWORD dwFileOffsetLow, // 文件加鎖開始位置低32位DWORD dwFileOffsetHigh, // 文件加鎖開始位置高32位DWORD nNumberOfBytesToLockLow, // 區域長度低32位DWORD nNumberOfBytesToLockHigh // 區域長度高32位 ); BOOL UnlockFile(HANDLE hFile, // 文件句柄DWORD dwFileOffsetLow, // 文件解鎖開始位置低32位DWORD dwFileOffsetHigh, // 文件解鎖開始位置高32位DWORD nNumberOfBytesToLockLow, // 區域長度低32位DWORD nNumberOfBytesToLockHigh // 區域長度高32位 );

在文件加鎖和解鎖上需要有對應關系,這種對應關系就是對A區域加鎖后必須對A區域解鎖后才可以對其他區域解鎖,而且必須是一對一的關系,也就是說調用一次對A區域的加鎖函數就必須調用一次對A區域的解鎖函數,而不能對一個區域加鎖后分次對該區域的不同部分解鎖。

在MFC中對文件操作進行了封裝,CFile中封裝了各種文件操作。在CFile中常用的成員函數有以下這些:

CFile( LPCTSTR lpszFileName, UINT nOpenFlags ); //打開文件virtual BOOL Open( LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL ); //打開文件 uOpenFlags為打開文件時的參數,可以取的以下值的組合: CFile::modeRead / CFile::modeReadWrite / CFile::modeWrite 讀寫模式 CFile::modeCreate 創建文件 CFile::shareDenyNone / CFile::shareDenyRead / CFile::shareDenyWrite 共享設置 CFile::typeText / CFile::typeBinary 以文本形式還時二進制形式打開文件virtual void Close( ); //關閉文件virtual UINT Read( void* lpBuf, UINT nCount ); //讀文件virtual void Write( const void* lpBuf, UINT nCount ); // 寫文件virtual LONG Seek( LONG lOff, UINT nFrom ); //設置文件指針void SeekToBegin( );//移動文件指針到文件頭DWORD SeekToEnd( );//移動文件指針到文件尾virtual void LockRange( DWORD dwPos, DWORD dwCount ); //鎖定文件virtual void UnlockRange( DWORD dwPos, DWORD dwCount ); //解鎖文件

CStdioFile是CFile的派生類,主要是完成對文本文件的操作,它只有兩個成員函數:

BOOL ReadString(CString& rString); //讀入文件中一行void WriteString( LPCTSTR lpsz );//將字符串作為一行寫入文件

轉載于:https://www.cnblogs.com/k1988/archive/2009/12/01/2165697.html

總結

以上是生活随笔為你收集整理的磁盘文件的正常读写与异步读写的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久亚洲精品无码va白人极品 | 黄色网日本 | 欧美午夜大片 | 久久久久久久 | 成人在线观看小视频 | 国产精品夜夜嗨 | www.久久精品.com | 亚洲午夜一区二区 | 成人av片免费看 | 久久偷看各类女兵18女厕嘘嘘 | 女女爱爱视频 | 日本不卡一区在线 | 伊人看片 | 51国产偷自视频区视频 | 男男野外做爰全过程69 | 男人日女人在线观看 | 精品欧美一区二区久久久 | 日本三级吃奶头添泬 | 久久香视频 | 亚洲精品成人影视 | 法国空姐 在线 | 99在线精品免费视频 | 日韩精品成人无码专区免费 | 日韩一区二区在线免费观看 | 国产一级爱 | 国产a国产片国产 | 久草福利在线视频 | 亚洲高清一区二区三区 | 自拍视频在线观看 | 中文在线а√在线 | 日韩免费在线观看 | 蜜桃久久久久久久 | 成人av第一页 | 欧美brazzers| 亚洲av无码久久精品色欲 | 免费黄色三级网站 | 欧美性视频在线 | 黄色大片久久 | 51啪影院 | jizz自拍| 国产女主播视频 | 狠狠操夜夜 | 五月婷婷六月综合 | 免费99视频| www.伊人网 | 欧美老熟妇喷水 | 在线二区 | 综合久色 | 精品人妻一区二区三区视频 | 人人爱人人射 | 美妇湿透娇羞紧窄迎合 | 春日野结衣av | 嫩草影院一区二区三区 | 看片网址国产福利av中文字幕 | 亚洲精品国产suv一区 | 久久久久亚洲精品中文字幕 | 香蕉视频一区二区三区 | 庆余年三 | 夜夜操网| 在哪里看毛片 | 欧美老熟妇喷水 | 成人av激情| 日韩毛片一级 | 欧美hdxxxx| 亚洲无人禁区 | 疯狂伦交| 九热在线视频 | 黄色视屏免费 | 久久99热这里只频精品6学生 | 中文字幕日韩经典 | 成年人免费网站视频 | 你懂的在线观看网站 | 久久国产一 | 国产视频第二页 | 欧美极品少妇xxxxⅹ裸体艺术 | 精品国产乱子伦一区二区 | 91黄色在线观看 | 久久久久亚洲av无码麻豆 | 亚洲天堂99 | 日韩综合色| 成人拍拍拍 | 免费av电影网站 | 色婷婷九月 | 4438国产精品一区二区 | 97久久人人 | 少妇一级淫片免费放中国 | 911美女片黄在线观看游戏 | 日本黄色动态图 | 久久久久99精品成人片我成大片 | 日本特黄一级 | 日本中文字幕第一页 | 丝瓜av| 国产精品久久久久99 | 久久99精品久久久水蜜桃 | 337p亚洲欧洲色噜噜噜 | 久久精选 | 国产操女人 | 亚洲一区二区三区高清视频 | 亚洲综合五区 |