在vc6里,CStdioFile类的release版也使用了buffer的,但是很明显它的代码比我的还多,但效率却和我自己写的效率差不多。 
我使用的是 _write 和 _comment 之类的IO函数。
请高手帮忙看看代码可以怎么优化能使它超过CstdioFile。
完整代码贴在我的blog里,链接:
http://blog.csdn.net/boythl/archive/2008/08/27/2835994.aspx
谢谢大虾们!!!

解决方案 »

  1.   

    你在Windows系统下_write效率不如WriteFile的系统API,
    low level file IO要自己管理系统的句柄等,效率并不高。
      

  2.   

    请教楼上,有什么介绍win下io的书么? 我对io的结构体系还不是很了解。
    _write算是哪一级或哪一类的函数?
    谢谢
      

  3.   


    C run-time I/O( fopen ... )    
    low level file I/O( _open ... )      
    C++ run-time I/O( ostream ... )
    win32 file I/O( CreateFile ... )
    Direct I/O ( Driver ... )其中最底层是驱动层的文件系统,直接操作扇区。
    之上就是API了win32 file I/O。
    而C run-time I/O、low level file I/O、C++ run-time I/O都是对API的包装,代码稍有不同,
    效率也稍有不同你可以参考Crt的源码就知道了.
    所以直接用CreateFile如果写的好的话,效率应该能够满足要求了。至于win下io的书好像没什么,这种内容基本都是简单介绍。
      

  4.   

    恩。wangk 解释的比较清晰。谢谢!
     我再尝试下。 有结果再贴出来。
      

  5.   

    磁盘映射文件,其他的效率都不会快,且瓶颈不在你用C++的流还是C FILE。
      

  6.   

    盘映射文件,其他的效率都不会快,且瓶颈不在你用C++的流还是C FILE。 
      

  7.   

    我只试过磁盘映射文件的读,好像比cfile的读也快不了多少,但内存占用却是文件尺寸大小。映射文件的写会比系统API快吗?
      

  8.   

    系统API里是不是没有移动文件指针的函数? 获取当前文件指针位置的函数也没找到
      

  9.   

    SetFilePointer可以移动指针。SetFilePointer传个0应该可以获取指针位置。对吧?
      

  10.   

    就是我现在有很多程序都需要写log日志,文本格式的。
    但我发现debug版的CStdiofile写起来很慢。写个80M的东西得很久。我想自己写一个,效率要超过cstdiofile。我的描述够了吧?
      

  11.   

    好多分钟。debug状态下,还有其他的操作,所以不能得到实际耗时。
    基本上是几个字符几个字符写的。 
    任务管理器里的io写出是几K几K的增加。
      

  12.   

    有缓冲的时候不会每次都访问磁盘而浪费时间,但由于每次只写几个字节,80MB数据大约要执行10M次写函数,而且Debug版的效率较低,时间肯定会很长。如果要提高效率,只能考虑尽量减少写操作执行的代码所需的时间,而用Debug版测试代码效率显然是没有意义的。
    另外,通常应用程序不会在短时间内执行这么多次写文件操作的,不清楚你怎么有这样的应用。
      

  13.   

    唉。 这是我们公司先前的一个库,因为要写一个产品文件,纯文本的。它采取的策略就是一截一截的写。 
    所以我就怀疑是太多次的写操作导致的效率低下。
    另,因为该库用到的其他库只有debug版,目前也只能发布debug版,所以我只能在debug版中测试效率。
    因此,我考虑能不能自己写个带缓冲的写文件类,来提高写的效率。
      

  14.   

    对于这种情况,用自己的缓冲可以提高效率,但还是很慢,因为执行代码本身也是需要时间的,调用次数多到一定程度后,执行代码的时间就不能忽略不计了。另外Debug版的库也可以用Release版的程序来调,你可以先试试。
      

  15.   

    恩。 cnzdgs 说的很有道理。我现在正好没什么事,多研究几种写文件方法也没坏处。
    我用WriteFile API写文件时
    HasOverlappedIoCompleted(m_pOverLapped)
    判断异步写磁盘是否完成,但一直是false,能告诉我怎么回事吗?
      

  16.   

    代码是怎么写的?CreateFile是否加了FILE_FLAG_OVERLAPPED标志?WriteFile返回成功了吗?
      

  17.   

    CreateFile加了FILE_FLAG_OVERLAPPED标志;
    WriteFile返回成功int nFlag = FILE_ATTRIBUTE_NORMAL |
     FILE_FLAG_OVERLAPPED/*异步IO*/ /*| FILE_FLAG_WRITE_THROUGH*/ | FILE_FLAG_NO_BUFFERING; if (INVALID_HANDLE_VALUE == 
    (this->m_Handle = CreateFile(lpszFileName, GENERIC_WRITE | GENERIC_READ, 
    FILE_SHARE_READ, NULL, nCreateFlag, nFlag, NULL)) 
    )//文件打开失败
    {
    this->m_Handle = NULL;
    return FALSE;
    }if (WriteFile(this->m_Handle, this->m_Buffer, dwLen, 
    &m_dwByteWrittern, m_pOverLapped))
    {
    if (m_pOverLapped->Offset + dwLen <= 0xFFFFFFFF)
    {
    m_pOverLapped->Offset += dwLen;
    }
    else
    {
    m_pOverLapped->OffsetHigh++;//高位加1
    m_pOverLapped->Offset += (dwLen - 0xFFFFFFFF);
    }
    }请帮我看看代码有问题吗?
      

  18.   

    WriteFile前调用了FlushBuffer和HasOverlappedIoCompleted(m_pOverLapped),以保证输出没有错误        FlushFileBuffers(this->m_Handle); while (!HasOverlappedIoCompleted(m_pOverLapped))
    {
    Sleep(10); //这一句是否有必要? 
    }
    发出两个WriteFile命令,100byte偏移位的写和50byte偏移位的写,不管他们谁先写应该都没问题吧?
      

  19.   

    我现在的问题是第一次WriteFile后HasOverlappedIoCompleted(m_pOverLapped)返回true,第二次WriteFile之后再判断就一直是false
      

  20.   

    在打开文件之后要初始化m_pOverLapped指向的结构。
    每次WriteFile之前给m_pOverLapped->Offset赋值。
    如果WriteFile返回失败,用GetLastError取错误码,如果是ERROR_IO_PENDING说明没有错误。
    WriteFile后直接返回,最好不要立即修改m_pOverLapped->Offset,不确定对操作是否会有影响。
    FlushFileBuffers是多余的。
    等待操作完成可以在循环中Sheep(0),以降低CPU使用率,也可以等待事件。
    使用FILE_FLAG_NO_BUFFERING标志时,每次写入文件的位置和数据长度必须是磁盘扇区大小(通常是512)的整数倍。
      

  21.   

    我知道原因了,经测试,是因为我最后一次写入的数据量不是512的整数倍。
    虽然msdn上说了每次数据量要是vector的整数倍,但我没注意到最后一次不是,是680000,512的1328.125倍。
    取消FILE_FLAG_NO_BUFFERING就ok了。那请问高手,若用FILE_FLAG_NO_BUFFERING最后的数据应该怎么write呢?我的buffer是512的整数倍,将后面的buffer用0复位然后writefile整个buffer?那岂非有冗余数据?一般应该怎么做呢?
      

  22.   

    妈妈的,我用API写文件效率竟然比CStdioFile效率低了一半,写110M数据我用了4863毫秒,CStdiofile用了2704毫秒太伤自尊了!!!int nFlag = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;//只设了overlap参数是不是memcpy很耗时? 为什么我的代码效率这么低? 郁闷!
      

  23.   

    用FILE_FLAG_NO_BUFFERING就只能这样写,不过你可以再SetEndOfFile丢弃最后的冗余数据。
    内存复制耗时很少,相对磁盘操作来说可以忽略不计。可能是你的缓冲区开得太大,导致等待时间过长,降低了效率。
      

  24.   

    不好意思,我昨天的数据弄反了,应该是我自己的是2704毫秒 ,CStdiofile是4863毫秒;效率比它快了一倍左右。
    r.Format("buffer:%ld file:%ld", d1, d2);
    AfxMessageBox(r);
    昨天d1和d2反了。不好意思。^_^今天发现,用了FILE_FLAG_WRITE_THROUGH效率会降低,不用FILE_FLAG_NO_BUFFERING就是说使用系统缓存将和CStdiofile时间相近。debug版下大致:
    714M数据耗时分别是20289和47000;
    476M数据耗时分别是13344和26735,
    238M数据耗时分别是4961和11633;release版和debug版相似,时间只少了一点点,可见耗时基本都在IO上。
      

  25.   

    目前的问题就是使用VirtualAlloc保证每次分配的buffer大小是当前OS页面的整数倍了。谢谢cnzdgs ,非常感谢!JT,不知道我能不能加分。试试