Ответ 1
Нет, нет возможности вставлять символы в существующий файл. Для этого вам понадобится второй файл.
Я написал программу, которая берет файл в качестве входных данных и всякий раз, когда он находит строку длиной > 80, она добавляет\и\n к этому файлу, чтобы сделать ее шириной 80 символов.
Проблема заключается в том, что я использовал fseek для вставки\и\n всякий раз, когда длина превышает 80, поэтому она переопределяет два символа этой строки, которая превышает длину 80. Есть ли способ, с помощью которого я могу вставлять текст без переопределения существующего текст?
Вот мой код: -
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
FILE *fp1,*fp2;
int prev=0,now=0;
char ch;
int flag=0;
long cur;
fp1=fopen(argv[1],"r+");
if(fp1==NULL){
printf("Unable to open the file to read. Program will exit.");
exit(0);
}
else{
while((ch=fgetc(fp1))!=EOF){
if(ch!=' ' && ch!='\n'){
now=now+1;
}
else{
if(now>=80){
fseek(fp1,cur,SEEK_SET);
fputc('\\',fp1);
fputc('\n',fp1);
now=0;
continue;
}
if(ch=='\n'){
flag=0;
now=0;
continue;
}
else{
prev=now;
cur=ftell(fp1);
}
now=now+1;
}
}
}
fclose(fp1);
return 0;
}
Чтобы запустить его, вам необходимо выполнить следующие действия: -
[email protected]$ cc xyz.c
[email protected]$ ./a.out file_to_check.txt
Нет, нет возможности вставлять символы в существующий файл. Для этого вам понадобится второй файл.
Хотя есть несколько способов сделать это на месте, вы работаете с текстовым файлом и хотите выполнять вставки. Операционные системы обычно не поддерживают вставки текстовых файлов в качестве примитива файловой системы, и нет причин, по которым они должны это делать.
Лучший способ сделать это - открыть файл для чтения, открыть новый файл для записи, скопировать часть файла до точки вставки, вставить данные, скопировать остальные, а затем переместить новый файл поверх старого.
Это обычная техника, и у нее есть цель. Если что-то пойдет не так (например, с вашей системой), у вас все еще есть исходный файл и вы можете повторить транзакцию позже. Если вы запускаете два экземпляра процесса и используете определенный шаблон, второй экземпляр может обнаружить, что транзакция уже запущена. Имея эксклюзивный доступ к файлам, он может даже определить, была ли транзакция прервана или все еще запущена.
Этот способ гораздо меньше подвержен ошибкам, чем любой из методов, выполняемых непосредственно на исходном файле, и используется всеми этими традиционными инструментами, такими как sed
, даже если вы попросите их работать на месте (sed -i
). Еще один бонус заключается в том, что вы всегда можете переименовать исходный файл в один с суффиксом резервного копирования, прежде чем перезаписывать его (sed
также предлагает такую опцию).
Такая же техника часто используется для файлов конфигурации, даже если ваша программа записывает совершенно новую версию и не использует для этого оригинальный файл. Уже давно многие интернет-журналы утверждали, что ext4 случайно обрезает конфигурационные файлы до нулевой длины. Это было именно потому, что некоторые приложения сохраняли файлы конфигурации открытыми и усеченными, когда система была принудительно отключена. Эти приложения часто подделывались исходными конфигурационными файлами, прежде чем они готовили данные, а затем даже открывали их, не синхронизируя их, что сделало окно для повреждения данных намного большим.
TL; версия DR:
Когда вы оцениваете свои данные, не уничтожайте их до того, как будете готовы к замене данных.
Нет, нет способа. Вам нужно создать новый файл или переместить содержимое файла на 2 символа назад.
Это функция, которую я использую для такого рода вещей:
int finsert (FILE* file, const char *buffer) {
long int insert_pos = ftell(file);
if (insert_pos < 0) return insert_pos;
// Grow from the bottom
int seek_ret = fseek(file, 0, SEEK_END);
if (seek_ret) return seek_ret;
long int total_left_to_move = ftell(file);
if (total_left_to_move < 0) return total_left_to_move;
char move_buffer[1024];
long int ammount_to_grow = strlen(buffer);
if (ammount_to_grow >= sizeof(move_buffer)) return -1;
total_left_to_move -= insert_pos;
for(;;) {
u16 ammount_to_move = sizeof(move_buffer);
if (total_left_to_move < ammount_to_move) ammount_to_move = total_left_to_move;
long int read_pos = insert_pos + total_left_to_move - ammount_to_move;
seek_ret = fseek(file, read_pos, SEEK_SET);
if (seek_ret) return seek_ret;
fread(move_buffer, ammount_to_move, 1, file);
if (ferror(file)) return ferror(file);
seek_ret = fseek(file, read_pos + ammount_to_grow, SEEK_SET);
if (seek_ret) return seek_ret;
fwrite(move_buffer, ammount_to_move, 1, file);
if (ferror(file)) return ferror(file);
total_left_to_move -= ammount_to_move;
if (!total_left_to_move) break;
}
seek_ret = fseek(file, insert_pos, SEEK_SET);
if (seek_ret) return seek_ret;
fwrite(buffer, ammount_to_grow, 1, file);
if (ferror(file)) return ferror(file);
return 0;
}
Используйте его следующим образом:
FILE * file= fopen("test.data", "r+");
ASSERT(file);
const char *to_insert = "INSERT";
fseek(file, 3, SEEK_SET);
finsert(file, to_insert);
ASSERT(ferror(file) == 0);
fclose(file);
Это (как другие, упомянутые здесь) может теоретически испортить файл, если есть ошибка, но вот какой-то код, чтобы на самом деле это сделать... Выполнение этого на месте, как это, как правило, хорошо, но вы должны сделать резервную копию файл, если вы беспокоитесь об этом...
Вы можете загрузить файл как фрагменты (в вашем случае - 80 символов), а затем добавить два символа (новая строка) и записать содержимое в файл anohter.