Truncate a large file in Windows

According to the function manual page truncatein R, on some platforms, including Windows:

... it will not work for large (> 2Gb) files

After some experiments, I managed to make a toy example showing that this can be done for large files (quite easily) with visual C ++:

// ConsoleApplication1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <iostream>
#include <string>

//  Forward declarations:
void append(LPCTSTR, LPCVOID, DWORD);
void readTail(LPCTSTR, LPVOID, DWORD);
void truncateTail(LPCTSTR, long);


int main()
{
    LPCTSTR fn = L"C:/kaiyin/kybig.out";
    char buf[] = "helloWorld"; 
    append(fn, buf, 10);
    BYTE buf1[10] = {0};
    readTail(fn, buf1, 5);
    std::cout << (char*) buf1 << std::endl;
    //truncateTail(fn, 5);
    //for (int i = 0; i < 10; i++) {
    //  buf1[i] = 0;
    //}
    //readTail(fn, buf1, 5);
    //std::cout << (char*) buf1 << std::endl;

    printf("End of program\n");
    std::string s = "";
    std::getline(std::cin, s);
    return 0;
}

void append(LPCTSTR filename, LPCVOID buf, DWORD writeSize) {
    LARGE_INTEGER size;
    size.QuadPart = 0;
    HANDLE fh = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    GetFileSizeEx(fh, &size);
    SetFilePointerEx(fh, size, NULL, FILE_BEGIN);
    WriteFile(fh, buf, writeSize, NULL, NULL);
    CloseHandle(fh);
}

void readTail(LPCTSTR filename, LPVOID buf, DWORD readSize) {
    LARGE_INTEGER size;
    size.QuadPart = 0;
    HANDLE fh = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    GetFileSizeEx(fh, &size);
    size.QuadPart -= readSize;
    SetFilePointerEx(fh, size, NULL, FILE_BEGIN);
    ReadFile(fh, buf, readSize, NULL, NULL);
    CloseHandle(fh);
}

void truncateTail(LPCTSTR filename, long truncateSize) {
    LARGE_INTEGER size;
    size.QuadPart = 0;
    HANDLE fh = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fh == INVALID_HANDLE_VALUE) {
        std::cerr << GetLastError();
        return;
    }
    GetFileSizeEx(fh, &size);
    size.QuadPart -= truncateSize;
    SetFilePointerEx(fh, size, NULL, FILE_BEGIN); 
    if (SetEndOfFile(fh) == 0) {
        std::cerr << GetLastError();
        return;
    }
    CloseHandle(fh);
}

This will add "helloWorld" to the file "C: /kaiyin/kybig.out" and then truncate the "World". In the console, it should print “World” (tail before truncation), then “hello” (tail after truncation).

There seems to be no problem trimming the tail of a file larger than 2 GB - in fact, I tested a file with a size of 4 bytes and the program still behaves correctly.

- , , truncate ( ) Windows?


Update

@hrbrmstr, R bugzilla, R-, , truncate Windows 8.1

filename = "C:/kaiyin/kybig.out"
f = file(filename, "w")
seek(f, 5L, "end")
truncate(f)
file.info(filename)$size

:

> filename = "C:/kaiyin/kybig.out"
> f = file(filename, "w")
> seek(f, 5L, "end")
[1] 0
> truncate(f)
NULL
> file.info(filename)$size
[1] 0

-, truncate , seek ing .

+2
2

- , , truncate ( ) Windows?

, Windows, R. Windows , , 32- , , , .

, , R , Windows.

+3

R, , Windows API , , POSIX ( POSIX-) , , , . , , , Windows Windows API ( ), , POSIX (-) , R, ( , . ).

0

Source: https://habr.com/ru/post/1608537/


All Articles