我正在制作一个程序,将文件分成N个较小的部分 几乎相同的尺寸。所以这是我的代码:
FILE * fp = fopen(file,"r");
long aux;
long cursor = 0;
long blockSize = 1024000; //supose each smaller file will have 1 MB
long bytesLimit = blockSize;
for( i = 0 ; i < n ; i++) {
FILE * fp_aux = fopen( outputs[i] , "w"); //outputs is an array of temporary file names
while(cursor < bytesLimit) { //here occurs the infinite loop
fscanf(fp,"%lu\n",&aux);
fprintf(fp_aux,"%lu\n",aux);
cursor = ftell(fp);
}
fclose(fp_aux);
bytesLimit = bytesLimit + blockSize;
}
//here add some more logic to get the remaining content left in the main file
如果我想将文件分成两个或三个部分,代码可以工作,但是当我尝试将其拆分为10个部分时,fscanf
会锁定读取相同的数字并在那里保持无限循环。 / p>
我的输入文件格式为“%lu \ n”,如下所示:
1231231
4341342
4564565
...
答案 0 :(得分:2)
如果拆分文件是焦点,那么简化您的方法。因为你的帖子表明你正在使用文本文件,所以假设它包含带有标点符号,数字,换行符等的单词。对于这种类型的内容,可以使用fgets()/ fputs()将其解析为行。这将允许您从一个大文件中读取行,跟踪累积的大小,并将行写入几个较小的文件......
一些简单的步骤 :
1) 确定要拆分的文件的文件大小
2) 设置所需的小文件大小
3) 打开大文件
4) 在循环中使用fgets / fputs,打开和关闭文件以分割内容,使用累积大小作为分割点。
5) 清理。 (fclose文件等)
以下是一个说明这些步骤的示例。无论文本内容如何,这都会按大小拆分大文本文件。 (我使用了一个体积为130K的文本文件并将其分成5k的片段
#define SEGMENT 5000 //approximate target size of small file
long file_size(char *name);//function definition below
int main(void)
{
int segments=0, i, len, accum;
FILE *fp1, *fp2;
long sizeFile = file_size(largeFileName);
segments = sizeFile/SEGMENT + 1;//ensure end of file
char filename[260]={"c:\\play\\smallFileName_"};//base name for small files.
char largeFileName[]={"c:\\play\\largeFileName.txt"};//change to your path
char smallFileName[260];
char line[1080];
fp1 = fopen(largeFileName, "r");
if(fp1)
{
for(i=0;i<segments;i++)
{
accum = 0;
sprintf(smallFileName, "%s%d.txt", filename, i);
fp2 = fopen(smallFileName, "w");
if(fp2)
{
while(fgets(line, 1080, fp1) && accum <= SEGMENT)
{
accum += strlen(line);//track size of growing file
fputs(line, fp2);
}
fclose(fp2);
}
}
fclose(fp1);
}
return 0;
}
long file_size(char *name)
{
FILE *fp = fopen(name, "rb"); //must be binary read to get bytes
long size=-1;
if(fp)
{
fseek (fp, 0, SEEK_END);
size = ftell(fp)+1;
fclose(fp);
}
return size;
}
答案 1 :(得分:1)
如果文件中的数据不是一个长的无符号整数格式,那么fscanf会读取它,fp文件对象的文件指针不会改变。然后程序将fp文件指针设置回该读取的开头,它将再次执行
为了防止这种情况,您需要检查fscanf的返回值,看它是否具有适当的值(可能为1)
答案 2 :(得分:0)
如果要将文件拆分为多个部分,并指定每个部分指定的最大文件大小,为什么要使用fscanf(..)
,ftell(..)
和fprintf(..)
?
这不是实现目标的最快方式......
我建议这样做:
!feof(..)
)fread
)fwrite
)如果这样做,拆分文件将不会超过特定的最大文件大小。此外,您可以避免使用fprintf
等慢速文件I / O函数。
可能的实现如下所示:
/*
** splitFile
** Splits an existing input file into multiple output files with a specified
** maximum file size.
**
** Return Value:
** Number of created result files, or 0 in case of bad input data or a negative
** value in case of an error during file splitting.
*/
int splitFile(char *fileIn, size_t maxSize)
{
int result = 0;
FILE *fIn;
FILE *fOut;
char buffer[1024 * 16];
size_t size;
size_t read;
size_t written;
if ((fileIn != NULL) && (maxSize > 0))
{
fIn = fopen(fileIn, "rb");
if (fIn != NULL)
{
fOut = NULL;
result = 1; /* we have at least one part */
while (!feof(fIn))
{
/* initialize (next) output file if no output file opened */
if (fOut == NULL)
{
sprintf(buffer, "%s.%03d", fileIn, result);
fOut = fopen(buffer, "wb");
if (fOut == NULL)
{
result *= -1;
break;
}
size = 0;
}
/* calculate size of data to be read from input file in order to not exceed maxSize */
read = sizeof(buffer);
if ((size + read) > maxSize)
{
read = maxSize - size;
}
/* read data from input file */
read = fread(buffer, 1, read, fIn);
if (read == 0)
{
result *= -1;
break;
}
/* write data to output file */
written = fwrite(buffer, 1, read, fOut);
if (written != read)
{
result *= -1;
break;
}
/* update size counter of current output file */
size += written;
if (size >= maxSize) /* next split? */
{
fclose(fOut);
fOut = NULL;
result++;
}
}
/* clean up */
if (fOut != NULL)
{
fclose(fOut);
}
fclose(fIn);
}
}
return (result);
}
上面的代码在大约500毫秒内将大小为126803945字节的测试文件拆分成121个1MB的部分。
请注意,缓冲区的大小(此处:16KB)会影响文件的分割速度。缓冲区越大,分割的文件越快。如果你想使用非常大的缓冲区(大约1MB左右),你必须在每次调用时分配(并释放)缓冲区(如果你不需要重入代码,则使用静态缓冲区)。