回 帖 发 新 帖 刷新版面

主题:如何获取已经打开的文件的指针

RT

回复列表 (共11个回复)

沙发

long int ftell(FILE *stream);
返回流stream中当前文件指针位置。偏移量是文件开始算起的字节数。出错时返回-1L,是长整数的-1值。

板凳

liudan319你好,我是要获取一个已经打开的文件的指针或者句柄,不是已经打开的文件的位置

3 楼

参考:
http://bbs.pfan.cn/post-316615.html

4 楼

[quote]参考:
http://bbs.pfan.cn/post-316615.html[/quote]

int main(int argc, char* argv[])
{
    const char* str = "D:\\1.txt";
    FILE* fp;
    fopen_s(&fp, str, "a");
    fopen_s(&fp, str, "a");
    return 0;
}

上面的代码,在第二次调用fopen_s的时候得到的fp为无效值。

目前想实现一种功能:如果判断文件D:\\1.txt被打开了,那么我要获取指向该文件的FILE*或者其他能操作该文件的句柄,如果判断文件D:\\1.txt没有被打开,那么我就打开该文件并进行一些写入操作。

5 楼

我没有编译器。很久没写东西啦。第二次调用的失败的原因是否跟。指针没有释放有关

6 楼

此路不通,得绕过去

之前在网上下了个CLog类(http://blog.csdn.net/karl_max/archive/2007/08/03/1724311.aspx),目的是用来记录日志的,但是发现该类的实现有点缺陷,那就是每次写日志时都要执行一次打开文件,关闭文件操作,影响效率。当时想找下windows有没有获取已打开文件的指针的方法,不过很遗憾,windows没有(Linux里面的lsof命令是不是有这个功能?)

今天想到了用static方法实现(相关头文件请自己添加):

//---------------------Log.h-----------------
#pragma once

void log_debug(LPCTSTR msg);
void log_debug(const char* pdu, int len);

class CLog
{
public:
    CLog(LPCTSTR lpszLogPath);
    ~CLog();

public:
    BOOL Open();
    BOOL Close();
    BOOL IsOpen(){return m_bOpen;}
    void AddString(LPCTSTR str);
private:
    void Add(const char* fmt, ...);
private:
    FILE* m_fp;
    BOOL m_bOpen;
    char m_tBuf[4096];
    CString m_strLogPath;
    CRITICAL_SECTION m_crit;
};
//---------------------Log.h-----------------

7 楼

//---------------------Log.cpp---------------
#include "Log.h"

/****************************************************
    Function:        CLog::CLog
    Description:    构造函数    
****************************************************/
CLog::CLog(LPCTSTR lpszLogPath) 
{
    ::InitializeCriticalSection(&m_crit);
    m_strLogPath = lpszLogPath;
    Open();
}

/***************************************************
    Function:        CLog::~CLog
    Description:    析构函数    
****************************************************/
CLog::~CLog()
{
    Close();
    ::DeleteCriticalSection(&m_crit);
}

/****************************************************
    Function:        CLog::Open
    Description:    打开日志文件
    Input:            
    Output:            
    Return:            TRUE-打开成功,FALSE-打开失败
    Other:            打开日志文件
****************************************************/
BOOL CLog::Open()   
{    
    char* strPath = m_strLogPath.GetBuffer();
    errno_t err = fopen_s(&m_fp, strPath, "a");
    if (err != 0)
    {
        m_bOpen = FALSE;
        return FALSE;
    }
    m_bOpen = TRUE;
    return TRUE;
}

/****************************************************
    Function:            CLog::Close
    Description:        关闭日志文件
    Input:                
    Output:                
    Return:                TRUE-关闭成功,FALSE-关闭失败
    Other:                
*****************************************************/
BOOL CLog::Close()
{
    if (fclose(m_fp) != 0)
    {
        return FALSE;
    }
    m_bOpen = FALSE;
    return TRUE;
}

/*****************************************************
    Function:            CLog::Add
    Description:        记录日志信息
    Input:                fmt, ...可变参数,类似printf    
    Output:                
    Return:                
    Other:                将格式化的fmt数据记录到日志文件中        
****************************************************/
void CLog::Add(const char* fmt, ...)
{
#ifdef _DEBUG
    if (m_strLogPath.IsEmpty())
        return ;

    if (!AfxIsValidString(fmt, -1))
        return ;

    ::EnterCriticalSection(&m_crit);   
    try      
    {
        va_list argptr;
        va_start(argptr, fmt);
        _vsnprintf_s(m_tBuf, 4096, fmt, argptr);
        va_end(argptr);
    }
    catch (...)
    {
        m_tBuf[0] = 0;
    }
    if (!m_bOpen)
    {
        Open();
    }
    if (m_fp)
    {
        CTime ct ;
        ct = CTime::GetCurrentTime();
        fprintf(m_fp,"%s : ",ct.Format("%Y-%m-%d %H:%M:%S"));
        fprintf(m_fp, "%s\n", m_tBuf);               
    }    
    ::LeaveCriticalSection(&m_crit);  
#endif
}

/****************************************************
    Function:            CLog::AddString
    Description:        记录日志信息
    Input:                str为写入文件的信息            
    Output:                        
    Return:                
    Other:                该函数直接调用Add函数
****************************************************/
void CLog::AddString(LPCTSTR str)
{
#ifdef _DEBUG
    Add("%s", str);
#endif
}
//---------------------Log.cpp---------------

8 楼

//---------------------Log.cpp---------------
/****************************************************
    Function:            log_debug
    Description:        打印日志
    Input:                msg为打印的字符串
    Output:                        
    Return:                
    Other:                该函数通过CLog类记录日志        
****************************************************/
void log_debug(LPCTSTR msg)
{
    //--------------------------------
    char   szPath[MAX_PATH];   
    GetModuleFileName(NULL, szPath, MAX_PATH);
    char   drive[_MAX_DRIVE];   
    char   dir[_MAX_DIR];   
    char   fname[_MAX_FNAME];   
    char   ext[_MAX_EXT];   
    _splitpath_s(szPath, drive, dir, fname, ext);
    CString strLogPath;
    strLogPath.Format("%s%s\\trace.txt", drive, dir);
    //----------------------------

    static CLog log(strLogPath);
    log.AddString(msg);
}

/****************************************************
    Function:            log_debug
    Description:        打印报文
    Input:                pdu为报文,len为报文长度            
    Output:                        
    Return:                
    Other:                该函数通过CLog类记录日志
****************************************************/
void log_debug(const char* pdu, int len)
{
    char buffer[4096] = {0};
    sprintf_s(buffer, "send data : \n");
    strcat_s(buffer, "................ ");
    char bt[4] = {0};
    for (int i = 0; i < len; ++i)
    {
        sprintf_s(bt, "%02x ", (unsigned char)pdu[i]);
        strcat_s(buffer, bt);
        //每行打印16个
        if ((i+1)%16==0 && i+1 != len)
        {
            strcat_s(buffer, "\n................ ");
        }
    }
    strcat_s(buffer, "\n");
    log_debug(buffer);
}
//---------------------Log.cpp---------------

以上实现在写日志时不用每次都执行打开文件,关闭文件操作。不过也有个问题,在第一次执行void log_debug(LPCTSTR msg)函数时(注意是第一次执行),如果是两个线程同时调用的话static CLog log(strLogPath);这里会有问题,具体什么问题我就不清了-_-!


每次能贴的内容太少了点吧。。。

9 楼

目前想实现一种功能:如果判断文件D:\\1.txt被打开了,那么我要获取指向该文件的FILE*或者其他能操作该文件的句柄,如果判断文件D:\\1.txt没有被打开,那么我就打开该文件并进行一些写入操作。
================================
如果文件已经打开,则函数返回已经打开的文件所对应的FILE*。假设已经有这样的函数了,那我可以多个位置同时使用那个FILE*,这样一来恐怕会造成数据错乱(双方都进行fseek、fread的话)。另外,如果双方都持有同一个FILE*,那应该由谁来调用fclose呢?如果双方都调用,则重复close会出错。


如果是两个线程同时调用的话static CLog log(strLogPath);这里会有问题,具体什么问题我就不清了-_-!
================================
这是一个著名的问题了。C++规定函数中的static对象在第一次使用之前被初始化,在编译器实现时,往往有一个标志来记录每个static变量是否已经初始化了。因此,每次执行到static变量的定义处,都会有判断:这个变量是否已经初始化?如果没有,则初始化(调用构造函数),然后把标志设置为“已经初始化”。注意这里用的是“标志”,而不是“锁”,所以多线程的时候就有问题。好象新的C++0x标准里面规定编译器必须保证多线程时也能正确,不过这是以后的事情,现在的话,还是只有加锁来解决了。


我觉得如果可能的话,开一个优先级较低的线程,专门负责写log。程序需要写log的时候,发送一个消息到该线程,该线程收到消息后,尝试打开文件并写入。如果打开失败,则过一段时间之后再试。
在程序运行的时候一直保持某个文件被打开,从来不关闭,这个办法我觉得也不太好。程序运行的时候如果想用其它软件去打开这个log文件的话,可能就会失败。

10 楼

几年不见,牛仔兄还是这么敬业[em2]

之前在华为做外包时,学了下他们的代码:

对于静态对象,在类里添加静态方法
CLog Clog::CreateInstance()
{
    static Clog log;
    return log;
}
在程序运行时就调用该方法,这样就可以避免第一次多线程同时调用的问题。

记录日志可以设置一个缓存buffer,每次记录日志时将记录的内容以添加的形式(类似strcat函数)缓存到buffer,当buffer达到一定容量时再写入文件。

不过我写的是很小的程序,目前可以不用考虑这么细

我来回复

您尚未登录,请登录后再回复。点此登录或注册