user-0 提问: 如何限制FILE *fp所创建的文件的大小，并追加文件？

回复:
user: user-1
content: 我的例子代码已经解决了楼主的问题。

user: user-0
content: 引用 15 楼 zhao4zhong1 的回复:仅供参考：#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef _MSC_VER     #pragma warning(disable:4996)     #include <windows.h>     #include <io.h> #else     #include <unistd.h>     #include <sys/time.h>     #include <pthread.h>     #define  CRITICAL_SECTION   pthread_mutex_t     #define  _vsnprintf         vsnprintf #endif //Log{ #define MAXLOGSIZE 20000000 #define MAXLINSIZE 16000 #include <time.h> #include <sys/timeb.h> #include <stdarg.h> char logfilename1[]="MyLog1.log"; char logfilename2[]="MyLog2.log"; static char logstr[MAXLINSIZE+1]; char datestr[16]; char timestr[16]; char mss[4]; CRITICAL_SECTION cs_log; FILE *flog; #ifdef _MSC_VER void Lock(CRITICAL_SECTION *l) {     EnterCriticalSection(l); } void Unlock(CRITICAL_SECTION *l) {     LeaveCriticalSection(l); } #else void Lock(CRITICAL_SECTION *l) {     pthread_mutex_lock(l); } void Unlock(CRITICAL_SECTION *l) {     pthread_mutex_unlock(l); } #endif void LogV(const char *pszFmt,va_list argp) {     struct tm *now;     struct timeb tb;      if (NULL==pszFmt||0==pszFmt[0]) return;     _vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);     ftime(&tb);     now=localtime(&tb.time);     sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);     sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );     sprintf(mss,"%03d",tb.millitm);     printf("%s %s.%s %s",datestr,timestr,mss,logstr);     flog=fopen(logfilename1,"a");     if (NULL!=flog) {         fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);         if (ftell(flog)>MAXLOGSIZE) {             fclose(flog);             if (rename(logfilename1,logfilename2)) {                 remove(logfilename2);                 rename(logfilename1,logfilename2);             }         } else {             fclose(flog);         }     } } void Log(const char *pszFmt,...) {     va_list argp;      Lock(&cs_log);     va_start(argp,pszFmt);     LogV(pszFmt,argp);     va_end(argp);     Unlock(&cs_log); } //Log} int main(int argc,char * argv[]) {     int i; #ifdef _MSC_VER     InitializeCriticalSection(&cs_log); #else     pthread_mutex_init(&cs_log,NULL); #endif     for (i=0;i<10000;i++) {         Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__);     } #ifdef _MSC_VER     DeleteCriticalSection(&cs_log); #else     pthread_mutex_destroy(&cs_log); #endif     return 0; } //1-79行添加到你带main的.c或.cpp的那个文件的最前面 //81-86行添加到你的main函数开头 //90-94行添加到你的main函数结束前 //在要写LOG的地方仿照第88行的写法写LOG到文件MyLog1.log中  这个里面运用了很多的结构类什么的，表示这些不是很明白，不过感谢大神的指教，对于之前的问题，我采用了一个折中的方法，就是存到一定的大小，将文件关闭改名，然后重新建立一个原来命名的日志文件进行追加。

user: user-0
content: 引用 9 楼 xy_kok 的回复:引用#8 通过第二条可以达到一定的预期目的，但是却是把原来的所有数据清空后重新写入的，如果我需要的是只清掉最早的，继续追加写入该如何弄了，就是假设有1000行，需要重新存入新的一行，但是大小已经达到了，这个时候就删除最早的一行，然后就可以写入一行了，这样的要如何操作了？  这个涉及到整体的文件内容迁移，暂时没想到好办法，如果不觉得麻烦的话，可以参考下面这种： 1.当文件未满是按原思路做； 2.当文件满时，创建一个临时文件，将除最早记录之外的文件内容复制到临时文件中，再清空原文件，之后将临时文件中的内容和新的内容写入到原文件中（临时文件只是为了保证原文件内容的完整性，但会损失一些效率）； 2-1. 要考虑到一点，可能会频繁的写入已经满的文件，此时，如果对写入内容没有过高的要求的话，可以将需要写入的内容存储到一个buffer中，当满足一定条件时，将buffer中的数据写入到文件，如此可避免过多的文件操作。 以上请参考。  这中方法确实是比较的麻烦，这估计会占用过多的内存吧。

