主题:如何获取已经打开的文件的指针
overfly
[专家分:3230] 发布于 2010-03-31 09:47:00
RT
回复列表 (共11个回复)
沙发
liudan319 [专家分:3780] 发布于 2010-03-31 12:36:00
long int ftell(FILE *stream);
返回流stream中当前文件指针位置。偏移量是文件开始算起的字节数。出错时返回-1L,是长整数的-1值。
板凳
overfly [专家分:3230] 发布于 2010-03-31 13:48:00
liudan319你好,我是要获取一个已经打开的文件的指针或者句柄,不是已经打开的文件的位置
3 楼
zhangmou [专家分:14200] 发布于 2010-03-31 14:12:00
参考:
http://bbs.pfan.cn/post-316615.html
4 楼
overfly [专家分:3230] 发布于 2010-03-31 14:27:00
[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 楼
zhangmou [专家分:14200] 发布于 2010-03-31 20:40:00
我没有编译器。很久没写东西啦。第二次调用的失败的原因是否跟。指针没有释放有关
6 楼
overfly [专家分:3230] 发布于 2010-04-01 10:38:00
此路不通,得绕过去
之前在网上下了个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 楼
overfly [专家分:3230] 发布于 2010-04-01 10:41:00
//---------------------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 楼
overfly [专家分:3230] 发布于 2010-04-01 10:42:00
//---------------------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 楼
eastcowboy [专家分:25370] 发布于 2010-04-01 14:45:00
目前想实现一种功能:如果判断文件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 楼
overfly [专家分:3230] 发布于 2010-04-02 14:04:00
几年不见,牛仔兄还是这么敬业[em2]
之前在华为做外包时,学了下他们的代码:
对于静态对象,在类里添加静态方法
CLog Clog::CreateInstance()
{
static Clog log;
return log;
}
在程序运行时就调用该方法,这样就可以避免第一次多线程同时调用的问题。
记录日志可以设置一个缓存buffer,每次记录日志时将记录的内容以添加的形式(类似strcat函数)缓存到buffer,当buffer达到一定容量时再写入文件。
不过我写的是很小的程序,目前可以不用考虑这么细
我来回复