C语言中常用的stdio类方法详解

Posted by Buddy on April 14, 2024

C语言中的stdio.h头文件包含了很多与输入输出相关的函数,这些函数是C语言中常用的标准库函数之一。在本篇博客中,我们将列举并详细讲解一些常用的stdio类方法,帮助读者更好地理解它们的用途和功能。

1. printf()

printf()函数是C语言中用于向标准输出设备(通常是终端)打印格式化输出的函数。其基本语法如下:

int printf(const char *format, ...);

其中,format参数是一个格式字符串,它可以包含普通字符和格式说明符,...表示可变数量的参数。printf()函数根据格式字符串中的格式说明符,将后续参数格式化成相应的字符串,并输出到标准输出设备上。

示例:

int num = 10;
printf("The value of num is %d\n", num);

2. scanf()

scanf()函数是C语言中用于从标准输入设备(通常是键盘)读取格式化输入的函数。其基本语法如下:

int scanf(const char *format, ...);

format参数是一个格式字符串,它包含了一系列的格式说明符,用于指定输入数据的类型和格式。...表示可变数量的参数,用于接收输入的值。

示例:

int num;
printf("Enter a number: ");
scanf("%d", &num);

3. getchar() 和 putchar()

getchar()函数用于从标准输入设备读取一个字符,putchar()函数用于向标准输出设备输出一个字符。它们的基本语法如下:

int getchar(void);
int putchar(int c);

getchar()函数没有参数,每次调用将从标准输入设备读取一个字符并返回其ASCII码值。putchar()函数接受一个int类型的参数,它会将参数对应的ASCII码值转换成字符并输出到标准输出设备上。

示例:

char ch;
printf("Enter a character: ");
ch = getchar();
printf("You entered: ");
putchar(ch);

4. gets() 和 puts()

gets()函数用于从标准输入设备读取一行字符串,puts()函数用于向标准输出设备输出一行字符串。它们的基本语法如下:

char *gets(char *str);
int puts(const char *str);

gets()函数接受一个指向字符数组的指针作为参数,它会读取一行字符串(直到遇到换行符为止)并将其存储在指定的字符数组中,不包括换行符。puts()函数接受一个指向字符串的指针作为参数,它会输出该字符串并在末尾添加一个换行符。

示例:

char str[100];
printf("Enter a string: ");
gets(str);
printf("You entered: ");
puts(str);

5. fopen() 和 fclose()

fopen()函数用于打开一个文件,并返回一个指向该文件的文件指针,fclose()函数用于关闭一个文件。它们的基本语法如下:

FILE *fopen(const char *filename, const char *mode);
int fclose(FILE *stream);

fopen()函数接受两个参数,filename表示要打开的文件名,mode表示打开文件的模式(如”r”表示只读,”w”表示只写,”a”表示追加等)。fopen()函数成功打开文件时返回一个指向FILE类型的文件指针,否则返回NULLfclose()函数接受一个指向已打开文件的文件指针作为参数,用于关闭该文件。

示例:

FILE *fp;
fp = fopen("file.txt", "w");
if (fp != NULL) {
    fclose(fp);
} else {
    printf("Failed to open the file\n");
}

6. fprintf() 和 fscanf()

fprintf()函数和fscanf()函数分别用于向文件写入格式化输出和从文件读取格式化输入。它们的基本语法如下:

int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);

fprintf()函数将格式化的输出写入到指定的文件流中,而fscanf()函数从指定的文件流中读取格式化输入。它们的参数和用法与printf()scanf()函数类似,只是多了一个文件指针参数。

示例:

FILE *fp;
int num;
fp = fopen("file.txt", "r");
if (fp != NULL) {
    fscanf(fp, "%d", &num);
    printf("The number read from file: %d\n", num);
    fclose(fp);
} else {
    printf("Failed to open the file\n");
}

7. fseek() 和 ftell()

fseek()函数用于设置文件指针的位置,ftell()函数用于获取文件指针的当前位置。它们的基本语法如下:

int fseek(FILE *stream, long int offset, int origin);
long int ftell(FILE *stream);

fseek()函数将文件指针移到相对于指定起始位置的偏移量处,offset参数表示偏移量,origin参数表示起始位置(SEEK_SET表示文件起始位置,SEEK_CUR表示当前位置,SEEK_END表示文件末尾)。ftell()函数返回当前文件指针的位置。

