C-读写文件和输出输出

问题

一直对C操作文件(读写)很模糊,不是很清楚,现系统的梳理下,彻底弄明白

说明:

这下面的程序在VS中编写和调试

基本知识

-----打开文件-----

fopen()

可以使用fopen()函数创建新文件和打开一个已有文件

会调用初始化类型FILE类型的一个对象,类型FILE包含所有用来控制二进制流的必要信息

函数原型为:

FILE *fopen( const char * filename, const char * mode );

参数介绍:

filename:是字符串,用来命名文件

mode:访问模式,下表中介绍:

模式描述
r 打开一个已有的文本文件,允许读取文件。
w 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容【覆盖】。如果文件存在,则该会被截断为零长度,重新写入。
a 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
r+ 打开一个文本文件,允许读写文件。
w+ 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。
a+ 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式

若是二进制文件,则用:

"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"

补充:

只有用 r+ 模式打开文件才能插入内容,w 或 w+ 模式都会清空掉原来文件的内容再来写,a 或 a+ 模式即总会在文件最尾添加内容,哪怕用 fseek() 移动了文件指针位置。

-----关闭文件-----

fclose()

fclose()函数,清空缓冲区的数据,关闭文件,释放文件中所有的内存

函数原型如下:

 int fclose( FILE *fp );

补充:

若关闭成功,则返回0;若关闭失败,返回EOF,EOF是一个定义在头文件stdio.h中的常量

-----写入文件-----

写入文件有很多方式,下面一一介绍:

fputc()

函数原型为:

int fputc( int c, FILE *fp );

介绍:

该函数是把参数int c的字符值写入fp指向的输入流中,若写入成功,则会返回写入字符;若写入失败,返回EOF

fputc()只能一次写入一个字符,与fputc()对应的是fgetc(),会在后面介绍

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    FILE* str = fopen("demo.txt", "w+");
    if (str == EOF)
    {
        printf("打开失败!");
    }
    printf("%c
", fputc(65, str));
    if (fclose(str) == EOF)
    {
        printf("写入失败!");
    }

    system("pause");
    return 0;
}

fputs()

函数原型:

int fputs( const char *s, FILE *fp );

介绍:

该函数是把字符串s写入到fp指向的输出流中,若写入成功,返回一个非负值;若写入失败,返回EOF

fputs()一次能写入一个字符串,与fputs()对应的是fgets(),会在后面介绍

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    FILE* str = fopen("demo.txt", "a+");//"a+"追加数据在文件中
    if (str == EOF)
    {
        printf("打开失败!");
    }
    printf("%d
", fputs("Helloworld", str));//写入成功后会返回一个非负值
    if (fclose(str) == EOF)
    {
        printf("写入失败!");
    }

    system("pause");
    return 0;
}

fprintf()

函数原型:

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

介绍:

stream:指向FILE的指针

format:指C字符串,包含了要被写入到流stream中的文本,可嵌入标签,标签可以被后面的参数中指定的值替换,并按需求格式化。

若写入成功,则返回字符总数;否则返回一个负数。与fprintf()对应的是fscanf(),会在后面介绍

标签格式以及具体说明如下:

