Я просто собираюсь затронуть часть вопроса «отредактировать файл на месте», хотя, похоже, это не совсем то, что вы искали. Вы найдете множество решений, описывающих функции, которые, как утверждают, выполняют редактирование на месте, но обычно эти решения вообще не редактируют файл. Вместо этого они записывают во временный файл, а затем перезаписывают оригинал временным файлом. (например, sed --in-place
является распространенным решением, которое записывает во временный файл). Редактирование файла на месте - это то, что вы практически никогда не хотите делать, поскольку изменение файла опасно. Действительно, если вы считаете, что хотите отредактировать файл на месте, серьезно подумайте и предположите, что вы не правы. Тем не менее, если по какой-то причине вам действительно нужно это сделать, возможно, безопаснее всего это сделать:
#include <err.h>
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
FILE * xfopen(const char *path, const char *mode);
int is_regular(int, const char *);
int
main(int argc, char **argv)
{
const char *rpath = argc > 1 ? argv[1] : "stdin";
const char *wpath = argc > 1 ? argv[1] : "stdout";
FILE *fr = argc > 1 ? xfopen(rpath, "r") : stdin;
FILE *fw = argc > 1 ? xfopen(wpath, "r+") : stdout;
char buf[BUFSIZ];
int c;
size_t rc;
off_t length = 0;
/* Discard the first line */
while( (c = getc(fr)) != EOF && c != '\n' ) {
;
}
if( c != EOF) while( (rc = fread(buf, 1, BUFSIZ, fr)) > 0) {
size_t wc;
wc = fwrite(buf, 1, rc, fw);
length += wc;
if( wc!= rc) {
break;
}
}
if( fclose(fr) ) {
err(EXIT_FAILURE, "%s", rpath);
}
if( is_regular(fileno(fw), wpath) && ftruncate(fileno(fw), length)) {
err(EXIT_FAILURE, "%s", wpath);
}
if( fclose(fw)) {
err(EXIT_FAILURE, "%s", wpath);
}
return EXIT_SUCCESS;
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
is_regular(int fd, const char *name)
{
struct stat s;
if( fstat(fd, &s) == -1 ) {
perror(name);
exit(EXIT_FAILURE);
}
return !!(s.st_mode & S_IFREG);
}
В явном виде довольно ясно, что вы можете легко потерять данные в файле. Но если вы хотите избежать чтения всего файла в память или не иметь двух копий на нескольких носителях одновременно, нет способа избежать этого, и любое решение, скрывающее этот риск, обманывает вас. Так что сделать это явно и знать, где опасность l ie - это то, что нужно делать.