示例:

FILE *fp;
long int position;
fp = fopen("file.txt", "r");
if (fp != NULL) {
    fseek(fp, 0L, SEEK_END);
    position = ftell(fp);
    printf("The size of the file: %ld bytes\n", position);
    fclose(fp);
} else {
    printf("Failed to open the file\n");
}

以上就是C语言中一些常用的stdio类方法的详细讲解。这些方法在文件操作和格式化输入输出中非常有用,掌握它们的用法能够帮助程序员更有效地进行文件处理和输入输出操作。

8. fgets() 和 fputs()

fgets()函数用于从文件中读取一行字符串,fputs()函数用于向文件中写入一行字符串。它们的基本语法如下:

char *fgets(char *str, int num, FILE *stream);
int fputs(const char *str, FILE *stream);

fgets()函数从指定的文件流中读取一行字符串,并将其存储到指定的字符数组中,最多读取num-1个字符,或者遇到换行符为止。fputs()函数将指定的字符串写入到指定的文件流中,不包括字符串的空终止符。

示例:

FILE *fp;
char str[100];
fp = fopen("file.txt", "r");
if (fp != NULL) {
    fgets(str, 100, fp);
    printf("The first line of the file: %s", str);
    fclose(fp);
} else {
    printf("Failed to open the file\n");
}

9. freopen()

freopen()函数用于重新打开一个已经存在的文件,并将其关联到一个不同的文件流。它的基本语法如下:

FILE *freopen(const char *filename, const char *mode, FILE *stream);

filename参数表示要打开的文件名,mode参数表示打开文件的模式,stream参数表示要重新关联的文件流。freopen()函数返回一个指向关联的文件流的指针。

示例:

FILE *fp;
fp = freopen("output.txt", "w", stdout);
if (fp != NULL) {
    printf("This will be written to output.txt\n");
    fclose(fp);
} else {
    printf("Failed to open the file\n");
}

10. feof() 和 ferror()

feof()函数用于检查文件流的文件结束标志,ferror()函数用于检查文件流的错误标志。它们的基本语法如下:

int feof(FILE *stream);
int ferror(FILE *stream);

feof()函数返回非零值(true)表示文件流已经到达文件结束位置,否则返回零值(false)。ferror()函数返回非零值(true)表示文件流上发生了错误,否则返回零值(false)。

示例:

FILE *fp;
int ch;
fp = fopen("file.txt", "r");
if (fp != NULL) {
    while ((ch = fgetc(fp)) != EOF) {
        putchar(ch);
    }
    if (feof(fp)) {
        printf("End of file reached\n");
    } else if (ferror(fp)) {
        printf("Error reading file\n");
    }
    fclose(fp);
} else {
    printf("Failed to open the file\n");
}

11. remove() 和 rename()

remove()函数用于删除指定的文件,rename()函数用于重命名文件。它们的基本语法如下:

int remove(const char *filename);
int rename(const char *old_filename, const char *new_filename);

remove()函数接受一个要删除的文件名作为参数,成功删除文件时返回零值,否则返回非零值。rename()函数接受两个参数,分别是要重命名的文件名和新的文件名,成功重命名文件时返回零值,否则返回非零值。

示例:

if (remove("oldfile.txt") == 0) {
    printf("File deleted successfully\n");
} else {
    printf("Failed to delete the file\n");
}

if (rename("oldfile.txt", "newfile.txt") == 0) {
    printf("File renamed successfully\n");
} else {
    printf("Failed to rename the file\n");
}

12. fflush()

fflush()函数用于刷新流的输出缓冲区。在默认情况下,输出到标准输出设备的数据会先被缓存起来,直到缓冲区满了或者遇到换行符才会输出到设备上。fflush()函数可以强制将缓冲区中的数据立即输出到设备上。它的基本语法如下:

int fflush(FILE *stream);

stream参数指定要刷新缓冲区的文件流。如果stream参数为NULL,则刷新所有输出缓冲区。

示例:

#include <stdio.h>

int main() {
    printf("This is some data to be flushed\n");
    fflush(stdout); // 刷新标准输出缓冲区
    printf("More data\n");
    return 0;
}

13. setbuf() 和 setvbuf()

setbuf()函数和setvbuf()函数用于设置文件流的缓冲区。setbuf()函数提供了一种简单的缓冲设置方式,而setvbuf()函数提供了更灵活的缓冲设置方式。它们的基本语法如下:

void setbuf(FILE *stream, char *buffer);
int setvbuf(FILE *stream, char *buffer, int mode, size_t size);

setbuf()函数用于设置文件流stream的缓冲区为bufferbuffer可以是一个自定义的字符数组,也可以是NULLsetvbuf()函数用于更详细地设置文件流stream的缓冲区,mode参数指定了缓冲模式,size参数指定了缓冲区的大小。

示例:

#include <stdio.h>

int main() {
    FILE *fp;
    char buffer[1024];
    
    // 使用setbuf设置标准输出的缓冲区
    setbuf(stdout, buffer);
    printf("This is some data buffered\n");

    // 使用setvbuf设置文件流的缓冲区
    fp = fopen("file.txt", "w");
    setvbuf(fp, NULL, _IOFBF, 1024); // 全缓冲模式,缓冲区大小为1024字节
    fprintf(fp, "This is some data written to file.txt\n");
    fclose(fp);

    return 0;
}

14. tmpfile() 和 tmpnam()

tmpfile()函数用于创建一个临时文件,并返回一个指向该临时文件的文件流。tmpnam()函数用于生成一个唯一的临时文件名。它们的基本语法如下:

FILE *tmpfile(void);
char *tmpnam(char *str);

tmpfile()函数创建一个临时文件,并返回一个指向该文件的文件指针。该临时文件通常是以二进制形式打开的。tmpnam()函数生成一个唯一的临时文件名,并将其存储到参数str所指向的字符数组中,如果str参数为NULL,则函数会返回一个静态分配的内存空间指向的字符串。

示例:

#include <stdio.h>

int main() {
    FILE *fp;
    char tmpname[L_tmpnam];
    char *filename;

    // 创建临时文件
    fp = tmpfile();
    if (fp != NULL) {
        printf("Temporary file created successfully\n");
        fclose(fp);
    } else {
        printf("Failed to create temporary file\n");
    }

    // 生成唯一的临时文件名
    filename = tmpnam(tmpname);
    if (filename != NULL) {
        printf("Temporary filename: %s\n", filename);
    } else {
        printf("Failed to generate temporary filename\n");
    }

    return 0;
}

15. perror()

perror()函数用于输出上一个函数调用发生的错误信息,通常与全局变量errno一起使用。它的基本语法如下:

void perror(const char *s);

s参数是一个字符串,用于在输出错误信息之前添加一些额外的描述信息。perror()函数会输出上一个函数调用的错误信息到标准错误流(stderr)中,并在末尾添加一个换行符。

示例:

#include <stdio.h>
#include <errno.h>

int main() {
    FILE *fp;
    fp = fopen("nonexistent_file.txt", "r");
    if (fp == NULL) {
        perror("Error opening file");
    }
    return 0;
}

16. clearerr()

clearerr()函数用于清除指定文件流的错误标志和文件结束标志。它的基本语法如下:

void clearerr(FILE *stream);

stream参数指定要清除错误标志和文件结束标志的文件流。调用clearerr()函数后,文件流的错误标志和文件结束标志将被清除,使得该文件流可以重新用于输入输出操作。

示例:

#include <stdio.h>

int main() {
    FILE *fp;
    int ch;

    fp = fopen("file.txt", "r");
    if (fp != NULL) {
        // 尝试读取一个字符
        ch = fgetc(fp);
        if (ch != EOF) {
            printf("Read character: %c\n", ch);
        } else {
            if (feof(fp)) {
                printf("End of file reached\n");
            } else if (ferror(fp)) {
                perror("Error reading file");
            }
            // 清除错误标志和文件结束标志
            clearerr(fp);
        }
        fclose(fp);
    } else {
        perror("Failed to open file");
    }

    return 0;
}

在上面的示例中,如果文件流遇到文件结束或者发生错误,会打印相应的信息并使用clearerr()函数清除错误标志和文件结束标志,以便后续重新使用文件流进行输入输出操作。

17. fseeko() 和 ftello()

