CTransferFile 类

来源:互联网 发布:php连接mysqli函数 编辑:程序博客网 时间:2024/06/02 19:54

//
// TransferFile.h
//
// Copyright (c) Shareaza Development Team, 2002-2005.
// This file is part of SHAREAZA (
www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#if !defined(AFX_TRANSFERFILE_H__FF7BC368_5878_4BCF_A2AD_055B0355AC3A__INCLUDED_)
#define AFX_TRANSFERFILE_H__FF7BC368_5878_4BCF_A2AD_055B0355AC3A__INCLUDED_

#pragma once

class CTransferFile;

/*

管理CTranferFiles对象和CTranferFiles对象对应的路径,

为了方便管理,将《路径,对象》保存到map中,然后为所有的

队列缓存写入的CTransferFile对象单独的建立一个链表CPtrList

*/

class CTransferFiles
{

// Construction

public:

 CTransferFiles();

 virtual ~CTransferFiles();

// Attributes

public:

 //确保互斥访问当前的CTransferFiles对象

 CCriticalSection m_pSection;

 CMapStringToPtr  m_pMap;

 CPtrList   m_pDeferred;

// Operations

public:

 CTransferFile* Open(LPCTSTR pszFile,
  BOOL bWrite, BOOL bCreate);

 //注意关闭的时候仅仅是将m_pDeferred和m_pMap清空,释放

 //这两个链表中元素所占用的空间,并没有调用延迟写入!!!!!

 void   Close();

 //将m_pDeferred中所有的延迟写入对象写入文件

 void   CommitDeferred();

protected:

 //将参数指定的CTransferFile对象加入到m_pDeferred中

 void   QueueDeferred(CTransferFile* pFile);

 //从m_pDeferred中删除参数指定的CTransferFile对象

 void   Remove(CTransferFile* pFile);

 friend class CTransferFile;
};

#define DEFERRED_MAX 8

class CTransferFile
{

// Construction

public:

 CTransferFile(LPCTSTR pszPath);

 virtual ~CTransferFile();

// Deferred Write Structure
protected:

 //延迟写入结构,定义了偏移量,写入长度和数据缓冲区指针

 class DefWrite
 {

 public:

  QWORD m_nOffset;

  DWORD m_nLength;

  BYTE* m_pBuffer;
 };

// Attributes

protected:

 //当前CTransferFile对应的文件

 CString  m_sPath;

 //对应的文件句柄

 HANDLE  m_hFile;

 //当前文件是否可以写入

 BOOL  m_bWrite;

 //当前文件被使用的记数

 DWORD  m_nReference;

protected:

 //管理了一个延迟写入数组

 DefWrite m_pDeferred[DEFERRED_MAX];

 //当前延迟写入数组中的元素个数

 int   m_nDeferred;

// Operations

public:

 //增加记数

 void  AddRef();

 //延迟写入,减少引用计数

 void  Release(BOOL bWrite);

 //延迟写入后,获得当前的文件句柄

 HANDLE  GetHandle(BOOL bWrite = FALSE);

 //当前文件是否是打开的

 BOOL  IsOpen();

 //先延迟写入,然后读取数据

 BOOL  Read(QWORD nOffset, LPVOID pBuffer,
  QWORD nBuffer, QWORD* pnRead);
 
 //如果写入偏移量大于20M,而且比当前文件长度还要大20M,则延迟写入

 //否则立即写入

 BOOL  Write(QWORD nOffset, LPCVOID pBuffer,
  QWORD nBuffer, QWORD* pnWritten);

protected:

 //打开已经存在的文件或者创建新文件

 BOOL  Open(BOOL bWrite, BOOL bCreate);

 //确保文件是可以写入的

 BOOL  EnsureWrite();

 //先延迟写入,然后重新打开文件

 BOOL  CloseWrite();

 //将DefWrite数组中的内容全部延迟写入

 void  DeferredWrite(BOOL bOffline = FALSE);

 friend class CTransferFiles;

};


extern CTransferFiles TransferFiles;

#endif // !defined(AFX_TRANSFERFILE_H__FF7BC368_5878_4BCF_A2AD_055B0355AC3A__INCLUDED_)

//
// TransferFile.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2005.
// This file is part of SHAREAZA (
www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "TransferFile.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/*

外部调用的时候,直接调用TransferFiles.open()就可以了

*/

CTransferFiles TransferFiles;


//////////////////////////////////////////////////////////////////////
// CTransferFiles construction

CTransferFiles::CTransferFiles()
{
}

CTransferFiles::~CTransferFiles()
{
 Close();
}

//////////////////////////////////////////////////////////////////////
// CTransferFiles open a file

//打开一个文件时,创建一个CTransferFile对象,引用计数增加1,