%[flags][width][.precision][length]specifier
specifier(说明符)输出
c 字符
d 或 i 有符号十进制整数
e 使用 e 字符的科学科学记数法(尾数和指数)
E 使用 E 字符的科学科学记数法(尾数和指数)
f 十进制浮点数
g 自动选择 %e 或 %f 中合适的表示法
G 自动选择 %E 或 %f 中合适的表示法
o 有符号八进制
s 字符的字符串
u 无符号十进制整数
x 无符号十六进制整数
X 无符号十六进制整数(大写字母)
p 指针地址
n 无输出
% 字符
flags(标识)描述
- 在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。
+ 强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。
(space) 如果没有写入任何符号,则在该值前面插入一个空格。
# 与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。
与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。
与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。
0 在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)
width(宽度)描述
(number) 要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。
* 宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
.precision(精度)描述
.number 对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。
对于 e、E 和 f 说明符:要在小数点后输出的小数位数。
对于 g 和 G 说明符:要输出的最大有效位数。
对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。
对于 c 类型:没有任何影响。
当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。
.* 精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
length(长度)描述
h 参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。
l 参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。
L 参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    FILE* str = fopen("demo.txt", "a+");//"a+"追加数据在文件中
    if (str == EOF)
    {
        printf("打开失败!");
    }
    //追加数据时换行;
    fputs("
", str);
    printf("%d
", fprintf(str,"He%s wor%s !","llo","ld"));//写入成功后会返回一个非负值
    if (fclose(str) == EOF)
    {
        printf("写入失败!");
    }

    system("pause");
    return 0;
}

说明:

若想要在追加文件时,换行

//追加数据时换行;
fputs("
", str); 

putc()

函数声明:

int putc(int char, FILE *stream)

介绍:

将参数char指向的字符(无符号字符)写入到指定的stream中,并把位置标识符向前移。每次写入单个字符,和fputc()功能大致一样,与之相对的是getc(),会在下面介绍

  • char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。
  • stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。

返回值:若成功则返回写入的字符,若失败,返回EOF

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

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

    fp = fopen("file.txt", "w");
    for (ch = 33; ch <= 100; ch++)
    {
        printf("%c",putc(ch, fp));
    }
    fclose(fp);

    return(0);
}

fwrite()

函数声明:

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

介绍:

把ptr所指向数组中的数据写入到stream中,与fwrite()对应的是fread(),在下面会详细介绍

size_t:定义为 long long unsigned int,函数sizeof()返回类型就是这个

ptr:指向要被写入的元素数组的指针

size:要被写入的每个元素的大小,以字节为单位

nmemb:元素的个数,每个元素的大小为size字节

stream:指向FILE的指针

返回值:若成功,返回一个size_t对象,表示元素的总数,若该数字与nmemb参数不同,会报错

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    FILE* fp;
    char str[] = "This is runoob.com";

    fp = fopen("file.txt", "w");
    printf("%ld",fwrite(str, sizeof(str), 1, fp));//若成功,返回1,即元素的个数

    fclose(fp);
    return(0);
}

-----读取文件-----

fgetc()

函数原型为:

int fgetc(FILE *stream)

介绍:

从指定的流stream中获取下一个字符,并将位置标识符向前移动?

返回值:以无符号chat强制转换int返回值,返回字符;若失败,则返回EOF

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    FILE* fp;
    int c;
    int n = 0;

    fp = fopen("demo.txt", "r");
    if (fp == NULL)
    {
        perror("打开文件时发生错误");
        return(-1);
    }
    do
    {
        c = fgetc(fp);//读出一个字符后,位置指针自动后移
        if (feof(fp))
        {
            break;
        }
        printf("%c", c);
    } while (1);

    fclose(fp);
    system("pause");
    return(0);
}

fgets()

函数原型:

char *fgets(char *str, int n, FILE *stream)

介绍:

该函数从指定流stream中读取一行,并存在str所指向的字符串内,当读取(n-1)个字符时,或者读到换行符时,或达到文件末尾时,会停止

str:指向一个字符数组的指针,该数组中存储了要读取的字符串

n:这是要读取的最大字符数(包括最后的空字符),通常指以str传递的数组的长度

stream:指向FILE的指针

返回值:若返回成功,返回相同的str参数,若到达文件尾或者没有读取到任何字符,str内容不变,返回空指针;若返回出错,返回空指针

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    FILE* fp;
    char str[60];

    /* 打开用于读取的文件 */
    fp = fopen("demo.txt", "r");
    if (fp == NULL) {
        perror("打开文件时发生错误");
        return(-1);
    }
    if (fgets(str, 60, fp) != NULL) {
        /* 向标准输出 stdout 写入内容 */
        puts(str);//此时对这个函数还不是很熟悉后面会详细介绍
    }
    fclose(fp);
    system("pause");
    return(0);
}

这里用到了puts()函数,此时还不太了解,本来是想梳理一下文件管理,看来最基本的输入输出也得系统的学习一下,该函数后面会详细介绍

fscanf()

函数原型:

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

介绍:

从流stream中读取,并格式化输入到format指定的变量中,读取时遇到空格自动结束

参数大致和fprintf()一致,标签可以被后面的参数中指定的值替换,并按需求格式化

返回值:若成功,则返回成功匹配和赋值的个数;若到达文件末尾或发生读错误,则返回 EOF

format说明符和具体介绍如下:

[=%[*][width][modifiers]type=]
参数描述
* 这是一个可选的星号,表示数据是从流 stream 中读取的,但是可以被忽视,即它不存储在对应的参数中。
width 这指定了在当前读取操作中读取的最大字符数。
modifiers 为对应的附加参数所指向的数据指定一个不同于整型(针对 d、i 和 n)、无符号整型(针对 o、u 和 x)或浮点型(针对 e、f 和 g)的大小: h :短整型(针对 d、i 和 n),或无符号短整型(针对 o、u 和 x) l :长整型(针对 d、i 和 n),或无符号长整型(针对 o、u 和 x),或双精度型(针对 e、f 和 g) L :长双精度型(针对 e、f 和 g)
type 一个字符,指定了要被读取的数据类型以及数据读取方式。具体参见下一个表格。
类型合格的输入参数的类型
c 单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。 char *
d 十进制整数:数字前面的 + 或 - 号是可选的。 int *
e,E,f,g,G 浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4 float *
o 八进制整数。 int *
s 字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。 char *
u 无符号的十进制整数。 unsigned int *
x,X 十六进制整数。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    char str1[10], str2[10], str3[10];
    int year;
    FILE* fp;

    fp = fopen("file.txt", "w+");
    fputs("We are in 2014", fp);

    rewind(fp);
    fscanf(fp, "%s %s %s %d", str1, str2, str3, &year);

    printf("Read String1 |%s|
", str1);
    printf("Read String2 |%s|
", str2);
    printf("Read String3 |%s|
", str3);
    printf("Read Integer |%d|
", year);

    fclose(fp);
    system("pause");
    return(0);
}

这里用到了rewind()函数,下面来学习一下

getc()

函数声明:

int getc(FILE *stream)

介绍:

从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动,和fgetc类似

返回值:若返回成功,则返回读取到的字符;若到达文件末尾或发生读错误,则返回 EOF。

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

int main()
{
    char c;

    printf("请输入字符:");
    c = getc(stdin);
    printf("输入的字符:");
    putc(c, stdout);

    return(0);
}

这里用到了stdinstdout,需要说明一下:

标准文件

stdin和stdout其实都是一个fp,指向一个流,stdin指的是一个输入流,stdout指的就是一个输出流

更多介绍:

C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕。

标准文件文件指针设备
标准输入 stdin 键盘
标准输出 stdout 屏幕
标准错误 stderr 您的屏幕

fread()

函数声明:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

介绍:

将给定stream读取到ptr所指向的数组中

参数和fwrite()中的参数中类似,不再赘述

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    FILE* fp;
    char c[] = "This is runoob";
    char buffer[20];

    /* 打开文件用于读写 */
    fp = fopen("file.txt", "w+");

    /* 写入数据到文件 */
    fwrite(c, strlen(c) + 1, 1, fp);

    /* 查找文件的开头 */
    fseek(fp, 0, SEEK_SET);

    /* 读取并显示数据 */
    fread(buffer, strlen(c) + 1, 1, fp);
    printf("%s
", buffer);
    fclose(fp);

    return(0);
}

-----其他文件函数-----

rewind()

函数原型:

void rewind(FILE *stream)

介绍:

该函数将文件内部的位置指针重新指向一个流的开头,可以理解成,重新将位置指针重新移动到开始

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    char str[] = "This is runoob.com";
    FILE* fp;
    int ch;

    /* 首先让我们在文件中写入一些内容 */
    fp = fopen("file.txt", "w");
    fwrite(str, 1, sizeof(str), fp);
    fclose(fp);

    fp = fopen("file.txt", "r");
    while (1)
    {
        ch = fgetc(fp);
        if (feof(fp))
        {
            break;
        }
        printf("%c", ch);
    }
    rewind(fp); //重新将位置指针移动至开始
    printf("
");
    while (1)
    {
        ch = fgetc(fp);
        if (feof(fp))
        {
            break;
        }
        printf("%c", ch);

    }
    fclose(fp);
    system("pause");
    return(0);
}

这里用到了feof()函数,我们在下面详细介绍:

feof()

函数声明:

int feof(FILE *stream)

介绍:

该函数是测试给定stream的文件结束标识符

返回值:若位置指针指到了文件结束标识符时,即该流读完时,返回一个非零值;否则返回0

例子就是上面的例子

fseek()

函数声明:

int fseek(FILE *stream, long int offset, int whence)

介绍:

设置stream的文件位置为给定的偏移offset,offset指从给定的whence位置开始查找的字节数

stream:指向FILE的指针

offset:相对whence的偏移量,以字节为单位;负号前移,正号后移。

whence:表示开始添加偏移offset的位置,一般指下面常量之一:

常量描述
SEEK_SET 文件的开头
SEEK_CUR 文件指针的当前位置
SEEK_END 文件的末尾

SEEK_END 为文件结尾时,偏移量应该为负值,指从文件末尾向前偏移这个结构体那么多的长度给文件指针fp

返回值:若成功,则返回0;否则返回非零值

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    FILE* fp;
    int c;
    fp = fopen("file.txt", "w+");
    fputs("This is runoob.com", fp);

    fseek(fp, 8, SEEK_SET);
    fputs(" C Programming Langauge", fp);
    fclose(fp);

    fp = fopen("file.txt", "r");
    while (1)
    {
        c = fgetc(fp);
        if (feof(fp))
        {
            break;
        }
        printf("%c", c);
    }
    fclose(fp);
    return(0);
}

这里我们写入文件后,重新指定位置指针,在第8个位置,然后从这里开始写入

ftell()

函数声明:

long int ftell(FILE *stream)

介绍:

该函数能返回给定流stream的当前文件位置

返回值:返回位置标识符的当前值 【字节表示】;若出错,返回-1L

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

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

    fp = fopen("file.txt", "r");
    if (fp == NULL)
    {
        perror("打开文件错误");
        return(-1);
    }
    fseek(fp, 0, SEEK_END);

    len = ftell(fp); //返回文件位置的结尾
    fclose(fp);

    printf("file.txt 的总大小 = %d 字节
", len);
    return(0);
}

截止到这里,关于文件的读写,已经有一个大致的了解,下面再梳理一下输入输出:

输入输出

-----输入-----

puts()

函数声明:

int puts(const char *str)

介绍:

该函数将一个字符串写入标准输出中,直到空字符,但不包括空字符。换行符会被追加到输出中

str -- 这是要被写入的 C 字符串

返回值:若成功,返回一个非负值【字符串长度(包括末尾)】;若出错,则返回EOF

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

int main()
{
    char str1[15];
    char str2[15];

    strcpy(str1, "RUNOOB1");
    strcpy(str2, "RUNOOB2");

    puts(str1);
    puts(str2);

    return(0);
}

这里用到了strcpy()函数,下面介绍一下

---strcpy()---

函数声明:

char *strcpy(char *dest, const char *src)

介绍:

该函数把src指向的字符串复制到dest中,用到了<string.h>库

dest:指存储数据的目标数组

src:要复制的字符串

返回值:返回一个指向最终目标字符串dest的指针

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
    char src[40];
    char dest[100];

    memset(dest, '', sizeof(dest));//将''作为结尾符,添加到最后面
    strcpy(src, "This is runoob.com");
    strcpy(dest, src);

    printf("最终的目标字符串: %s
", dest);

    return(0);
}

这里又用到了memset()函数,下面来看一下该函数:

----memset()----

函数声明:

void *memset(void *str, int c, size_t n)

介绍:

该函数复制字符c(一个无符号字符)到参数str所指向的字符串的前n个字符

  • str -- 指向要填充的内存块。
  • c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
  • n -- 要被设置为该值的字符数。

返回值:返回一个指向存储区str的指针

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>


int main()
{
    char str[50];

    strcpy(str, "This is string.h library function");
    puts(str);

    memset(str, '$', 7);
    puts(str);

    return(0);
}

getchar()

函数声明:

int getchar(void)

介绍:

从标准输入 stdin 获取一个字符(一个无符号字符),这等同于 getc 带有 stdin 作为参数

从屏幕读取下一个可用的字符,并把它返回为一个整数。这个函数在同一个时间内只会读取一个单一的字符。您可以在循环内使用这个方法,以便从屏幕上读取多个字符。

返回值:若成功,返回对应的字符;若到达文件末尾或发生读错误,则返回 EOF

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

int main()
{
    char c;

    printf("请输入字符:");
    c = getchar();

    printf("输入的字符:");
    putchar(c);

    return(0);
}

-----输出-----

gets()

函数声明:

char *gets(char *str)

介绍:

从标准输入 stdin 读取一行,并把它存储在 str 所指向的字符串中。当读取到换行符或者到达文件末尾时,它会停止,具体视情况而定

返回值:若成功,该函数返回 str。如果发生错误或者到达文件末尾时还未读取任何字符,则返回 NULL。

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

int main()
{
    char str[50];

    printf("请输入一个字符串:");
    gets(str);

    printf("您输入的字符串是:%s", str);

    return(0);
}

putchar()

函数声明:

int putchar(int char)

介绍:

把参数 char 指定的一个字符(一个无符号字符)写入到标准输出 stdout 中,该字符以其对应的 int 值进行传递

把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符。您可以在循环内使用这个方法,以便在屏幕上输出多个字符。

返回值:若成功,则返回写入的字符;若发生错误则返回 EOF

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

int main()
{
    char ch;

    for (ch = 'A'; ch <= 'Z'; ch++) {
        putchar(ch);
    }

    return(0);
}

参考

1、C语言

2、C 库函数 - fprintf()

3、C 库函数 - fgetc()

4、C 库函数 - fgets()

5、文件读写

6、输入 & 输出

作者: Pam

出处: https://www.cnblogs.com/pam-sh/>

关于作者:网安在读

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(mir_soh@163.com)咨询.

原文地址:https://www.cnblogs.com/pam-sh/p/14847158.html