文件IO,缓冲区

今天主要学习了标准io和文件io以及缓冲区的概念

一,标准io与文件io的区别

操作系统为了方便用户使用系统功能而对外提供的一组系统函数。称之为 系统调用  其中有个  文件IO, 一般都是对设备文件操作,当然也可以对普通文件进行操作。一个基于Linux内核的没有缓存的IO机制,文件IO没有缓冲区。

1.文件IO的特性

(1)没有缓存区

(2)操作对象不在是流,而是文件描述符

(3)文件描述符:很小的非负的整数    int   0-1023,内核每打开一个文件就会获得一个文件    描述符

每个程序在启动的时候操作系统默认为其打开
          三个描述符与流对象匹配:
          0 ==>STDIN_FILENO === stdin
          1 ==>STDOUT_FILENO == stdout
          2 ==>STDERR_FILENO == stderr
          stdin,stdout,stderr,===>FILE*
          ansi c 
          unistd.h ===>POSIX 标准库

2.标准IO和文件IO的后缀

w == O_WRONLY | O_CREAT | O_TRUNC 
w+ == O_RDWR | O_CREAT | O_TRUNC 
r == O_RDONLY 
r+ == O_RDWR
a == O_WRONLY | O_CREAT | O_APPEND
a+ == O_RDWR|O_CREAT|O_APPEND

3.文件IO的操作流程

(1)打开:open
(2)读写:read / write 
(3)关闭:close

二,标准io函数

1.fseek函数,

*FILE stream:指向FILE对象的指针,该对象标识了要进行操作的文件。这个FILE对象应该是通过fopen、freopen或fdopen等函数成功打开的文件指针。
long offset:表示要移动的字节数。正数表示向文件末尾方向移动,负数表示向文件开头方向移动。
int whence:表示移动的起始位置,它必须是以下三个常量之一:
SEEK_SET(通常为0):文件开头。
SEEK_CUR(通常为1):当前位置。

如图,输出结果是buf is hello,world!

#include <stdio.h>

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

    // 移动文件指针到文件开头后10个字节的位置
    fseek(fp, 10, SEEK_SET);

    // 在当前位置写入数据(如果文件大小不足10字节,则可能会写入文件末尾之后的位置,但这在文本模式下可能不会立即显示)
    fputs("Hello, World!", fp);

    // 重置文件指针到文件开头
    fseek(fp, 0, SEEK_SET);

    // 读取并打印文件内容(注意:如果之前写入了数据,但文件原本不足10字节,则打印的内容可能包含未定义的行为)
    char buffer[100];
    if (fgets(buffer, sizeof(buffer), fp) != NULL)
    {
        printf("%s", buffer);
    }

    fclose(fp);
    return 0;
}

2.ftell函数 获得文件字节大小

*FILE stream:指向 FILE 对象的指针,该对象标识了要查询偏移量的文件。这个 FILE 对象应该是通过 fopen、freopen 或 fdopen 等函数成功打开的文件指针。

ftell 函数通常与 fseek 函数一起使用,以在文件中进行随机访问。你可以使用 fseek 将文件指针移动到文件的某个特定位置,然后使用 ftell 来获取该位置的偏移量,或者简单地使用 ftell 来获取当前读写位置的偏移量。(偏移到最后就可以看文件字节的大小)

运行结果

记得指针复位rewind函数

3.rewind函数 指针复位

*FILE stream:需要复位 FILE 的指针。当使用rewind函数后,文件内部的位置指针会被移动到文件的开头,但文件本身的内容不会发生改变。

#include <stdio.h>

int main() 
{
    FILE *fp = fopen("example.txt", "w+"); // 以读写模式打开文件
    if (fp == NULL) 
    {
        perror("Error opening file");
        return -1;
    }

    fprintf(fp, "Hello, world!\n"); // 写入内容到文件

    // 使用ftell函数获取当前文件位置指针的偏移量(可选,用于演示)
    long pos = ftell(fp);
    printf("Before rewind, file position: %ld bytes\n", pos);

    rewind(fp); // 将文件内部的位置指针移动到开头

    // 再次使用ftell函数获取当前文件位置指针的偏移量(可选,用于演示)
    pos = ftell(fp);
    printf("After rewind, file position: %ld bytes\n", pos);

    // 读取文件内容并打印(可选,用于演示)
    char buffer[100];
    if (fgets(buffer, sizeof(buffer), fp) != NULL) 
    {
        printf("File content: %s", buffer);
    }

    fclose(fp); // 关闭文件
    return 0;
}

三,文件io  适合执行设备类文件

以下都需要包这些头文件

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

1.open函数

pathname:必需,待打开/创建文件的路径名。
flags:必需,指定文件的打开/创建模式,如O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)、O_CREAT(创建文件)等。
mode:可选,当flags中包含O_CREAT时,用于指定新文件的访问权限。

如果里面加入O_CREAT(创建文件)则必须加0666

运行结果为 fd is 3

这意味着open函数成功打开了一个文件或设备,并且操作系统为这次打开操作分配了一个文件描述符3。你可以使用这个文件描述符在后续的操作中引用这个文件或设备,比如进行读写操作。

在Unix/Linux系统中,文件描述符0、1、2分别默认被分配给标准输入(stdin)、标准输出(stdout)和标准错误输出(stderr)。因此,当你通过open函数或类似机制打开一个文件时,得到的文件描述符通常会从3开始(如果在此之前没有打开其他文件或设备)。但是,这个起始值并不是固定的,它取决于在调用open之前系统中已经打开了多少文件或设备。

