我有一个Linux C程序,它将配置参数存储在文本文件中。我使用
从文本文件中读取 FILE *file = fopen(filename, "r"):
使用以下代码
写入文件 FILE *file = fopen(filename, "w"):
我遇到问题,文本文件被清除,下次我来读它时它是空白的。 据我所知,当文件被打开以进行写入时,它会被覆盖,我的程序在读取文件后将其内容存储起来并将其写回。 它在主要部分正确地写出来,但偶尔我会发现文本文件是空白的。
我最初的想法是,这可能是因为程序被不安全地停止,在写入文件的过程中,将其留空或者有2个程序运行实例,并且打开它进行写入,另一个读取它,意思是它会读取一个空白文件,然后在写出来时用空白文件覆盖它。 经过一些测试后,情况似乎并非如此。
这让我不确定导致文本文件被清除的原因。 有没有人有任何想法?
见下面的代码
char text_lines[200][54]; /* global variable */
void read_in_text_file()
{
/* this sub reads in the text file */
//printf("read in file\n");
/* declares the variables */
char line[128];
int counter = 0;
int length;
/* open a text file and read it in line by line, storing each line in a variable. also returning a value for the number of lines in each section */
static const char filename[] = "config.txt";
FILE *file = fopen(filename,"r"); /* opens the config file */
if (file==NULL){ /* checks if the file has successfully opened */
perror ("Error opening file"); /* displays error message on stderr - that returns reason file did not open */
printf("Error opening file\n"); /* tells the user that the file has not opened */
exit(0); /* exits the program if the text file can not be read in */
}
else{
//printf("the file is open\n");
while ( fgets ( line, sizeof line, file ) != NULL) /* reads each line of the text file */
{
sprintf(text_lines[counter],"%s",line); /* puts the line into a variable */
length = zstrlen(text_lines[counter]); /* calculates the length of the text not including \r or \n characters */
if(text_lines[counter][length-1] == '\n') /* checks if the last character is \n (a new line character) */
{
text_lines[counter][length-1] = '\0'; /* removes this new line character and replaces it with end of line identifier */
}
counter = counter + 1; /* uses a counter for each line */
} /* end of while loop */
number_of_lines = counter; /* puts the number of lines into a integer variable */
fclose(file); /* closes the file */
}
} /* end of sub for reading in the text file */
/* some changes may be made to the config before it is printed to the file again */
void print_to_text_file()
{
pthread_mutex_lock(&lock); /* block until thread has ownership */
/* sub for printing all the lines in the text_lines variable to the text file "config.txt" */
int counter;
static const char filename[] = "config.txt";
FILE *file = fopen(filename,"w"); /* opens the config.txt file, with write privileges */
if (file==NULL){ /* checks if the file has successfully opened */
perror ("Error opening file"); /* displays error message on stderr - that returns reason file did not open */
printf("Error opening file\n"); /* tells the user that the file has not opened */
}
else{
//printf("the file is open\n"); /* prints to the terminal screen the file has opened */
for (counter = 0; counter < number_of_lines; counter++) /* uses a for loop to scroll through all text lines */
{
// printf("%s\n",text_lines[counter]);
fprintf(file, "%s\n",text_lines[counter]); /* prints current text line to the file */
}
fclose(file); /* closes the file */
}
pthread_mutex_unlock(&lock); /* release blocking on thread */
} /* end of print text to file sub */
答案 0 :(得分:3)
首先,您应该知道当您使用fopen
和模式w
打开文件时,文件会立即被截断为零字节(删除其内容)。您可以使用w+
或wa
来阻止此操作。
其次,当您完成文件时,可能会遗漏fclose()
来关闭文件。虽然程序退出时,通常会关闭所有文件。但是,如果不关闭该文件,则对其所做的更改可能不会提交到磁盘。
由于您更新了问题以包含一些代码,我可以说您的程序不安全,并且如果文件包含超过200行,则可能会超出text_lines
缓冲区。如果您可以提供一个可以编译和运行的实际完整但最小的测试程序,它将帮助您下次获得更多答案。
这是一个可以编译和运行的实际程序。它读入config.txt
行,将所有字符转换为大写字母,然后将这些行写回文件。我删除了你的pthread互斥函数调用,因为在这个测试程序中没有必要(没有多线程)。
#include <ctype.h> /* toupper */
#include <stdio.h> /* fopen, fclose, fgets, perror */
#include <stdlib.h> /* exit */
#include <string.h> /* strlen */
/* Constants */
/* Maximum number of lines to read */
#define TEXT_LINES_CAPACITY 54
/* Maximum length of a line including EOL and NUL */
#define MAX_LINE_LEN 200
/* Global variables */
char text_lines[TEXT_LINES_CAPACITY][MAX_LINE_LEN]; /* text of lines */
int number_of_lines; /* number of lines in text_lines */
/* Function declarations */
void capitalize_string(char* s);
void strip_eol(char* s);
void read_in_text_file(void);
void print_to_text_file(void);
/* Function definitions */
int main()
{
int i;
/* Read in the contents of the file. */
read_in_text_file();
/* Modify it by capitalizing the text. */
for (i = 0; i < number_of_lines; ++i)
{
capitalize_string(text_lines[i]);
}
/* Write out the modified contents to the same file. */
print_to_text_file();
return 0;
}
void capitalize_string(char* s)
{
while (*s != 0)
{
*s = toupper(*s);
++s;
}
}
/* Open a text file and read it in line by line. The lines are stored in the
* global variable text_lines and the number of lines in number_of_lines. */
void read_in_text_file(void)
{
static const char filename[] = "config.txt";
FILE *file = fopen(filename,"r"); /* opens the config file */
if (file == NULL)
{
/* Print error message after the file name. */
perror(filename);
exit(1); /* Exit with failure code (nonzero) */
}
else
{
/* Read each line of the text file. */
while (number_of_lines < TEXT_LINES_CAPACITY &&
fgets(text_lines[number_of_lines], MAX_LINE_LEN, file) != NULL)
{
strip_eol(text_lines[number_of_lines]);
++number_of_lines;
}
fclose(file);
}
}
/* Remove LF and/or CR characters from the end of the string. */
void strip_eol(char* s)
{
/* Loop while the string ends with a CR or LF character. */
while (strlen(s) > 0 &&
(s[strlen(s) - 1] == '\n' ||
s[strlen(s) - 1] == '\r'))
{
/* Erase the last character. */
s[strlen(s) - 1] = '\0';
}
}
/* Write all the lines of text_lines to the text file "config.txt" */
void print_to_text_file(void)
{
static const char filename[] = "config.txt";
/* open the config.txt file, with write privileges */
FILE *file = fopen(filename,"w");
if (file == NULL)
{
/* Print error message after the file name. */
perror(filename);
}
else
{
int i;
/* Iterate over all text lines. */
for (i = 0; i < number_of_lines; i++)
{
fprintf(file, "%s\n", text_lines[i]); /* prints current text line to the file */
}
fclose(file); /* closes the file */
}
}