user: user-0
content: 引用 10 楼 SXJIAKE 的回复:[quote=引用 7 楼 a1317296227 的回复:]是没有复制完全还是什么的，复制到我这边编译一大堆问题。且不知道各个的作用。 手打的，其中有一处错误，应为：sprintf(file2, "%s.%d", file, index++);我没有编译运行，因为有些变量没有声明，就比如 fwrite 这一行。如果你这个都看不明白的话，那我也没办法。我这个只是给个思路，即文件超出指定大小，则将文件关闭，改名，然后重新创建一个同名文件。举个例子，日志叫 debug.log，首次打开的时候，获取到末尾偏移，也就是大小了，然后每写入一行都会加上写入的字节数，如果超出一定大小，比如 4MB，则关闭该文件，循环查找 debug.log.0、debug.log.1、debug.log.2... 直到某个文件不存在，则将 debug.log 改名为这个名字，然后重新打开 debug.log 以这个名字继续写日志。即 debug.log 永远都是最新的内容。当然，你也可以以年月日时分秒作为后缀作为备份文件名，这样的话就更直观看到哪些是旧文件的了。这个思路其实是从 log4j 中学来的。[/quote]   // 限制大小 4MB int limit = 4 * 1024 * 1024; FILE *fp = fopen(file, "w+"); if (fp != NULL) {     fseek(fp, 0, SEEK_END);     int pos = ftell(fp);     while (...) {         // 循环写入数据         pos += fwrite(p, s, 1, fp);         // 如果文件大于指定字节数则关闭改名         // 重新以原始名称打开该文件         if (pos > limit) {             int index = 0;             while (1) {                 char file2[256];                 sprintf(file2, "%s.%d", index++);                 FILE *fp2 = fopen(file2, "r");                 if (fp2 != NULL) {                     fclose(fp2);                 } else {                     fflush(fp);                     fclose(fp);                     rename(file, file2);                     fp = fopen(file, "w+");                     pos = 0;                     break;                 }             }         }     }     fflush(fp);     fclose(fp); }   对于你的这一段函数中，pos += fwrite(p, s, 1, fp);这个的p,s不清楚； sprintf(file2, "%s.%d", file, index++);这个为什么这么写不清楚，为什么第一个是file2,第三个是file； 最后的                     pos = 0;                     break; 这两句不理解。  求大神指教，另外如果说是添加时间又是如何弄的了？

user: user-2
content: 引用引用 12楼 a1317296227的回复 ： 这中方法确实是比较的麻烦，这估计会占用过多的内存吧。  这种方法是比较麻烦，我暂时没有其他更好的办法。不过相比于频繁的操作文件（耗时，在加上flush操作就更麻烦了），占用些内存也无伤大雅。而且缓冲用的buffer不需要太大，可以根据流量设计一个合理的不大不小的值。

user: user-3
content: 引用这中方法  我答案里的方法比较简单，在1楼。

user: user-1
content: 仅供参考：#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef _MSC_VER     #pragma warning(disable:4996)     #include <windows.h>     #include <io.h> #else     #include <unistd.h>     #include <sys/time.h>     #include <pthread.h>     #define  CRITICAL_SECTION   pthread_mutex_t     #define  _vsnprintf         vsnprintf #endif //Log{ #define MAXLOGSIZE 20000000 #define MAXLINSIZE 16000 #include <time.h> #include <sys/timeb.h> #include <stdarg.h> char logfilename1[]="MyLog1.log"; char logfilename2[]="MyLog2.log"; static char logstr[MAXLINSIZE+1]; char datestr[16]; char timestr[16]; char mss[4]; CRITICAL_SECTION cs_log; FILE *flog; #ifdef _MSC_VER void Lock(CRITICAL_SECTION *l) {     EnterCriticalSection(l); } void Unlock(CRITICAL_SECTION *l) {     LeaveCriticalSection(l); } #else void Lock(CRITICAL_SECTION *l) {     pthread_mutex_lock(l); } void Unlock(CRITICAL_SECTION *l) {     pthread_mutex_unlock(l); } #endif void LogV(const char *pszFmt,va_list argp) {     struct tm *now;     struct timeb tb;      if (NULL==pszFmt||0==pszFmt[0]) return;     _vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);     ftime(&tb);     now=localtime(&tb.time);     sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);     sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );     sprintf(mss,"%03d",tb.millitm);     printf("%s %s.%s %s",datestr,timestr,mss,logstr);     flog=fopen(logfilename1,"a");     if (NULL!=flog) {         fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);         if (ftell(flog)>MAXLOGSIZE) {             fclose(flog);             if (rename(logfilename1,logfilename2)) {                 remove(logfilename2);                 rename(logfilename1,logfilename2);             }         } else {             fclose(flog);         }     } } void Log(const char *pszFmt,...) {     va_list argp;      Lock(&cs_log);     va_start(argp,pszFmt);     LogV(pszFmt,argp);     va_end(argp);     Unlock(&cs_log); } //Log} int main(int argc,char * argv[]) {     int i; #ifdef _MSC_VER     InitializeCriticalSection(&cs_log); #else     pthread_mutex_init(&cs_log,NULL); #endif     for (i=0;i<10000;i++) {         Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__);     } #ifdef _MSC_VER     DeleteCriticalSection(&cs_log); #else     pthread_mutex_destroy(&cs_log); #endif     return 0; } //1-79行添加到你带main的.c或.cpp的那个文件的最前面 //81-86行添加到你的main函数开头 //90-94行添加到你的main函数结束前 //在要写LOG的地方仿照第88行的写法写LOG到文件MyLog1.log中

user: user-2
content: 引用#8 通过第二条可以达到一定的预期目的，但是却是把原来的所有数据清空后重新写入的，如果我需要的是只清掉最早的，继续追加写入该如何弄了，就是假设有1000行，需要重新存入新的一行，但是大小已经达到了，这个时候就删除最早的一行，然后就可以写入一行了，这样的要如何操作了？  这个涉及到整体的文件内容迁移，暂时没想到好办法，如果不觉得麻烦的话，可以参考下面这种： 1.当文件未满是按原思路做； 2.当文件满时，创建一个临时文件，将除最早记录之外的文件内容复制到临时文件中，再清空原文件，之后将临时文件中的内容和新的内容写入到原文件中（临时文件只是为了保证原文件内容的完整性，但会损失一些效率）； 2-1. 要考虑到一点，可能会频繁的写入已经满的文件，此时，如果对写入内容没有过高的要求的话，可以将需要写入的内容存储到一个buffer中，当满足一定条件时，将buffer中的数据写入到文件，如此可避免过多的文件操作。 以上请参考。

user: user-4
content: 引用 7 楼 a1317296227 的回复:是没有复制完全还是什么的，复制到我这边编译一大堆问题。且不知道各个的作用。 手打的，其中有一处错误，应为：sprintf(file2, "%s.%d", file, index++);我没有编译运行，因为有些变量没有声明，就比如 fwrite 这一行。如果你这个都看不明白的话，那我也没办法。我这个只是给个思路，即文件超出指定大小，则将文件关闭，改名，然后重新创建一个同名文件。举个例子，日志叫 debug.log，首次打开的时候，获取到末尾偏移，也就是大小了，然后每写入一行都会加上写入的字节数，如果超出一定大小，比如 4MB，则关闭该文件，循环查找 debug.log.0、debug.log.1、debug.log.2... 直到某个文件不存在，则将 debug.log 改名为这个名字，然后重新打开 debug.log 以这个名字继续写日志。即 debug.log 永远都是最新的内容。当然，你也可以以年月日时分秒作为后缀作为备份文件名，这样的话就更直观看到哪些是旧文件的了。这个思路其实是从 log4j 中学来的。

user: user-5
content: fseek(fp_r,0L,SEEK_END); ulFileSize = ftell(fp_r);//文件总的字节数 if( ulFileSize>MAXBUFFER ) {     //Do something.... }

user: user-6
content: 只需要在循环最后检测如果文件大小写满了D关闭文件再用w的方式打开再关闭再用a+方式打开即可继续写入文件。

user: user-0
content: 引用 5 楼 xy_kok 的回复:想来想去没找到限制文件大小的函数原型，估摸着只能自己实现逻辑了。 简单点说：自己添加一个值作为文件的额定大小，操作文件时写入量切勿超过自己设定的额定值；其次fopen中w为清空写，a+为追加写，分情况选择打开文件方式；  #define FILESIZE 12312   // 定义文件大小  1. 获取文件大小(fseek, ftell配合使用) 2.检测当前文件大小与额定值的大小关系 if(filesize < FILESIZE) // 小于额定值 { fopen("xxx.txt", "a+") } else { fopen("xxx.txt", "w"); }  3. 写文件 left = FILESIZE - filesize； // 获取文件剩余量 res = fwrite(....); left -= res； 检测left的值，切勿使其值<=0  这是一个大概的逻辑，有两点需要注意： （1）. 当前逻辑适用于文件多次被打开关闭，如果只打开一次，3的逻辑还要更严谨一些，还要涉及到文件清空的问题； （2）. 文件未满，但需要的写入的量大于剩余量时，如何处理，这需要楼主根据业务要求自行定夺。  通过第二条可以达到一定的预期目的，但是却是把原来的所有数据清空后重新写入的，如果我需要的是只清掉最早的，继续追加写入该如何弄了，就是假设有1000行，需要重新存入新的一行，但是大小已经达到了，这个时候就删除最早的一行，然后就可以写入一行了，这样的要如何操作了？

user: user-0
content: 引用 4 楼 SXJIAKE 的回复:// 限制大小 4MB int limit = 4 * 1024 * 1024; FILE *fp = fopen(file, "w+"); if (fp != NULL) { 	fseek(fp, 0, SEEK_END);     int pos = ftell(fp); 	while (...) { 		// 循环写入数据 		pos += fwrite(p, s, 1, fp); 		// 如果文件大于指定字节数则关闭改名 		// 重新以原始名称打开该文件 		if (pos > limit) { 			int index = 0; 			while (1) { 				char file2[256]; 				sprintf(file2, "%s.%d", index++); 				FILE *fp2 = fopen(file2, "r"); 				if (fp2 != NULL) { 					fclose(fp2); 				} else { 					fflush(fp); 					fclose(fp); 					rename(file, file2); 					fp = fopen(file, "w+"); 					pos = 0; 					break; 				} 			} 		} 	} 	fflush(fp); 	fclose(fp); }   是没有复制完全还是什么的，复制到我这边编译一大堆问题。且不知道各个的作用。

user: user-0
content: 引用 1 楼 fight_in_dl 的回复:引用不知道如何处理 这个问题的关键是限定创建文件的大小，提供一个方法： #include <stdio.h> int main(void) {         int X = 1024 * 1024 - 1;         FILE *fp = fopen("myfile", "w");         fseek(fp, X , SEEK_SET);         fputc('\0', fp);          fclose(fp); } 如何删除文件内容？ fclose(fopen("file.txt", "w")); //w方式打开就会清空文件，之后再用添加模式打开文件即可  完整的程序您可以根据需求编写调试。 看不懂啊，没有注释，和我那个不知道如何结合起来好

user: user-3
content: 引用不知道如何处理 这个问题的关键是限定创建文件的大小，提供一个方法： #include <stdio.h> int main(void) {         int X = 1024 * 1024 - 1;         FILE *fp = fopen("myfile", "w");         fseek(fp, X , SEEK_SET);         fputc('\0', fp);          fclose(fp); } 如何删除文件内容？ fclose(fopen("file.txt", "w")); //w方式打开就会清空文件，之后再用添加模式打开文件即可  完整的程序您可以根据需求编写调试。

user: user-2
content: 想来想去没找到限制文件大小的函数原型，估摸着只能自己实现逻辑了。 简单点说：自己添加一个值作为文件的额定大小，操作文件时写入量切勿超过自己设定的额定值；其次fopen中w为清空写，a+为追加写，分情况选择打开文件方式；  #define FILESIZE 12312   // 定义文件大小  1. 获取文件大小(fseek, ftell配合使用) 2.检测当前文件大小与额定值的大小关系 if(filesize < FILESIZE) // 小于额定值 { fopen("xxx.txt", "a+") } else { fopen("xxx.txt", "w"); }  3. 写文件 left = FILESIZE - filesize； // 获取文件剩余量 res = fwrite(....); left -= res； 检测left的值，切勿使其值<=0  这是一个大概的逻辑，有两点需要注意： （1）. 当前逻辑适用于文件多次被打开关闭，如果只打开一次，3的逻辑还要更严谨一些，还要涉及到文件清空的问题； （2）. 文件未满，但需要的写入的量大于剩余量时，如何处理，这需要楼主根据业务要求自行定夺。

user: user-4
content: // 限制大小 4MB int limit = 4 * 1024 * 1024; FILE *fp = fopen(file, "w+"); if (fp != NULL) { 	fseek(fp, 0, SEEK_END);     int pos = ftell(fp); 	while (...) { 		// 循环写入数据 		pos += fwrite(p, s, 1, fp); 		// 如果文件大于指定字节数则关闭改名 		// 重新以原始名称打开该文件 		if (pos > limit) { 			int index = 0; 			while (1) { 				char file2[256]; 				sprintf(file2, "%s.%d", index++); 				FILE *fp2 = fopen(file2, "r"); 				if (fp2 != NULL) { 					fclose(fp2); 				} else { 					fflush(fp); 					fclose(fp); 					rename(file, file2); 					fp = fopen(file, "w+"); 					pos = 0; 					break; 				} 			} 		} 	} 	fflush(fp); 	fclose(fp); }