在处理大型文件时,fseek()ftell() 函数可能无法处理大于 LONG_MAX 的文件大小和偏移量。为了解决这个问题,C标准引入了 fseeko()ftello() 函数,它们支持大于 LONG_MAX 的文件大小和偏移量。它们的基本语法如下:

int fseeko(FILE *stream, off_t offset, int whence);
off_t ftello(FILE *stream);

fseeko() 函数用于设置文件指针的位置,ftello() 函数用于获取文件指针的当前位置。与 fseek()ftell() 类似,fseeko()offset 参数和 ftello() 的返回值都是 off_t 类型,它是一个有符号整数类型,通常为 64 位。参数 whence 表示起始位置,其值可以是 SEEK_SETSEEK_CURSEEK_END,分别表示文件起始位置、当前位置和文件末尾。

示例:

#include <stdio.h>

int main() {
    FILE *fp;
    off_t position;

    fp = fopen("large_file.bin", "rb");
    if (fp != NULL) {
        fseeko(fp, 0, SEEK_END);
        position = ftello(fp);
        printf("File size: %lld bytes\n", (long long)position);
        fclose(fp);
    } else {
        perror("Failed to open file");
    }

    return 0;
}

在上面的示例中,我们使用了 fseeko() 函数将文件指针移动到文件末尾,然后使用 ftello() 函数获取文件大小。

18. getc_unlocked() 和 putc_unlocked()

getc_unlocked()putc_unlocked() 函数是线程不安全的版本,它们与 getc()putc() 函数功能相同,但效率更高。这些函数不进行线程锁定操作,因此在多线程环境下使用时需要谨慎。

这些函数可以提高文件输入输出的性能,但是需要确保在调用这些函数时不会有其他线程同时访问相同的文件流。

示例:

#include <stdio.h>

int main() {
    FILE *fp;
    char ch;

    fp = fopen("file.txt", "r");
    if (fp != NULL) {
        while ((ch = getc_unlocked(fp)) != EOF) {
            putchar(ch);
        }
        fclose(fp);
    } else {
        perror("Failed to open file");
    }

    return 0;
}

在上面的示例中,我们使用了 getc_unlocked() 函数来读取文件中的字符,并使用 putc_unlocked() 函数将字符输出到标准输出设备。

19. fdopen()

fdopen() 函数用于将已存在的文件描述符关联到一个 FILE* 文件流,并返回一个指向该文件流的指针。它的基本语法如下:

FILE *fdopen(int fd, const char *mode);

fd 参数是一个文件描述符,mode 参数是一个字符串,表示打开文件的模式,与 fopen() 函数的模式参数相同。fdopen() 函数将已存在的文件描述符关联到一个文件流,并根据指定的模式打开文件。

示例:

#include <stdio.h>
#include <fcntl.h>

int main() {
    int fd;
    FILE *fp;

    fd = open("file.txt", O_RDONLY);
    if (fd != -1) {
        fp = fdopen(fd, "r");
        if (fp != NULL) {
            // 使用 fp 进行文件读取操作
            fclose(fp);
        } else {
            perror("fdopen failed");
        }
    } else {
        perror("open failed");
    }

    return 0;
}

在上面的示例中,我们首先使用 open() 函数打开一个文件,然后使用 fdopen() 函数将文件描述符关联到一个 FILE* 文件流,以便后续使用标准 I/O 函数进行文件读取操作。

20. popen() 和 pclose()

popen() 函数用于创建一个管道并启动一个新的进程,然后将该进程的标准输入或标准输出关联到一个 FILE* 文件流,并返回指向该文件流的指针。pclose() 函数用于关闭通过 popen() 函数创建的进程。

popen() 函数的基本语法如下:

FILE *popen(const char *command, const char *mode);

command 参数是一个字符串,表示要执行的命令,mode 参数是一个字符串,表示打开文件的模式,通常是 "r""w",分别表示只读模式和只写模式。

pclose() 函数的基本语法如下:

int pclose(FILE *stream);

stream 参数是一个指向通过 popen() 函数创建的文件流的指针,pclose() 函数用于关闭该文件流,并等待相关的进程结束。

示例:

#include <stdio.h>

