青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 64, 文章 - 11, 評論 - 12, 引用 - 0
數(shù)據(jù)加載中……

三種操作文件存儲方案的比較

           這段時(shí)間,我正在負(fù)責(zé)升級公司中一個(gè)產(chǎn)品的幾個(gè)版本。這幾個(gè)系統(tǒng)的基本框架都相同,架構(gòu)都是以第一個(gè)系統(tǒng)為模型,只是后續(xù)的產(chǎn)品擴(kuò)展了許多功能。總的說來這幾個(gè)產(chǎn)品邏輯也不是很復(fù)雜,但因幾易開發(fā)員,而且沒有標(biāo)準(zhǔn)和缺乏設(shè)計(jì),所以系統(tǒng)的可維護(hù)性較低。

         上個(gè)星期,我重構(gòu)了產(chǎn)品中的文件操作方案。原有的操作方案是先以讀的方式打開原文件,而后從該文件中不斷地讀取指定緩沖大小的內(nèi)容,并對讀取的字串進(jìn)行處理,把處理過后的內(nèi)容寫入到一個(gè)臨時(shí)文件中,最后把原文件刪除而把臨時(shí)文件更名為原文件名。個(gè)人基于如下的考慮認(rèn)為這種方案不適于當(dāng)前場景:(1)需修改一條內(nèi)容時(shí),得從文件頭一條一條地讀取出來,然后判斷是修改或者是刪除,或者是沒有找到則是增加。(2)這種方案對于刪除、修改操作都要先逐條地移動(dòng)記錄到臨時(shí)文件,而后再重命名,所以這種方案對于大文件或者是經(jīng)常修改的文件是不合適的。(3)由于這塊文件操作是多線程的,那么可以假設(shè)一個(gè)場景 TA線程以共享讀的方式打開了文件,然后轉(zhuǎn)化到了臨時(shí)文件,關(guān)閉兩個(gè)文件句柄,TA停止。這時(shí)TB也打開原有文件并讀取了一段內(nèi)容,并打開重寫了臨時(shí)文件,接著TB又停止并關(guān)閉了文件句柄。TA繼續(xù)工作,刪除原文件重命名臨時(shí)文件,這時(shí)TB線程讀了臟數(shù)據(jù)而TA就有可能提交了錯(cuò)誤的數(shù)據(jù)。當(dāng)然這種情況是我推理出來的,實(shí)際是很少出現(xiàn)的,問題肯定是存在的。有關(guān)的這種文件操作方式的其它缺點(diǎn)還可以查閱windows核心編程中的相關(guān)章節(jié)。其中也有相關(guān)的論述。基于上述的分析,我決定重構(gòu)其實(shí)現(xiàn)。我提出了兩種備選方案,(1)采用XML的方式,對于文件鎖定的方案是以流的方式從獨(dú)占的文件中讀取,完成操作寫入時(shí)關(guān)閉。采用這種方式有利于查找、修改、刪除和添加。因?yàn)?/span>XML文件要先載入內(nèi)存并解析成DOM樹,所以XML文件較大時(shí)就不適合。(2)以獨(dú)占方式打開文件,采用內(nèi)存映射的方式操作,完成操作后寫回并關(guān)閉。在創(chuàng)建映射內(nèi)核對象時(shí)以原文件大小再加一個(gè)適當(dāng)?shù)脑隽浚詈蟾鶕?jù)實(shí)際的大小截?cái)辔募Mㄟ^比較這兩種方案在執(zhí)行50000條記錄時(shí),都是1500ms這內(nèi)。最后,基于與原有格式的兼容性和可能會出現(xiàn)大文件的考慮,我選擇了內(nèi)存映射方式。通過此次重構(gòu),大大提高了系統(tǒng)的運(yùn)行效率和穩(wěn)定性。

         代碼如下,供大家點(diǎn)評。

 1//頭文件
 2#pragma once
 3
 4class ShadowDirText
 5{
 6public:
 7    ShadowDirText(LPCTSTR szId);
 8    virtual ~ShadowDirText(void);
 9
10private:
11    ShadowDirText(const ShadowDirText &);
12    ShadowDirText& operator=(const ShadowDirText &);
13
14public:
15    static bool GetDirShadowListFilePath(LPCTSTR szDirPath, CString &strPath);
16    static bool Exists(LPCTSTR szDirPath);
17    static bool Create(LPCTSTR szDirPath);
18    static bool Delete(LPCTSTR szDirPath);
19    static void SetFileName(LPCTSTR szName);
20    
21    bool Open(LPCTSTR szDirPath);
22    void Close();
23    bool RemoveRecord(LPCTSTR szPath, bool bDir);
24    bool AddRecord(LPCTSTR szPath, bool bDir);
25    bool ExistRecord(LPCTSTR szPath, bool bDir);
26
27    bool RemoveAll();
28
29private:
30    DWORD Find(LPCTSTR szPath, bool bDir);
31    bool  FindLineById(DWORD dwSearchPosition, DWORD &dwBegin, DWORD &dwEnd);
32    void FillEnd();
33
34private:
35    CString m_strId;
36    CString m_strDir;
37    HANDLE m_hFile;
38    HANDLE m_hFileMapping;
39    PVOID m_pvMapView;
40    DWORD m_dwFileSize;
41    DWORD m_dwOriginalSize;
42
43    static const int m_snExtened;
44    static TCHAR m_sszFileName[_MAX_FNAME];
45    static const CString m_sstrFormatting; 
46    static const TCHAR m_sszLineEnd[2];
47}
;
48

  1#include "StdAfx.h"
  2#include "ShadowDirText.h"
  3
  4//////////////////////////////////////////////////////////////////////////
  5// Constraint and static variable
  6//
  7//
  8//////////////////////////////////////////////////////////////////////////
  9const int ShadowDirText::m_snExtened =102400//100KB
 10TCHAR ShadowDirText::m_sszFileName[_MAX_FNAME] = {_T('\0')};
 11
 12// attention:
 13// m_sstrFormatting and m_sszLineEnd must have the same end symbols.
 14//
 15const CString ShadowDirText::m_sstrFormatting = _T("id=\"%s\",name=\"%s\",isdir=\"%d\"\r\n");
 16const TCHAR ShadowDirText::m_sszLineEnd[2= {_T('\r'), _T('\n')};
 17
 18//////////////////////////////////////////////////////////////////////////
 19// Constructor and Destructor
 20//
 21//
 22//////////////////////////////////////////////////////////////////////////
 23ShadowDirText::ShadowDirText(LPCTSTR szId)
 24:    m_strId(szId)
 25{
 26    m_hFile = NULL;
 27    m_hFileMapping = NULL;
 28    m_pvMapView = NULL;
 29    m_dwFileSize = 0;
 30}

 31
 32ShadowDirText::~ShadowDirText(void)
 33{
 34    Close();
 35}

 36
 37//////////////////////////////////////////////////////////////////////////
 38// public static methods
 39//
 40//
 41//////////////////////////////////////////////////////////////////////////
 42
 43bool ShadowDirText::GetDirShadowListFilePath(LPCTSTR szDirPath, CString &strPath)
 44{
 45    ATLASSERT(szDirPath && 
 46        _T("argument 'szDirPath' of ShadowDirListHelper::GetDirShadowListFilePath is null."));
 47
 48    strPath = szDirPath;
 49    if(strPath.GetLength() == 0)
 50    {
 51        return false;
 52    }

 53    if(strPath.GetAt(strPath.GetLength() -1!= _T('\\'))
 54    {
 55        strPath.AppendChar(_T('\\'));
 56    }

 57    if(!PathFileExists(strPath))
 58    {
 59        return false;
 60    }

 61    strPath.Append(m_sszFileName);
 62    return true;
 63}

 64
 65bool ShadowDirText::Exists( LPCTSTR szDirPath )
 66{
 67    CString strPath;
 68    if(!GetDirShadowListFilePath(szDirPath, strPath))
 69    {
 70        return false;
 71    }

 72    if(!PathFileExists(strPath))
 73    {
 74        return false;
 75    }

 76    return true;
 77}

 78
 79bool ShadowDirText::Create(LPCTSTR szDirPath)
 80{
 81    CString strPath;
 82    if(!GetDirShadowListFilePath(szDirPath, strPath))
 83    {
 84        return false;
 85    }

 86    if(!PathFileExists(strPath))
 87    {
 88        HANDLE handle = CreateFile(strPath,
 89            GENERIC_READ | GENERIC_WRITE,
 90            0,
 91            NULL,
 92            OPEN_ALWAYS,
 93            FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE,
 94            NULL);
 95        if(INVALID_HANDLE_VALUE == handle)
 96        {
 97            return false;
 98        }

 99        static BYTE unicodeHeader[]= {0xff0xfe};
100        static TCHAR szEnd[] = _T("\r\n");
101        DWORD dwWrited = 0;
102        WriteFile(handle, unicodeHeader, sizeof(unicodeHeader), &dwWrited,0);
103        WriteFile(handle,szDirPath, (DWORD)(_tcslen(szDirPath) * sizeof(TCHAR)), &dwWrited, 0);
104        WriteFile(handle, szEnd, (DWORD)(_tcslen(szEnd) * sizeof(TCHAR)), &dwWrited, 0);
105        CloseHandle(handle);
106    }

107    return true;
108}

109
110bool ShadowDirText::Delete( LPCTSTR szDirPath )
111{
112    CString strPath;
113    if(!GetDirShadowListFilePath(szDirPath, strPath))
114    {
115        return true;
116    }

117    if(PathFileExists(strPath))
118    {
119        if(!DeleteFile(strPath))
120        {
121            return false;
122        }

123    }

124    return true;
125}

126
127void ShadowDirText::SetFileName( LPCTSTR szName )
128{
129    ATLASSERT(szName && _T("argument of ShadowDirListHelper::SetFileName is NULL"));
130    _tcscpy_s(m_sszFileName,_MAX_FNAME, szName);
131}

132//////////////////////////////////////////////////////////////////////////
133// public methods
134//
135//
136//////////////////////////////////////////////////////////////////////////
137bool ShadowDirText::Open(LPCTSTR szDirPath )
138{
139    CString strPath;
140    if(!GetDirShadowListFilePath(szDirPath, strPath))
141    {
142        return false;
143    }

144    if(!PathFileExists(strPath))
145    {
146        if(!Create(szDirPath))
147        {
148            return false;
149        }

150    }

151    Close();
152    m_strDir = szDirPath;
153    m_hFile = CreateFile(strPath, 
154        GENERIC_READ | GENERIC_WRITE, 
155        0
156        NULL, 
157        OPEN_EXISTING, 
158        FILE_ATTRIBUTE_HIDDEN, 
159        0);
160    if(INVALID_HANDLE_VALUE == m_hFile)
161    {
162        return false;
163    }

164    m_dwOriginalSize = m_dwFileSize = GetFileSize(m_hFile, NULL);
165    m_hFileMapping = CreateFileMapping(m_hFile, 
166        NULL, 
167        PAGE_READWRITE, 
168        0
169        m_dwFileSize + m_snExtened, 
170        0);
171    if(NULL == m_hFileMapping)
172    {
173        Close();
174        return false;
175    }

176    m_pvMapView = MapViewOfFile(m_hFileMapping, FILE_MAP_ALL_ACCESS, 000);
177    if(NULL == m_pvMapView)
178    {
179        Close();
180        return false;
181    }

182    m_pvMapView = (char*)m_pvMapView + 2;
183    m_dwFileSize -= 2;
184    FillEnd();
185    return true;
186}

187
188void ShadowDirText::Close()
189{
190    if(m_pvMapView)
191    {
192        m_pvMapView = (char*)m_pvMapView - 2;
193        ::UnmapViewOfFile(m_pvMapView);
194        m_pvMapView = NULL;
195    }

196    if(m_hFileMapping)
197    {
198        CloseHandle(m_hFileMapping);
199        m_hFileMapping = NULL;
200    }

201    if(m_hFile)
202    {
203        SetFilePointer(m_hFile, m_dwFileSize + 2, NULL, FILE_BEGIN);
204        SetEndOfFile(m_hFile);
205        CloseHandle(m_hFile);
206        m_hFile = NULL;
207    }

208}

209
210bool ShadowDirText::RemoveRecord( LPCTSTR szPath, bool bDir)
211{
212    DWORD dwPosition = Find(szPath, bDir);
213    if(0 == dwPosition)
214    {
215        return true;
216    }

217    CString strTemp;
218    strTemp.Format(m_sstrFormatting, m_strId, szPath, (bDir? 10));
219    int nLength = strTemp.GetLength() * sizeof(TCHAR);
220    char *pBegin = (char*)m_pvMapView;
221    memmove_s(pBegin + dwPosition, m_dwFileSize - dwPosition,pBegin + dwPosition + nLength, 
222        m_dwFileSize - dwPosition);
223    m_dwFileSize -= nLength;
224    FillEnd();
225    return true;
226}

227
228bool ShadowDirText::AddRecord(LPCTSTR szPath, bool bDir)
229{
230    DWORD dwPosition = Find(szPath, bDir);
231    if(0 != dwPosition)
232    {
233        return true;
234    }

235    CString strTemp;
236    strTemp.Format(m_sstrFormatting, m_strId, szPath, (bDir? 10));
237    int nLength = strTemp.GetLength() * sizeof(TCHAR);
238    if(m_dwFileSize + nLength + 2 > m_dwOriginalSize + m_snExtened)
239    {
240        Close();
241        Open(m_strDir);
242        return AddRecord(szPath, bDir);    
243    }

244    char *pBegin = (char*)m_pvMapView;
245    TCHAR *pWriten=(TCHAR*)(pBegin + m_dwFileSize);
246    memcpy_s(pWriten, nLength + sizeof(TCHAR), strTemp, nLength);
247    m_dwFileSize += nLength;
248    FillEnd();
249    return true;
250}

251
252bool ShadowDirText::ExistRecord( LPCTSTR szPath, bool bDir)
253{
254    return (Find(szPath, bDir)? truefalse);
255}

256
257bool ShadowDirText::RemoveAll()
258{
259    DWORD dwSearchPosition = 0;
260    DWORD dwBegin = 0;
261    DWORD dwEnd = 0;
262    bool bRet = true;
263    while (FindLineById(dwSearchPosition, dwBegin, dwEnd))
264    {
265        if(dwEnd > dwBegin)
266        {
267            char *pBegin = (char*)m_pvMapView;
268            memmove_s(pBegin + dwBegin, m_dwFileSize - dwBegin,pBegin + dwEnd, 
269                m_dwFileSize - dwBegin);
270            m_dwFileSize -= (dwEnd - dwBegin);
271            FillEnd();
272        }

273    }

274    if (dwBegin >= m_dwFileSize || dwEnd > m_dwFileSize)
275    {
276        bRet = false;
277    }

278    return bRet;
279}

280//////////////////////////////////////////////////////////////////////////
281// private methods
282//
283//
284//////////////////////////////////////////////////////////////////////////
285DWORD ShadowDirText::Find( LPCTSTR szPath, bool bDir )
286{
287    ATLASSERT(m_pvMapView != NULL && _T("Map file base address is invalid."));
288    if(NULL == m_pvMapView)
289    {
290        return 0;
291    }

292    CString strTemp;
293    strTemp.Format(m_sstrFormatting, m_strId, szPath, (bDir? 10));
294    TCHAR *pBegin =(TCHAR*)m_pvMapView;
295    TCHAR *= _tcsstr(pBegin, strTemp);
296    if(!p)
297    {
298        return 0;
299    }

300    DWORD dwOffset = (DWORD)(p - pBegin) * sizeof(TCHAR);
301    if(dwOffset >= m_dwFileSize)
302    {
303        return 0;
304    }

305    return dwOffset;
306}

307
308void ShadowDirText::FillEnd()
309{
310    char *pBegin = (char*)m_pvMapView;
311    TCHAR *pWriten=(TCHAR*)(pBegin + m_dwFileSize);
312    *pWriten = 0;
313}

314
315bool ShadowDirText::FindLineById( DWORD dwSearchPosition, DWORD &dwBegin, DWORD &dwEnd )
316{
317    ATLASSERT(dwSearchPosition % sizeof(TCHAR) == 0 && 
318        _T("argument \"dwSearchPosition\" of ShadowDirText::FindLineById must be even"));
319    dwBegin = 0;
320    dwEnd = 0;
321    if(dwSearchPosition % sizeof(TCHAR))
322    {
323        return true;
324    }

325    CString str;
326    str.Format(_T("id=\"%s\""), m_strId);
327    TCHAR *pBegin = (TCHAR *)((char*)m_pvMapView + dwSearchPosition);
328    TCHAR *p1 = _tcsstr(pBegin, str);
329    if(!p1)
330    {
331        return false;
332    }

333    dwBegin = dwSearchPosition + (p1 - pBegin) * sizeof(TCHAR);
334    TCHAR *p2 = _tcsstr(p1, m_sszLineEnd);
335    if(!p2)
336    {
337        dwEnd = m_dwFileSize;
338    }

339    else
340    {
341        dwEnd = dwBegin + (p2 - p1) * sizeof(TCHAR) + sizeof(m_sszLineEnd);
342    }

343    if(dwBegin >= m_dwFileSize || dwEnd > m_dwFileSize)
344    {
345        ATLASSERT(_T("the end of memory was bad."));
346        return false;
347    }

348    return true;
349}

      由于篇幅太長,我就不貼上XML文件操作的封裝類。在上面的代碼中str.Format(_T("id=\"%s\""), m_strId);這語句應(yīng)提取出來以提高可維護(hù)性。這里貼出的是評價(jià)方案時(shí)的類,并不是實(shí)際項(xiàng)目中的類。但總體上是一樣的,差別是完成了id, name,isdir等的常量及相關(guān)格式的標(biāo)準(zhǔn)化。

posted on 2009-07-22 10:51 Robertxiao 閱讀(935) 評論(0)  編輯 收藏 引用 所屬分類: Windows/MFC探索

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            中日韩视频在线观看| 欧美1区2区| 亚洲欧美日韩在线综合| 国产精品午夜在线观看| 亚洲欧美精品在线观看| 亚洲欧美日韩在线观看a三区| 国产欧美日韩一级| 久久久久一本一区二区青青蜜月| 欧美一级理论片| 欲香欲色天天天综合和网| 久热精品视频在线| 欧美aⅴ99久久黑人专区| 日韩天天综合| 亚洲在线成人精品| 一区二区在线免费观看| 亚洲三级视频在线观看| 亚洲三级免费观看| 先锋影音久久久| 久久国内精品视频| 亚洲高清精品中出| 亚洲视频电影在线| 国产亚洲免费的视频看| 欧美黄色aa电影| 欧美私人啪啪vps| 久久深夜福利| 欧美天堂亚洲电影院在线观看 | 亚洲综合日本| 最近中文字幕日韩精品| 中文高清一区| 亚洲国产精品成人va在线观看| 亚洲日韩欧美视频一区| 国产日韩欧美一区二区| 亚洲国产精品一区二区www| 国产精品久久久久久久久久免费| 久久久久久亚洲精品中文字幕| 欧美激情免费在线| 久久久久成人精品| 欧美午夜精品理论片a级按摩| 久久综合免费视频影院| 国产精品国产三级国产普通话蜜臀| 久久久999精品免费| 欧美日韩精品一区视频| 女生裸体视频一区二区三区| 国产精品久久国产愉拍| 亚洲国产日韩在线| 激情久久久久久久久久久久久久久久 | 欧美三日本三级三级在线播放| 久久久青草青青国产亚洲免观| 欧美日韩第一区日日骚| 欧美 日韩 国产在线| 国产片一区二区| 中文av字幕一区| 一本在线高清不卡dvd | 亚洲欧美国产视频| 亚洲一区三区视频在线观看| 欧美成人免费视频| 欧美国产极速在线| 亚洲第一黄网| 久久久国产视频91| 久久夜色精品国产| 国产综合久久| 久久er精品视频| 久久精品99无色码中文字幕| 国产精品高清网站| 亚洲午夜国产一区99re久久| 在线亚洲激情| 欧美视频四区| 亚洲午夜在线观看| 亚欧成人在线| 国产亚洲精品福利| 久久精品视频免费观看| 久久综合色婷婷| 亚洲成在线观看| 久久综合色天天久久综合图片| 美女视频黄a大片欧美| 在线成人中文字幕| 男人插女人欧美| 最新亚洲激情| 亚洲午夜一区二区三区| 国产精品久久国产精麻豆99网站| 中文在线一区| 久久国产直播| 亚洲国产一区二区精品专区| 欧美激情中文字幕一区二区| 亚洲精品男同| 欧美一区二区三区播放老司机 | 国产伦精品一区二区三区高清| 亚洲自拍三区| 欧美成人免费全部观看天天性色| 亚洲美女视频在线免费观看| 欧美午夜剧场| 久久成人国产精品| 亚洲国产精品电影| 午夜精品福利在线| 伊人久久大香线| 欧美日韩国产在线播放网站| 亚洲男人的天堂在线aⅴ视频| 久久久精品午夜少妇| 91久久综合| 国产精品综合久久久| 久久天天躁狠狠躁夜夜爽蜜月| 亚洲国产三级网| 久久av资源网站| 亚洲三级免费| 国产一区二区精品| 欧美精品三级| 久久精品国产一区二区电影 | 免费在线日韩av| 亚洲永久精品大片| 亚洲黄色在线观看| 久久精品国产第一区二区三区| 亚洲日本成人网| 国产亚洲欧美日韩在线一区| 欧美乱大交xxxxx| 久久国产一区二区三区| 亚洲欧洲三级| 免费成人av| 久久精品视频在线| 亚洲在线视频| 日韩午夜免费视频| 亚洲国产精品999| 国内精品免费午夜毛片| 国产精品国产三级国产aⅴ浪潮| 久久婷婷麻豆| 久久国产精品一区二区| 亚洲图片欧洲图片av| 亚洲欧洲一区二区天堂久久| 久久亚洲精品视频| 久久久久成人精品| 欧美一区免费| 亚洲欧美美女| 亚洲欧美激情视频| 亚洲性夜色噜噜噜7777| 亚洲美女少妇无套啪啪呻吟| 亚洲激情小视频| 亚洲国产精品久久人人爱蜜臀| 国产视频一区二区三区在线观看| 国产精品久久久久久久电影| 欧美三级网页| 欧美视频在线观看| 欧美性猛交一区二区三区精品| 欧美精品在线观看播放| 欧美国产日韩在线| 欧美电影在线免费观看网站| 免费观看一区| 欧美国产专区| 欧美日韩国产精品专区| 欧美日韩国产美女| 欧美视频精品在线| 国产精品久久久久久久第一福利 | 欧美性开放视频| 国产精品欧美一区喷水| 国产精品一区二区黑丝| 国产精品麻豆欧美日韩ww| 国产精品影片在线观看| 国产精品稀缺呦系列在线| 国产日韩欧美a| 伊人久久大香线蕉av超碰演员| 亚洲国产精品电影在线观看| 亚洲国产一区二区三区在线播| 亚洲精品国产精品乱码不99| 亚洲天堂av在线免费| 性感少妇一区| 欧美aa国产视频| 亚洲三级视频在线观看| 亚洲专区一区二区三区| 狼人天天伊人久久| 欧美日韩久久久久久| 国产亚洲精久久久久久| 91久久精品视频| 亚洲欧美综合v| 麻豆9191精品国产| 一区二区成人精品| 久久九九国产精品怡红院| 欧美精品在线视频观看| 国产午夜精品一区二区三区视频| 亚洲国产精品久久人人爱蜜臀| 亚洲无玛一区| 欧美成人精品h版在线观看| 亚洲黄页视频免费观看| 性欧美大战久久久久久久久| 欧美福利视频在线观看| 国产精品伦一区| 欧美黄色一区| 国产精品久久久久秋霞鲁丝 | 久久精品日韩| 国产精品久久久久久久久免费桃花| 国产精品视频导航| 亚洲高清不卡在线| 99精品视频免费观看视频| 亚洲欧美日韩精品久久亚洲区| 久久精品一本| 一区二区三区免费看| 久久精品99国产精品| 欧美极品aⅴ影院| 亚洲国产精品成人综合色在线婷婷| 中文久久精品| 美女国内精品自产拍在线播放| 亚洲一区影音先锋| 嫩草成人www欧美|