简体   繁体   English

C:从一个文件读取,排序,然后输出到另一个

[英]C: Read from one file, Sort, and then Output to another

I'm just getting into C and I figured this would be a good exercise. 我刚接触C,我认为这将是一个很好的练习。 I've been putsing around with fgets trying to read from a file and I am just doing something wrong. 我一直在尝试从文件读取fgets,但我做错了什么。 I would like to enter the file name to read, enter the file name to output to, create that file, sort it (just a list of words), and then dump the sorted list into the created file. 我想输入要读取的文件名,输入要输出到的文件名,创建该文件,对其进行排序(只是单词列表),然后将排序后的列表转储到创建的文件中。 I know I should be doing something like: 我知道我应该做类似的事情:

char strIn[25];
printf("Enter a source filename: ");
fgets(strIn, 25, stdin);
printf("You entered: %s \n", strIn);
FILE *infile;    
infile = fopen(strIn, "r");
if (infile == NULL){
    printf("Unable to open file.");
}


char strOut[25];
printf("Enter a destination filename: ");
fgets(strOut, 25, stdin);
printf("You entered: %s \n", strOut);
FILE *outfile;

Any help is appreciated! 任何帮助表示赞赏! Thank you 谢谢

fgets puts the newline character \\n at the end of your buffer. fgets将换行符\\n放在缓冲区的末尾。 So you need to remove it. 因此,您需要将其删除。

int length = strlen(strIn);
if ( length > 0 && strIn[length-1] == '\n' )
    strIn[length-1] = '\0';

You are on the right track. 您走在正确的轨道上。 qsort will do what you want. qsort会做你想要的。 The approach used here is not scalable; 这里使用的方法是不可扩展的。 everything is held in memory and static allocation will make things HUGE very quickly, but it works as a toy example. 一切都保存在内存中,并且静态分配会使事情变得非常快,但这只是一个玩具示例。 At the moment it will break once there are more than 1000 lines in the input file. 现在,一旦输入文件中的行数超过1000行,它将中断。

# include <stdio.h>
# include <string.h>

#define MAXNAMELEN 100
#define MAXLINELEN 100
#define MAXITEMS 1000

int main(int argc, char ** argv) {

    FILE * infile, * outfile;
    // Statically allocated -- dastardly!
    char name[MAXNAMELEN];
    char line[MAXLINELEN];
    char lines[MAXITEMS][MAXLINELEN];
    int i, items = 0;

    printf("Enter a source filename: ");
    fgets(name, sizeof(name), stdin);
    name[strlen(name)-1] = '\0'; // strip newline
    // No error checking -- ANYWHERE -- dastardly!
    infile = fopen(name, "r");
    while (fgets(line, sizeof(line), infile)) {
            strcpy(lines[items], line);
            items++;
    }

    qsort(lines, items, MAXLINELEN, strcmp);

    printf("Enter a destination filename: ");
    fgets(name, sizeof(name), stdin);
    name[strlen(name)-1] = '\0'; // strip newline
    outfile = fopen(name, "w");
    for (i=0; i<items; i++) {
        fputs(lines[i], outfile);
    }

    fclose(infile);
    fclose(outfile);
}

Now with dynamic allocation and error-checking (possibly an improvement on than the version above). 现在具有动态分配和错误检查功能(可能是对上述版本的改进)。 Sorts /usr/share/dict/words (99171 lines) no problem at all. 排序/usr/share/dict/words (99171行)根本没有问题。 Still requires that the entire array be held in memory. 仍然需要将整个阵列保存在内存中。 See External Sorting for a way around that. 有关解决此问题的方法,请参见外部排序

# include <stdio.h>
# include <string.h>
# include <stdlib.h>

#define CHUNKLEN 100 
#define INITITEMS 1000

/* Reads a string from stream into buffer until a newline or EOF.  
   buffer is dynamically allocated (and reallocated if necessary) 
   to ensure the string fits. Returns the number of characters put
   into the buffer (zero if EOF and no characters read), or -1 on error. */

int unlimited_read(char ** buffer, FILE * stream) {

    int bufl = CHUNKLEN;
    int strl = 0;
    char * chunk = (char *)malloc(CHUNKLEN);

    if ( (*buffer = (char *) malloc(CHUNKLEN)) == NULL ) {
        perror("memory error (malloc)");
        return -1;
    }

    while (fgets(chunk, CHUNKLEN, stream) != NULL) {

        strcpy(*buffer + strl, chunk);
        strl += strlen(chunk);

        if ( (strl == bufl - 1 ) && *(*buffer + strl - 1) != '\n')  {

            // lengthen buffer
            bufl += CHUNKLEN - 1;
            if ( (*buffer = realloc(*buffer, bufl)) == NULL ) {
                perror("memory error (realloc)");
                return -1;
            }

        } else {
            // This shouldn't fail -- we're only ever making it smaller
            *buffer = realloc(*buffer, strl);
            return strl;
        }

    } // while

    // If fgets returned NULL and we are not at EOF, it didn't work
    return feof(stream) ? strl : -1;
}

/* Compare two strings given pointers to those strings.
   Routine is courtesy of the qsort man page */

int cmpstringp(const void *p1, const void *p2) {
    return strcmp(* (char * const *) p1, * (char * const *) p2);
}

/* Sort lines in a file.  File must end with a newline. */
int main(int argc, char ** argv) {

    FILE * infile, * outfile;
    char * inname, * outname, *tmpstr;
    char ** lines;
    int ret, tmp, nlines, i, items = 0;

    if (argc != 3) {
        printf("Usage: %s file_to_sort output_file\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    inname = argv[1];
    outname = argv[2];  

    if ( (lines = malloc(INITITEMS * sizeof(char *))) == NULL) {
        perror("memory error (malloc)");
        exit(EXIT_FAILURE);
    }

    nlines = INITITEMS;

    infile = fopen(inname, "r");
    while ((ret = unlimited_read(&lines[items], infile)) > 0) {
            items++;
            if (items == nlines) {
                nlines += INITITEMS;
                lines = realloc(lines, (nlines * sizeof(char *)));
            }
    }

    if (ret < 0) {
        printf("WARNING: possibly truncated file\n");
    }

    tmpstr = lines[items - 1]; // Final line in file
    tmp = strlen(tmpstr); 
    if (tmpstr[tmp - 1] != '\n') {
        printf("Error: input file does not end with newline\n");
        exit(EXIT_FAILURE);
    }

    qsort(lines, items, sizeof(char *), cmpstringp);

    outfile = fopen(outname, "w");

    for (i = 0; i < items; i++) {
        fputs(lines[i], outfile);
        free(lines[i]);
    }
    free(lines);

    fclose(infile);
    fclose(outfile);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM