【问题标题】:Add/Remove bytes from end of file on Windows在 Windows 上从文件末尾添加/删除字节
【发布时间】:2014-01-18 16:57:34
【问题描述】:

所以,我环顾四周,但找不到在不重写整个文件的情况下从文件末尾删除字节的方法。我发现a truncate function 适用于 linux,但没有找到适用于 windows 的任何东西。现在,显然,要扩展文件,我可以用空字节填充结尾,但是为了减小文件的大小,是否真的有必要在 Windows 上重写整个文件?或是否有一个函数(可能在 windows.h 中)允许我(如 linux 上的 truncate)重新分配文件的大小?

编辑: 我刚刚找到了函数@987654322@,我正在阅读如何使用它。

编辑: 而且,为什么 fstream 忽略了这个重要功能?

编辑:好吧,看来_chdir() 不起作用(我忘了提这个,顺便说一句),因为函数必须支持大于 4 GB 的文件 - 即,我使用的是 64 位文件指针。我认为这是与生俱来的,但在阅读了chsize 的参数后,长度不是size_t

【问题讨论】:

  • 不是真的 - 我不一定会使用 system 命令行函数来运行已经在 c++ 中作为函数的进程(即 SetEndOfFile)。
  • 链接到 Apache Portable Runtime 并使用 apr_file_trunc apr.apache.org/docs/apr/1.4/…
  • 对不起,不,谢谢 - 我不能完全附加一个库并将我的所有代码切换到 apache 文件函数以获得一个函数的能力。
  • @AUTO:抱歉误读了您的问题,在编辑窗口后意识到但留下了链接,因为它可能对其他人有帮助。

标签: c++ windows filesize truncate


【解决方案1】:

您可能需要SetEndOfFile 函数。

编辑:这应该适用于大于 4GB 的文件。为此使用SetFilePointerEx 函数。

【讨论】:

  • SetFilePointerSetFilePointerEx 都支持大于 4GB 的文件。
  • @IInspectable:我知道,但第一个似乎很难使用。
【解决方案2】:

您可以通过调用SetFilePointerSetFilePointerEx 到所需位置,然后调用SetEndOfFile 来截断文件。下面展示了如何实现truncate 函数:

bool truncate( HANDLE hFile, LARGE_INTEGER NewSize ) {
    LARGE_INTEGER Size = { 0 };
    if ( GetFileSizeEx( hFile, &Size ) ) {
        LARGE_INTEGER Distance = { 0 };
        // Negative values move the pointer backward in the file
        Distance.QuadPart = NewSize.QuadPart - Size.QuadPart;
        return ( SetFilePointerEx( hFile, Distance, NULL, FILE_END ) &&
                 SetEndOfFile( hFile ) );
    }
    return false;
}

// Helper function taking a file name instead of a HANDLE
bool truncate( const std::wstring& PathName, LARGE_INTEGER NewSize ) {
    HANDLE hFile = CreateFileW( PathName.c_str(), GENERIC_WRITE, FILE_SHARE_READ,
                                NULL, OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL, NULL );
    if ( hFile == INVALID_HANDLE_VALUE ) {
        return false;
    }
    bool Success = truncate( hFile, NewSize );
    CloseHandle( hFile );
    return Success;
}

编辑:短版 truncate 函数可以简写为:

bool truncate( HANDLE hFile, LARGE_INTEGER NewSize ) {
    return ( SetFilePointerEx( hFile, NewSize, NULL, FILE_BEGIN ) &&
             SetEndOfFile( hFile ) );
}

如果您希望传递缩小文件的字节数,可以使用以下实现:

bool truncate( HANDLE hFile, LARGE_INTEGER ShrinkBy ) {
    ShrinkBy.QuadPart = -ShrinkBy.QuadPart;
    return ( SetFilePointerEx( hFile, ShrinkBy, NULL, FILE_END ) &&
             SetEndOfFile( hFile ) );
}

要增大文件,请使用 CreateFile 和包含 FILE_APPEND_DATAdwDesiredAccess 打开文件。再次使用SetFilePointer 将文件指针设置为文件末尾,然后您可以调用WriteFile 写入新数据。例如,请参阅Appending One File to Another File


编辑:在不写入的情况下扩展文件

如果您不关心超出原始文件大小的文件内容,您可以应用与截断文件相同的顺序来扩展它:

bool SetFileSize( HANDLE hFile, LARGE_INTEGER NewSize ) {
    return ( SetFilePointerEx( hFile, NewSize, NULL, FILE_BEGIN ) &&
             SetEndOfFile( hFile ) );
}

这是SetEndOfFile 的记录行为:

SetEndOfFile 函数可用于截断或扩展文件。如果文件被扩展,文件的旧端和新端之间的文件内容没有定义。

【讨论】:

  • 我喜欢这个答案,但我想在正式接受之前让它工作。不过可能需要一段时间;我仍在研究如何做到这一点。我不经常使用windows功能。
  • 谢谢!为了增加文件,我只使用了 ofstream::write 在最后转储一个归零的缓冲区(如有必要,可以多次)。我很确定这是同一件事..
  • @AUTO 实际上,如果您传递大于当前大小的NewSize 参数,您也可以调用truncate增长 文件。这可能比调用ofstream::write() 提供更好的性能。
【解决方案3】:

在 Windows 上从文件末尾删除字节:

FSUTIL file seteof <filename> <new size>

将(空)字节添加到(现有)文件的末尾:

FSUTIL file seteof <filename> <new size>

无需复制/“在windows上重写整个文件”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    相关资源
    最近更新 更多