//将之加入到map中,没有加入到m_pDeferred中!!!!

CTransferFile* CTransferFiles::Open(LPCTSTR pszFile,
         BOOL bWrite, BOOL bCreate)
{
 CSingleLock pLock( &m_pSection, TRUE );

 CTransferFile* pFile = NULL;

 if ( m_pMap.Lookup( pszFile, (void*&)pFile ) )
 {
  //在原来的map中有,参数要求写而且当前文件不能写,则返回NULL

  if ( bWrite && ! pFile->EnsureWrite() )
  {
   return NULL;
  }
 }
 else // 原来的map中没有,根据参数路径创建一个新的CTransferFile对象
 {
  //打开参数路径所指定的文件,将这个pair加入到map中

  pFile = new CTransferFile( pszFile );

  if ( ! pFile->Open( bWrite, bCreate ) )
  {
   delete pFile;

   return NULL;
  }

  m_pMap.SetAt( pFile->m_sPath, pFile );
 }
 
 //CTransferFile对象的引用记数增加1

 pFile->AddRef();

 //返回创建的CTransferFile对象

 return pFile;
}

//////////////////////////////////////////////////////////////////////
// CTransferFiles close all files

//删除m_pMap中所有的CTransferFile,删除m_pMap,然后删除所有的m_pDeferred

void CTransferFiles::Close()
{
 CSingleLock pLock( &m_pSection, TRUE );

 for ( POSITION pos = m_pMap.GetStartPosition() ; pos ; )
 {
  CTransferFile* pFile;

  CString strPath;

  m_pMap.GetNextAssoc( pos, strPath, (void*&)pFile );

  //删除所有的CTransferFile对象

  delete pFile;
 }

 m_pMap.RemoveAll();

 m_pDeferred.RemoveAll();
}

//////////////////////////////////////////////////////////////////////
// CTransferFiles commit deferred writes

//将m_pDeferred中所有的CTransferFile对象延迟写入,然后清空m_pDeferred链表

void CTransferFiles::CommitDeferred()
{
 CSingleLock pLock( &m_pSection, TRUE );

 for ( POSITION pos = m_pDeferred.GetHeadPosition() ; pos ; )
 {
  CTransferFile* pFile = (CTransferFile*)m_pDeferred.GetNext( pos );

  pFile->DeferredWrite( TRUE );
 }

 m_pDeferred.RemoveAll();
}

//////////////////////////////////////////////////////////////////////
// CTransferFiles queue for deferred write

//如果在m_pDeferred链表中没有找到pFile文件,则将之加入到m_pDeferred的最后

void CTransferFiles::QueueDeferred(CTransferFile* pFile)
{
 if ( NULL == m_pDeferred.Find( pFile ) )
 {
  m_pDeferred.AddTail( pFile );
 }
}

//////////////////////////////////////////////////////////////////////
// CTransferFiles remove a single file

//在m_pMap和m_pDeferred中删除参数指定的CTransferFile对象

void CTransferFiles::Remove(CTransferFile* pFile)
{
 m_pMap.RemoveKey( pFile->m_sPath );

 if ( POSITION pos = m_pDeferred.Find( pFile ) )
 {
  m_pDeferred.RemoveAt( pos );
 }
}


//////////////////////////////////////////////////////////////////////
// CTransferFile construction

CTransferFile::CTransferFile(LPCTSTR pszPath)
{
 m_sPath    = pszPath;

 m_hFile    = INVALID_HANDLE_VALUE;

 m_nReference  = 0;

 m_bWrite   = FALSE;

 m_nDeferred   = 0;
}

//将当前TransferFile的内容写入文件m_hFile,然后关闭这个文件

CTransferFile::~CTransferFile()
{
 if ( m_hFile != INVALID_HANDLE_VALUE )
 {
  DeferredWrite();

  CloseHandle( m_hFile );
 }
}

//////////////////////////////////////////////////////////////////////
// CTransferFile reference counts

//将当前TransferFile的记数增加1

void CTransferFile::AddRef()
{
 CSingleLock pLock( &TransferFiles.m_pSection, TRUE );

 m_nReference++;
}

//将当前TransferFile的记数减少1

void CTransferFile::Release(BOOL bWrite)
{
 CSingleLock pLock( &TransferFiles.m_pSection, TRUE );

 if ( ! --m_nReference )
 {
  TransferFiles.Remove( this );

  delete this;

  return;
 }

 if ( m_bWrite && bWrite )
 {
  //如果可以写而且参数规定了要写,则先延迟写入,然后再打开

  CloseWrite();
 }
}

//////////////////////////////////////////////////////////////////////
// CTransferFile handle

//获得文件句柄,这里如果当前文件是不可写的,而参数为要写入,则返回false