int main() {
    FILE *fp;
    char buffer[1024];

    // 通过管道执行一个命令并读取其输出
    fp = popen("ls -l", "r");
    if (fp != NULL) {
        while (fgets(buffer, sizeof(buffer), fp) != NULL) {
            printf("%s", buffer);
        }
        pclose(fp);
    } else {
        perror("popen failed");
    }

    return 0;
}

在上面的示例中,我们使用 popen() 函数执行 ls -l 命令,并读取其输出。然后使用 pclose() 函数关闭通过 popen() 函数创建的文件流,并等待相关的进程结束。

21. rewind()

rewind() 函数用于将文件流的文件位置指示器重新定位到文件的起始位置,清除文件流的错误标志和文件结束标志。它的基本语法如下:

void rewind(FILE *stream);

stream 参数是一个指向要重新定位的文件流的指针。调用 rewind() 函数后,文件位置指示器会被设置为文件的起始位置,文件流的错误标志和文件结束标志会被清除。

示例:

#include <stdio.h>

int main() {
    FILE *fp;
    char buffer[100];

    fp = fopen("file.txt", "r");
    if (fp != NULL) {
        fgets(buffer, sizeof(buffer), fp);
        printf("Before rewind: %s\n", buffer);

        rewind(fp); // 重新定位文件位置指示器到文件起始位置

        fgets(buffer, sizeof(buffer), fp);
        printf("After rewind: %s\n", buffer);

        fclose(fp);
    } else {
        perror("Failed to open file");
    }

    return 0;
}

在上面的示例中,我们首先使用 fgets() 函数读取文件中的一行内容,然后调用 rewind() 函数将文件位置指示器重新定位到文件的起始位置,再次使用 fgets() 函数读取文件中的一行内容。

22. tmpfile64() 和 fdopen64()

在一些平台上,tmpfile()fdopen() 函数可能无法处理大于 LONG_MAX 的文件大小和偏移量。为了解决这个问题,一些系统提供了 tmpfile64()fdopen64() 函数,它们支持大于 LONG_MAX 的文件大小和偏移量。

tmpfile64() 函数用于创建一个临时文件,并返回一个指向该临时文件的文件流。fdopen64() 函数用于将已存在的文件描述符关联到一个 FILE* 文件流,并返回一个指向该文件流的指针。

这些函数的使用方法与 tmpfile()fdopen() 函数类似,但是支持大于 LONG_MAX 的文件大小和偏移量。

示例:

#include <stdio.h>
#include <fcntl.h>

int main() {
    FILE *fp;

    fp = tmpfile64();
    if (fp != NULL) {
        printf("Temporary file created successfully\n");
        fclose(fp);
    } else {
        perror("Failed to create temporary file");
    }

    return 0;
}

在上面的示例中,我们使用了 tmpfile64() 函数创建了一个临时文件。如果 tmpfile64() 函数不可用,可以尝试使用 fdopen64() 函数将一个已存在的文件描述符关联到一个文件流。

23. _flushall()

_flushall() 函数用于刷新所有的输出缓冲区。它的作用类似于 fflush(NULL),但是 _flushall() 函数是一个 Microsoft 特定的扩展函数,通常用于 Windows 平台上。它的基本语法如下:

int _flushall(void);

调用 _flushall() 函数将会刷新所有的输出缓冲区,将缓冲区中的数据立即输出到设备上。这对于确保所有的输出都被及时写入文件或者显示到屏幕上是非常有用的。

示例:

#include <stdio.h>

int main() {
    printf("This is some data to be flushed\n");
    _flushall(); // 刷新所有的输出缓冲区
    printf("More data\n");
    return 0;
}

在上面的示例中,我们使用了 _flushall() 函数刷新所有的输出缓冲区,以确保所有的输出都被及时写入到标准输出设备上。

24. tempnam()

tempnam() 函数用于生成一个临时文件名,并返回一个指向该文件名的字符串指针。它的基本语法如下:

char *tempnam(const char *dir, const char *prefix);

dir 参数是一个字符串,表示临时文件的目录路径,如果 dir 参数为 NULL,则会在系统默认的临时文件目录中创建临时文件。prefix 参数是一个字符串,表示临时文件名的前缀部分。

tempnam() 函数会根据指定的目录路径和前缀生成一个唯一的临时文件名,并返回一个指向该文件名的字符串指针。注意,生成的临时文件名由调用者负责释放。

示例:

#include <stdio.h>

