Самый эффективный способ - поиск конца файла и перемещение указателя конца файла назад.К сожалению, это не переносимо, потому что в стандартных библиотеках C или C ++ не существует стандартного способа установки указателя конца файла.Вам необходимо использовать платформо-зависимую функцию, например SetEndOfFile
в Windows или ftruncate
в POSIX.Например:
void RemoveFinalNewline(const char *filename)
{
#if defined(_WIN32)
HANDLE hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
; // handle error
LARGE_INTEGER fileSize;
if(GetFileSizeEx(hFile, &fileSize) == 0)
; // handle error
if(fileSize.QuadPart < 2)
; // this case is left as an exercise to the reader
LARGE_INTEGER newFilePtr;
newFilePtr.QuadPart = -2;
if(SetFilePointerEx(hFile, &newFilePtr, NULL, FILE_END) == 0)
; // handle error
char lastTwoBytes[2];
if(ReadFile(hFile, lastTwoBytes, 2, NULL, NULL) == 0)
; // handle error
if(lastTwoBytes[1] == '\n')
{
fileSize.QuadPart--;
if(lastTwoBytes[0] == '\r')
fileSize.QuadPart--;
if(SetFilePointerEx(hFile, &fileSize, NULL, FILE_BEGIN) == 0)
; // handle error
if(SetEndOfFile(hFile) == 0)
; // handle error
// Success!
}
// else the file didn't end in a newline
CloseHandle(hFile); // and we're done
#else // POSIX case; the non-Windows, non-POSIX case is left as an exercise
int fd = open(filename, O_RDWR);
if(fd == -1)
; // handle error
off_t fileSizeMinus1 = lseek(fd, -1, SEEK_END);
if(fileSizeMinus1 == (off_t)-1)
; // handle error
// We're assuming that a newline is a bare LF '\n' here. The CRLF case
// is left as an exercise (hint: see the Windows case above)
char lastChar;
if(read(fd, &lastChar, 1) != 1)
; // handle error
if(lastChar == '\n')
{
if(ftruncate(fd, fileSizeMinus1) == -1)
; // handle error
// else success!
}
// else the file does not end in a newline
close(fd); // and we're done
#endif
}