//如果文件是可写的,先延迟写入,然后返回文件句柄m_hFile

HANDLE CTransferFile::GetHandle(BOOL bWrite)
{
 CSingleLock pLock( &TransferFiles.m_pSection, TRUE );

 if ( bWrite && ! m_bWrite )
 {
  return INVALID_HANDLE_VALUE;
 }

 if ( m_nDeferred > 0 )
 {
  DeferredWrite();
 }

 return m_hFile;
}

//m_hFile句柄有效说明当前的CTransferFile是打开的

BOOL CTransferFile::IsOpen()
{
 return m_hFile != INVALID_HANDLE_VALUE;
}

//////////////////////////////////////////////////////////////////////
// CTransferFile open

//打开m_sPath指定的文件,参数确定了打开的方式

BOOL CTransferFile::Open(BOOL bWrite, BOOL bCreate)
{
 if ( m_hFile != INVALID_HANDLE_VALUE )
 {
  return FALSE;
 }

 DWORD dwDesiredAccess = GENERIC_READ;

 if ( bWrite )
 {
  dwDesiredAccess |= GENERIC_WRITE;
 }

 DWORD dwShare = FILE_SHARE_READ|FILE_SHARE_WRITE;

 if ( theApp.m_bNT )
 {
  dwShare |= FILE_SHARE_DELETE;
 }

 DWORD dwCreation = bCreate ? CREATE_ALWAYS : OPEN_EXISTING;

#if 1

 m_hFile = CreateFile( m_sPath, dwDesiredAccess, dwShare,
  NULL, dwCreation, FILE_ATTRIBUTE_NORMAL, NULL );

#else
 // Testing
 m_hFile = CreateFile( _T("C://Junk//Incomplete.bin"), dwDesiredAccess,
  dwShare, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
#endif

 if ( m_hFile != INVALID_HANDLE_VALUE )
 {
  m_bWrite = bWrite;
 }

 return m_hFile != INVALID_HANDLE_VALUE;
}

//////////////////////////////////////////////////////////////////////
// CTransferFile write access management

//首先关闭m_hFile句柄,然后重新打开,这里是打开已经存在的文件

//所以是open(true, false ),这个方法是确保文件是可以写的

BOOL CTransferFile::EnsureWrite()
{
 if ( m_hFile == INVALID_HANDLE_VALUE )
 {
  return FALSE;
 }

 if ( m_bWrite )
 {
  return TRUE;
 }

 CloseHandle( m_hFile );

 m_hFile = INVALID_HANDLE_VALUE;

 if ( Open( TRUE, FALSE ) )
 {
  return TRUE;
 }

 Open( FALSE, FALSE );

 return FALSE;
}

//调用DeferredWrite完成写入,然后关闭文件句柄,再打开这个文件

BOOL CTransferFile::CloseWrite()
{
 if ( m_hFile == INVALID_HANDLE_VALUE )
 {
  return FALSE;
 }

 if ( ! m_bWrite )
 {
  return TRUE;
 }

 DeferredWrite();

 CloseHandle( m_hFile );

 m_hFile = INVALID_HANDLE_VALUE;

 return Open( FALSE, FALSE );
}

//////////////////////////////////////////////////////////////////////
// CTransferFile read

//如果需要延迟写,则写入,然后读取数据

BOOL CTransferFile::Read(QWORD nOffset, LPVOID pBuffer,
       QWORD nBuffer, QWORD* pnRead)
{
 CSingleLock pLock( &TransferFiles.m_pSection, TRUE );

 *pnRead = 0;

 if ( m_hFile == INVALID_HANDLE_VALUE )
 {
  return FALSE;
 }

 if ( m_nDeferred > 0 ) //m_nDeferred > 0表示需要延迟写,则写入
 {
  DeferredWrite();
 }

 //从m_hFile文件的 nOffset位置读取pnRead个字符到参数pBuffer中

 DWORD nOffsetLow = (DWORD)( nOffset & 0x00000000FFFFFFFF );

 DWORD nOffsetHigh = (DWORD)( ( nOffset & 0xFFFFFFFF00000000 ) >> 32 );

 SetFilePointer( m_hFile, nOffsetLow, (PLONG)&nOffsetHigh, FILE_BEGIN );

 return ReadFile( m_hFile, pBuffer, (DWORD)nBuffer, (DWORD*)pnRead, NULL );
}

//////////////////////////////////////////////////////////////////////
// CTransferFile write (with deferred extension)

/*

在nOffset位置写入数据pBuffer,长度为nBuffer。

如果偏移位置nOffset比当前文件的大小还要大,而且差距超过了

20M,则将这个写的任务使用队列缓存到TransferFiles中,以后延迟写入。

其他情况将文件指针直接定位到nOffset位置,然后写入

pBuffer数据


*/

#define DEFERRED_THRESHOLD  (20*1024*1024)

BOOL CTransferFile::Write( QWORD nOffset, LPCVOID pBuffer,
        QWORD nBuffer, QWORD* pnWritten )
{
 CSingleLock pLock( &TransferFiles.m_pSection, TRUE );

 *pnWritten = 0;

 if ( m_hFile == INVALID_HANDLE_VALUE )
 {
  return FALSE;
 }

 if ( ! m_bWrite )
 {
  return FALSE;
 }


 if ( nOffset > DEFERRED_THRESHOLD )
 {
  DWORD nSizeHigh = 0;

  QWORD nSize = (QWORD)GetFileSize( m_hFile, &nSizeHigh );

  nSize |= ( (QWORD)nSizeHigh << 32 );

  //如果要写入的位置比当前文件的大小还要大,而且间隔超过了20M

  //则将之缓存起来,并不写入

  if ( nOffset > nSize
   && nOffset - nSize > DEFERRED_THRESHOLD )
  {
   //首先将当前的TransferFile对象加入到队列中缓存起来先

   TransferFiles.QueueDeferred( this );

   //如果缓存的数目超过8了,则首先将缓存的全部写入

   if ( m_nDeferred >= DEFERRED_MAX )
   {
    DeferredWrite();
   }

   //创建一个新的DefWrite对象,加入到m_pDeferred中

   DefWrite* pWrite = &m_pDeferred[ m_nDeferred++ ];

   pWrite->m_nOffset = nOffset;
   pWrite->m_nLength = (DWORD)nBuffer;
   pWrite->m_pBuffer = new BYTE[ (DWORD)nBuffer ];

   //将参数pBuffer的内容拷贝到新创建的DefWrite对象的buffer中

   CopyMemory( pWrite->m_pBuffer, pBuffer, (DWORD)nBuffer );

   *pnWritten = nBuffer;

   theApp.Message( MSG_TEMP,
    _T("Deferred write of %I64i bytes at %I64i"),
    nBuffer, nOffset );

   return TRUE;
  }
 }

 //如果偏移量小于20M,则直接将指针移动到nOffset位置,然后写入数据

 DWORD nOffsetLow = (DWORD)( nOffset & 0x00000000FFFFFFFF );

 DWORD nOffsetHigh = (DWORD)( ( nOffset & 0xFFFFFFFF00000000 ) >> 32 );

 SetFilePointer( m_hFile, nOffsetLow, (PLONG)&nOffsetHigh, FILE_BEGIN );

 return WriteFile( m_hFile, pBuffer, (DWORD)nBuffer, (LPDWORD)pnWritten, NULL );
}

//////////////////////////////////////////////////////////////////////
// CTransferFile deferred writes

//延迟写

/*

将m_pDeferred链表中的所有的DefWrite指针的buffer的内容写入到文件

 m_hFile中,每个DefWrite定义了要写入数据的开始位置,写入长度

 和数据缓冲区,m_pDeferred保存了好多个DefWrite对象

*/

void CTransferFile::DeferredWrite(BOOL bOffline)
{
 if ( m_nDeferred == 0 )
 {
  return;
 }

 if ( m_hFile == INVALID_HANDLE_VALUE )
 {
  return;
 }

 if ( ! m_bWrite )
 {
  return;
 }

 DefWrite* pWrite = m_pDeferred;

 //pWrite->m_nOffset 指明了要写入的起始位置,pWrite->m_nLength指定了写入的长度

 for ( int nDeferred = 0 ; nDeferred < m_nDeferred ; nDeferred++, pWrite++ )
 {
  theApp.Message( MSG_TEMP, _T("Committing deferred write of %lu bytes at %I64i"),
   pWrite->m_nLength, pWrite->m_nOffset );

  //将指针移动到pWrite->m_nOffset位置,然后写入pWrite->m_nLength个字节的数据

  //为什么要拆成两半,是因为SetFilePointer函数需要用到高位字节

  DWORD nOffsetLow = (DWORD)( pWrite->m_nOffset & 0x00000000FFFFFFFF );

  DWORD nOffsetHigh = (DWORD)( ( pWrite->m_nOffset & 0xFFFFFFFF00000000 ) >> 32 );

  SetFilePointer( m_hFile, nOffsetLow, (PLONG)&nOffsetHigh, FILE_BEGIN );

  DWORD nWritten = 0;

  //将m_pBuffer写入文件

  WriteFile( m_hFile, pWrite->m_pBuffer, pWrite->m_nLength, &nWritten, NULL );

  delete [] pWrite->m_pBuffer;
 }

 m_nDeferred = 0;

 theApp.Message( MSG_TEMP, _T("Commit finished") );
}