int main() {
    char *tmpfile;

    tmpfile = tempnam("/tmp", "tmp");
    if (tmpfile != NULL) {
        printf("Temporary filename: %s\n", tmpfile);
        free(tmpfile); // 释放临时文件名字符串内存
    } else {
        perror("Failed to generate temporary filename");
    }

    return 0;
}

在上面的示例中,我们使用了 tempnam() 函数在 /tmp 目录中生成了一个以 tmp 为前缀的临时文件名,并打印出来。然后我们释放了 tempnam() 函数返回的字符串指针所指向的内存。

25. feof_unlocked() 和 ferror_unlocked()

feof_unlocked()ferror_unlocked() 函数与 feof()ferror() 函数类似,用于检查文件流的文件结束标志和错误标志。但是,它们是线程不安全的版本,不会进行线程锁定操作,因此在多线程环境下使用时需要谨慎。

这些函数与 feof()ferror() 函数的使用方法相同,但是可以提高文件操作的性能。然而,需要注意的是,在多线程环境中同时操作同一个文件流时,可能会发生竞态条件,因此需要特别小心。

示例:

#include <stdio.h>

int main() {
    FILE *fp;

    fp = fopen("file.txt", "r");
    if (fp != NULL) {
        int ch;
        while ((ch = fgetc_unlocked(fp)) != EOF) {
            putchar(ch);
        }
        if (feof_unlocked(fp)) {
            printf("End of file reached\n");
        } else if (ferror_unlocked(fp)) {
            perror("Error reading file");
        }
        fclose(fp);
    } else {
        perror("Failed to open file");
    }

    return 0;
}

在上面的示例中,我们使用了 feof_unlocked()ferror_unlocked() 函数来检查文件流的文件结束标志和错误标志,以及使用 fgetc_unlocked() 函数来逐个读取文件中的字符。这些函数与它们的线程安全版本相比,可以提高文件操作的性能,但需要注意在多线程环境下可能会出现的竞态条件。

26. getchar_unlocked() 和 putchar_unlocked()

getchar_unlocked()putchar_unlocked() 函数是 getchar()putchar() 函数的线程不安全版本,它们可以提高输入输出的性能。这些函数不进行线程锁定操作,因此在多线程环境下使用时需要谨慎。

getchar_unlocked() 函数用于从标准输入流中获取一个字符,而 putchar_unlocked() 函数用于向标准输出流中输出一个字符。

示例:

#include <stdio.h>

int main() {
    int ch;

    printf("Enter some text: ");
    while ((ch = getchar_unlocked()) != EOF) {
        putchar_unlocked(ch);
    }

    return 0;
}

在上面的示例中,我们使用了 getchar_unlocked() 函数从标准输入中逐个获取字符,并使用 putchar_unlocked() 函数将字符逐个输出到标准输出中。这些函数与它们的线程安全版本相比,可以提高输入输出的性能,但需要注意在多线程环境下可能会出现的竞态条件。

27. fileno()

fileno() 函数用于获取文件流对应的文件描述符。文件描述符是一个非负整数,用于标识已打开的文件或者其他I/O对象。fileno() 函数的基本语法如下:

int fileno(FILE *stream);

stream 参数是一个指向已打开文件流的指针,该函数返回文件流对应的文件描述符。通常情况下,文件描述符被用于底层系统调用或者其他需要使用文件描述符的场景。

示例:

#include <stdio.h>

int main() {
    FILE *fp;
    int fd;

    fp = fopen("file.txt", "r");
    if (fp != NULL) {
        fd = fileno(fp);
        printf("File descriptor for file.txt: %d\n", fd);
        fclose(fp);
    } else {
        perror("Failed to open file");
    }

    return 0;
}

在上面的示例中,我们使用了 fileno() 函数获取了文件流对应的文件描述符,并将其打印出来。

总结

stdio.h头文件中定义的函数提供了丰富的文件操作和输入输出功能,使得C语言能够处理各种文件和数据。通过掌握这些函数的用法,程序员可以更加灵活地操作文件、进行输入输出,并能够更好地编写高效、可靠的程序。以上就是C语言中一些常用的stdio类方法的详细讲解。这些函数在C语言编程中起着非常重要的作用,掌握它们的用法能够提高程序的编写效率和可读性。