将文件拆分为C中的n个较小文件

时间:2015-05-13 18:07:28

标签: c

我正在制作一个程序,将文件分成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
...

3 个答案:

答案 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(..)? 这不是实现目标的最快方式......

我建议这样做:

  1. 打开输入文件
  2. 只要有输入数据(!feof(..)
  3. 打开输出文件(如果尚未打开)
  4. 读取输入数据块(fread
  5. 将数据块写入输出文件(fwrite
  6. 跟踪写入的字节数,如果达到最大文件大小,则关闭输出文件
  7. 返回第2步。
  8. 清理
  9. 如果这样做,拆分文件将不会超过特定的最大文件大小。此外,您可以避免使用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左右),你必须在每次调用时分配(并释放)缓冲区(如果你不需要重入代码,则使用静态缓冲区)。