2.write函数

int fd:文件描述符,表示要写入的文件或设备的标识。
const void *buf:指向要写入数据的缓冲区的指针。
size_t count:指定要写入数据的字节数。

写入数据:write函数会将buf指向的内存区域中的count个字节写入到文件描述符fd指定的文件或设备中。

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

int main()
 {
    int fd = open("example.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) 
    {
        perror("open");
        exit(EXIT_FAILURE);
    }

    const char *message = "Hello, Linux!";
    ssize_t bytes_written = write(fd, message, strlen(message));
    if (bytes_written == -1) 
    {
        perror("write");
        close(fd);
        exit(EXIT_FAILURE);
    }

    printf("Wrote %zd bytes to file.\n", bytes_written);
    close(fd);
    return 0;
}

3.read函数


int fd:文件描述符,表示要从中读取数据的文件、管道或设备的标识。
void *buf:指向缓冲区的指针,该缓冲区用于存储从文件描述符fd读取的数据。
size_t count:指定要读取的最大字节数。

运行结果

类似与ftell

4.lseek函数

fd:文件描述符(file descriptor),一个指向已打开文件的整数标识符。
offset:偏移量,以字节为单位,表示从whence指定的位置开始移动的字节数。这个值可以是正数、负数或零。
whence:指定offset的起始位置,它可以是以下三个值之一:
SEEK_SET:文件的开头。
SEEK_CUR:文件的当前位置。如果offset为正数,则读写位置向文件尾部移动;如果为负数,则向文件头部移动。
SEEK_END:文件的末尾。如果offset为正数,则读写位置从文件末尾开始向后移动;如果为负数,则从文件末尾开始向前移动。

文件定位:当你需要从文件的特定位置读取或写入数据时,可以使用lseek来设置当前文件指针的位置。
文件截断:通过将读写位置设置到文件的末尾并且不写入任何内容,可以实现对文件的截断操作。但请注意,单独的lseek调用并不能实质性地截断文件,通常需要结合write或ftruncate等函数来完成。
文件大小获取:通过将whence设置为SEEK_END并读取返回的偏移量,可以获取文件的大小。

lseek函数可能会因为超出文件大小而失败,所以在使用之前应该确保文件足够大或者使用ftruncate等函数调整文件大小。

如果1.txt文件中为 hello,world 将会变为,helloChina

4.close函数

即可关闭

四,缓冲区

缓冲区(Buffer)在计算机科学中是一个非常重要的概念,它用于存储临时数据,以减少对物理设备(如硬盘、网络等)的直接访问次数,从而提高数据处理效率。以下是关于缓冲区的一些关键点:

1. 定义与作用

定义:缓冲区是一块连续的计算机内存区域,用于存储输入或输出的数据。当数据从一个地方传输到另一个地方时,它首先被放置在缓冲区中,然后再从缓冲区中取出或发送到目标位置。
作用:
减少访问延迟:通过减少对物理设备的直接访问,缓冲区可以减少数据传输的延迟。
提高数据传输效率:由于数据可以批量处理,缓冲区可以提高数据传输的吞吐量。
保护数据完整性:在数据传输过程中,缓冲区可以作为数据的临时存储区域,防止数据丢失或损坏。

2. 缓冲区的类型

缓冲区可以根据其用途和特性分为多种类型,如:

输入缓冲区:用于存储从外部设备(如键盘、鼠标)或文件读取的数据。
输出缓冲区:用于存储待发送到外部设备(如显示器、打印机)或文件的数据。
网络缓冲区:在网络通信中,用于存储发送和接收的数据包。

3. 缓冲区的工作原理

以文件输入输出为例,当程序需要从文件中读取数据时,它首先将数据从文件读取到输入缓冲区中,然后程序从缓冲区中读取数据。同样地,当程序需要向文件写入数据时,它首先将数据写入输出缓冲区中,当缓冲区满或程序主动要求刷新缓冲区时,缓冲区中的数据才会被写入文件。

4. 缓冲区相关函数

在C语言中,有几个与缓冲区相关的函数,如:

setvbuf/setbuf:用于设置文件流的缓冲区类型和大小。
fflush:用于刷新输出缓冲区,即将缓冲区中的数据发送到目标位置(如文件、网络等)。但需要注意的是,并非所有情况下fflush(stdin)都是可移植或有效的,因为标准C并没有规定fflush可以应用于输入流。
rewind:虽然rewind函数的主要作用是将文件指针重新定位到文件的开头,但它也可以间接影响缓冲区。在将文件指针重新定位后,如果文件是以缓冲模式打开的,那么与之关联的缓冲区可能会被清空或重新填充,但这取决于具体的实现和缓冲区状态。

5. 缓冲区溢出的风险

缓冲区溢出是一种常见的安全漏洞,当程序尝试将过多的数据写入固定大小的缓冲区时,就会发生这种情况。如果超出缓冲区的部分覆盖了程序的其他部分(如代码、栈、堆等),就可能导致程序崩溃、数据损坏或执行恶意代码。因此,在编写程序时,需要特别注意避免缓冲区溢出的风险。

总结

缓冲区是计算机内存中用于存储临时数据的区域,它可以减少访问延迟、提高数据传输效率并保护数据完整性。在编程时,需要合理使用缓冲区并注意避免缓冲区溢出的风险。

今天的学习到此,明天见

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值