我想在我的程序中实现一个功能,该功能将.txt发送给我的电子邮件,其中包含我当天必须执行的一些任务。这是代码:
void txtCreator(){
/**file.dat and file.txt, respectively**/
FILE *fp, *fp1;
/**struct that contain the events**/
struct evento *display = (struct evento *)malloc(sizeof(struct evento));
char buffer[48];
char email_events[] = {"dd_mm.txt"};//filename.txt
char msg[]={"Nao ha eventos disponiveis para hoje!\n"};
int count=0;
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
strftime(buffer, 48, "%d_%m", &timenow);
fp = fopen(file_name, "rb");
fp1 = fopen(email_events, "w");
if(strcmp(buffer, email_events)!=0){
strcpy(email_events, buffer);
while(fread(display, sizeof(struct evento), 1, fp)==1){
if (feof(fp) || fp==NULL){
break;
}
else if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1){
fwrite(display, sizeof(struct evento), 1, fp1);
fprintf(fp1, "%s", "\n");
count++;
}
}
}
if(count==0){
fprintf(fp1, "%s", msg);
}
fclose(fp);
fclose(fp1);
}
一切正常,但是有两个问题:
1-
strcpy(email_events, buffer);
不起作用,并且:
2-
当我创建.txt文件时,它显示如下:
测试¹0(¹€(。€(.v™™°'¹8¹uguese_Brazil.12
它正确显示了事件名称(测试),但日期不起作用。
我尝试了很多事情,但是没有用。
很抱歉英语不好,不是我的母语。
答案 0 :(得分:0)
假设您要复制email_events
到buffer
中(因为已分配了静态字符串),则strcpy
参数是向后的。
下面是strcpy
char *strcpy(char *dest, const char *src);
您可能是说:
strcpy(buffer, email_events);
答案 1 :(得分:0)
当我创建.txt文件时,它显示如下:
test ¹0(¹€(.v™ ™ °'¹8¹uguese_Brazil.12
首先解决这个问题:您不是在.txt
文件中写入文本。您正在编写一个结构。看起来像垃圾。
例如,假设display->dia
是19。这意味着将数字19写入文件,而不是文本19
,即数字19。作为文本读取,19是垃圾。 10是换行符。 65是A
。
如果您打算将结构转储到文件中,并假设struct evento
没有指针,那很好。实际上,您可能不应该添加换行符,它会因结构的大小而干扰文件的读取。
如果您要生成人类可读的文本文件,则需要将每个结构片段转换为文本。例如,如果您想将日期和月份写为文本...
fprintf(fp1, "%d_%d", display->dia, display->mes);
我认为这会继续下去。
strcpy(email_events, buffer);
不起作用
乍看之下,您的strcpy
似乎是倒退的,它是strcpy(src, dest)
,大概是您想将email_events
复制到buffer
:strcpy(buffer, email_events)
中。
进一步,您的代码在此之后对buffer
或email_events
都无效。 strcpy
毫无意义。
更进一步,buffer
是07_19
之类的月份和日期。 email_events
始终为dd_mm.txt
。那些永远不会匹配。 strcmp(buffer, email_events)!=0
永远都是正确的,使得if
的检查毫无意义。
我不确定buffer
和email_events
的意图是什么,但是它似乎正在尝试根据当前日期创建文件名?可以使用一个更好命名的变量outfile
来简单得多。
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
char outfile[20];
strftime(outfile, 20, "%d_%m.txt", &timenow);
要解决其他问题,您不必检查fp1
是否已打开。
您最终确实检查了fp
,但是在之后对其进行了检查,您已经从可能为空的文件指针中读取了该内容。如果您compiling with an address sanitizer(应该这样做)将导致错误。使用null指针时导致错误很好,它将为您解决许多神秘的内存问题。
它更容易,更强大,并且可以立即检查地址是否友好。我们还可以更好地命名它们,以避免混淆输出in
和out
的输入。
FILE *in = fopen(file_name, "rb");
if( in == NULL ) {
perror(file_name);
exit(1);
}
由于您正在使用rb
读取二进制文件,因此您应该编写二进制文件,因此应该使用wb
。这仅在Windows上很重要,但也可能是一致的。
FILE *out = fopen(outfile, "wb");
if( out == NULL ) {
perror(outfile);
exit(1);
}
无需检查feof(fp)
,while(fread(display, sizeof(struct evento), 1, fp)==1)
在读取失败时将在文件末尾退出循环。通常,显式检查文件末尾会导致一些细微问题。
读取/写入循环现在更加简单。
while(fread(display, sizeof(struct evento), 1, in)==1){
if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1) {
fprintf(out, "%d_%d\n", display->dia, display->mes);
count++;
}
}
将它们放在一起...
void txtCreator(){
const char *no_events_found_msg = "Nao ha eventos disponiveis para hoje!\n";
// No need to cast the result of malloc, it just invites mistakes.
struct evento *display = malloc(sizeof(struct evento));
// Generate the output filename directly, no strcmp and strcpy necessary.
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
char outfile[20];
strftime(outfile, 48, "%d_%m.txt", &timenow);
// Immediatetly make sure the files are open and error immediately.
FILE *in = fopen(file_name, "rb");
if( in == NULL ) {
perror(file_name);
exit(1);
}
FILE *out = fopen(outfile, "wb");
if( out == NULL ) {
perror(outfile);
exit(1);
}
// Now that we know the files are open, reading and writing is much simpler.
int count=0;
while(fread(display, sizeof(struct evento), 1, in)==1){
if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1) {
fprintf(out, "%d_%d\n", display->dia, display->mes);
count++;
}
}
if(count==0){
fprintf(out, "%s", no_events_found_msg);
}
fclose(in);
fclose(out);
}
请注意,我使用了一种在适当位置声明变量的样式。这使代码更易于阅读,限制了每个变量的范围,并且避免了声明从未使用过的变量。