【CS34913】LAB2-文件信息处理

 

第1章 实验基本信息... - 2 -

1.1 实验目的... - 2 -

1.2 实验环境与工具... - 2 -

1.2.1 硬件环境... - 2 -

1.2.2 软件环境... - 2 -

1.2.3 开发工具... - 2 -

第2章 虚拟地址空间... - 3 -

2.1 按要求将linkaddress.c编译链接生成执行程序,按照地址从高到低,列出所有程序符号的地址、名称、存储区、占用空间... - 3 -

第3章 文件信息处理... - 4 -

3.1 基本数据类型的文件读写(20分)... - 4 -

3.1.1文本文件读写(10分)... - 4 -

3.1.2 二进制文件读写(10分)... - 4 -

3.2 结构体数据的二进制文件读写(19分)... - 5 -

3.2.1写操作(10分)... - 5 -

3.2.2读操作(9分)... - 5 -

第4章 补充:UNIX IO

4.1 UNIX IO的优缺点

4.2 使用UNIX IO完成实验

1章 实验基本信息

1.1 实验目的

1.2 实验环境与工具

1.2.1 硬件环境

Intel X86-64、ARM v8鲲鹏920处理器、香橙派/树莓派

1.2.2 软件环境

Ubuntu 18.04 LTS 64以上
(或Windows/MacOS + 虚拟机VirtualBox/Vmware );

1.2.3 开发工具

gcc、g++;vi/vim/gedit

2章 虚拟地址空间

2.1 按要求将linkaddress.c编译链接生成执行程序,按照地址从高到低,列出所有程序符号的地址、名称、存储区、占用空间

首先查看linkaddress.c程序,该程序已提供。

// 编译链接: gcc -Og -no-pie -fno-PIC -fno-omit-frame-pointer -fno-stack-protector -fcf-protection=none -mmanual-endbr -g
// -fno-PIC 共享函数与main在同一段   -fPIC 共享函数在高地址 共享函数区     分别实验看一下
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char big_array[1L<<24];    /*  16 MB */						//.bss
char huge_array[1L<<30];   /*   1 GB */						//.bss
int gint0 =0;									//初值为0,放在.bss节
int global = 0x55aa00ff;							//.data
long glong=0x1122334455667788L;							//.data
char cstr[100]="cstr1234567890abcdefghijklmnopqrstuvwxyz";		//放在.data节 数据段,可更改
char *pstr="rstr1234567890abcdefghijklmnopqrstuvwxyz";			//放在.rodata节 代码段 不能修改,否则出现段错误
const int gc=0x8899aabb;						//.rodata
const char cc[100]="Hello!\n";						//.rodata

int useless() { return 0; }						//.text
static void show_pointer(void *p, char *descr) {			//.text
    //    printf("Pointer for %s at %p\n", descr, p);
    printf("%s\t%p\t%lu\n", descr, p, (unsigned long) p);
}

int main (int argc,char *argv[])					//.text
{
    char **env = __environ;    //环境变量__environ
    void *p1, *p2, *p3, *p4,*p5;					//heap 或 共享heap
    int li0 = 0;
    int li1 = 1;
    static int lsi0=0;							//.bss
    static int lsi1=1;							//.data
    char lc[1001]="9876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210";
    char *ls="1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF";

    if(argc!=4)
    {
        printf("Usage: LinkAddress P1 P2 P3\n");
        return 1;
    }
    useless();
   //打印系统变量信息
    show_pointer((void *) env, "env");
    int i=0;
    while(*env)
    {
        printf("env[%d]\t",i);
        show_pointer((void *) (*env), "*env");
        puts(*env);
        env++;   i++;
    }

    p1 = malloc(1L << 28);
    p2 = malloc(1L << 17);
    p3 = malloc( (1L << 17) +1);
    p4 = malloc(1L << 30);
    p5 = malloc(1L << 31);

    show_pointer((void *) big_array, "big array");
    show_pointer((void *) huge_array, "huge array");
    show_pointer((void *) &global, "global");
    show_pointer((void *) &gint0, "gint0");
    show_pointer((void *) &glong, "glong");
    cstr[0]='C';
    show_pointer((void *) cstr, "cstr");
//    pstr[0]='R';                          //rodata节在text代码段,不能修改
    show_pointer((void *) pstr, "pstr");
    show_pointer((void *) &gc, "gc");
    show_pointer((void *) cc, "cc");
    show_pointer((void *) &li0, "local int 0");
    show_pointer((void *) &li1, "local int 1");
    show_pointer((void *) &lsi0, "local static int 0");
    show_pointer((void *) &lsi1, "local static int 1");
    show_pointer((void *) lc, "local astr");
    show_pointer((void *) ls, "local pstr");

    show_pointer((void *) &argc, "argc");
    show_pointer((void *) argv, "argv");
    printf("argv[0] %16lx\n",(unsigned long) (*argv));
    printf("argv[1] %16lx\n",(unsigned long) (*(argv+1)));    //argv[1]  argv 指针+1 就是argv地址+8
    printf("argv[2] %16lx\n",(unsigned long) (*(argv+2)));
    printf("argv[3] %16lx\n",(unsigned long) (*(argv+3)));
    show_pointer((void *) argv[0], "argv[0]");
    printf("%s\n",argv[0]);
    show_pointer((void *) argv[1], "argv[1]");
    printf("%s\n",argv[1]);
    show_pointer((void *) argv[2], "argv[2]");
    printf("%s\n",argv[2]);
    show_pointer((void *) argv[3], "argv[3]");
    printf("%s\n",argv[3]);
    show_pointer((void *) p1, "p1");
    show_pointer((void *) p2, "p2");
    show_pointer((void *) p3, "p3");
    show_pointer((void *) p4, "p4");
    show_pointer((void *) p5, "p5");

    show_pointer((void *) show_pointer, "show_pointer");
    show_pointer((void *) useless, "useless");
    show_pointer((void *) main, "main");
    show_pointer((void *) exit, "exit");
    show_pointer((void *) printf, "printf");
    show_pointer((void *) malloc, "malloc");
    show_pointer((void *) free, "free");
    free(p1);      free(p2);       free(p3);	    free(p4);         free(p5);
    show_pointer((void *) strcpy, "strcpy");
    return 0;
}

编译命令

~$  gcc -Og -no-pie -fno-PIC -fno-omit-frame-pointer -fno-stack-protector -fcf-protection=none -mmanual-endbr –g
linkaddress.c –o linkadress

 命令行还需输入运行参数

~$ ./linkaddress <long int> <string> <long int>

这个实验主要要掌握的是,在一个c程序中,链接后生成的执行程序各语言要素(变量、参数、常量、函数等)在虚拟地址空间的分布 。

参考以上内容,可以总结,在链接过程中

代码段.txt/.rodata:可执行程序的机器代码、常量const、字符串常量。这个段是只读的。

数据段.data:数据段包括了初始化的全局变量和静态变量。这些变量在程序运行期间可以被修改。数据段通常位于代码段之后,它的地址也是可执行程序加载时确定的。

BSS段.bss:未初始化的全局变量和静态变量,它们在程序加载时被初始化为零。BSS段也位于数据段之后,它的大小在可执行程序中是固定的,但它不占用实际的磁盘空间。

堆(Heap):堆是用于动态分配内存的区域,它通常位于数据段和共享库之间的空间。堆的大小可以动态地增长和收缩,由C库函数(如malloc和free)管理。堆的起始地址通常由操作系统在程序运行时决定。

栈(Stack):栈用于存储函数的局部变量、函数的返回地址以及函数调用的上下文信息。栈通常位于虚拟地址空间的高地址部分,向低地址方向增长。栈的大小在程序运行时是动态管理的,当函数被调用时,会在栈上分配一些空间,当函数返回时,这些空间会被释放。

共享库(Shared Libraries):共享库包含了可执行程序所需的共享代码和数据,这些库通常被多个进程共享,以减少内存占用和提高效率。共享库的地址通常也由操作系统管理和加载。

第3章 文件信息处理

3.1 基本数据类型的文件读写

3.1.1文本文件读写

从文本文件读入数据,文件中每行保存着一个数据记录,包括编号id(纯数字)、姓名name、3个课程分数的数值(浮点型,0~100)、1个体重(整型),各数值之间有空格分开。将读入到内存的数据,输出到文本文件,格式同前。

读写操作

相关函数代码与说明:

#include <stdio.h>
#include <stdlib.h>
#include "fileop.h"


int main() {
    FILE *file = fopen("testfile.txt", "r"); 
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }
    FILE *fp = fopen("test_write.txt", "w");
    if (fp == NULL) {
        perror("无法打开文件");
        return 1;
    }
    fileop(file,fp);
    fclose(file);
    fclose(fp);
    return 0;
}

讲解一下思路。首先定义一个结构体存储信息,接着从传入的文件中读取一行数据,当没有读到文件末尾时进行循环,使用sscanf 判断对应输入是否合法,是则打印到屏幕上,再使用fprintf写入文件。

//input:file:pointer of input txt;fp:pointer of output txt
//output:逐项格式化输出,write in fp
void fileop(FILE *file,FILE *fp)
{
	// 定义结构体来存储每个数据记录
    struct Record {
    int id;
    char name[50];
    float scores[3];
    int weight;
    };
    struct Record record; // 存储每行数据记录的结构体
    char line[256]; // 用于存储读取的每行数据

    while (fgets(line, sizeof(line), file) != NULL) 
    {
        if (sscanf(line, "%d %49s %f %f %f %d", &record.id, record.name,
                   &record.scores[0], &record.scores[1], &record.scores[2], &record.weight) == 6) {
            printf("%d, %s, %.1f, %.1f, %.1f, %d\n", record.id, record.name,
                   record.scores[0], record.scores[1], record.scores[2],record.weight);
           fprintf(fp, "%d, %s, %.1f, %.1f, %.1f, %d\n", record.id,
                record.name, record.scores[0],
                record.scores[1], record.scores[2], record.weight);
          
        }
    }
    
}

 用到的文件操作函数

FILE* fopen(<filename>,r/w)

其中r/w表示对文件是只读还是读写,其返回值是指向该文件的指针。在调用该函数后一般需要检查文件打开是否成功,即检查指针是否为空。注意文件要在当前工作区内。

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

其中str是待存储区域的指针,stream是一个数据流,fgets函数将数据流中的内容写入到s中,但写入有限制,最多写size-1个就停止,此时在文件结尾写入结束符\0。成功读取时返回str,否则返回null,所以使用fgets时也要检查返回值。

fgets函数及其用法,C语言fgets函数详解-CSDN博客

int sscanf(const char *str, const char *format, ...);

sscanf比scanf多出的就是指定了要解析度字符串str,后面跟随其格式化形式,以及存储到什么变量里面去。其返回值是成功解析的参数数量。

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

和sscanf类似,将后续的参数按照指定的格式写入到指定的输出流stream中。返回值是成功写入的字符数,即成功写入到输出流中的字符数,如果写入失败,则返回一个负数作为错误标志。

3.1.2 二进制文件读写

(1)写操作

将1个100个元素的浮点数组、1个100个字符的字符数组分别写入到二进制文件、文本文件(共四个文件),比较文本/二进制文件的大小、内容的差异。

相关函数代码与说明:

使用时间为种子生成随机数初始化两个数组,然后分别写到二进制文件和文本文件中,写入二进制文件使用fwrite函数,写入文本文件使用fprintf函数,最后别忘了关闭四个文件

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

int main() 
{
    srand(time(NULL));
    float farr[100];
    for (int i = 0; i<100; i++) 
    {
        farr[i] = ((float)rand() / RAND_MAX) * 100.0;
    }
    char carr[100];
    for (int i = 0; i<100; i++) 
    {
        carr[i] = 'Y' + rand() % 26;
    }
    FILE *file1 = fopen("bin_float.bin", "wb");//wb表示二进制写
    FILE *file2 = fopen("bin_char.bin", "wb");
    if (file1 == NULL || file2 == NULL)
    {
        perror("无法打开二进制文件");
        return 1;
    }

    fwrite(farr, sizeof(float), 100, file1);
    fwrite(carr, sizeof(char), 100, file2);

    fclose(file1);
    fclose(file2);

    // 写入文本文件
    FILE *file3 = fopen("text_float.txt", "w");
    FILE *file4 = fopen("text_char.txt", "w");
    if (file3 == NULL || file4 == NULL) 
    {
        perror("无法打开文本文件");
        return 1;
    }

    for (int i = 0; i < 100; i++) 
    {
        fprintf(file3, "%.2f\n", farr[i]);
        fprintf(file4, "%c\n", carr[i]);
    }

    fclose(file3);
    fclose(file4);

    printf("wirte success!\n");

    return 0;
}

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

ptr是指向待写入数据的区域的指针,size是每个写入数据的大小,可以通过sizeof获取,count是写入数据的个数,stream是被写入的文件指针。返回成功写入的数据项数量,如果写入失败或出现错误,则返回一个小于 count 的值。可以使用 ferror 函数来检查是否发生了错误,以及使用 feof 函数检查是否到达了文件的末尾。

【C 语言】文件操作 ( fwrite 函数 )_韩曙亮的博客-CSDN博客

两个结果文件的差异、你的经验体会:

①同一文件类型和数据量,浮点数文件大于字符文件,这可能是因为浮点数占用的位数更多

②同一数据量,二进制文件小于文本文件,这可能是因为二进制编码更高效

③心得:保存较大的文件时,可以尝试着保存为二进制文件减小占用

(2)读操作

从二进制文件读入100个浮点数值。

相关函数代码与说明:使用fopen函数打开文件得到文件指针。使用fread函数读取二进制文件并拷贝到farr数组中,最后打印出来

#include <stdio.h>

int main() 
{
    FILE *file = fopen("bin_float.bin", "rb"); // "rb" 表示以二进制读取方式打开文件

    if (file == NULL)
    {
        perror("无法打开二进制文件");
        return 1;
    }
    float farr[100]; 
    //size_t size = sizeof(floatArray) / sizeof(floatArray[0]);
    fread(farr, sizeof(float), 100, file);

    // 读取字符数组(字符串)
    //char charArray[256]; // 假设字符数组最大长度为256
   // fread(charArray, sizeof(char), sizeof(charArray), file);

    // 关闭文件
    fclose(file);

    // 打印读取的数据
    for (size_t i = 0; i < 100; i++) 
    {
        printf("%.2f\n ", farr[i]);
    }

    //printf("字符数组(字符串):%s\n", charArray);

    return 0;
}

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

ptr是指向被写入数据的区域的指针,size是每个写入数据的大小,可以通过sizeof获取,count是写入数据的个数,stream是待写入的文件指针。返回成功写入的数据项数量,如果写入失败或出现错误,则返回一个小于 count 的值。

【C 语言】文件操作 ( fread 函数 )_fread循环读取一个文件-CSDN博客

3.2 结构体数据的二进制文件读写

3.2.1写操作

将结构体数组写入二进制文件。

相关函数代码与说明:

#include <stdio.h>
#include <string.h>
struct Person {
    char name[50];
    int age;
    float height;
};
int main() {
    struct Person people[3] = {
        {"Alice", 25, 160.5},
        {"Bob", 30, 175.0},
        {"Charlie", 22, 180.2}
    };

    // 打开用于写入数据的二进制文件,如果不存在则创建
    FILE *file = fopen("struct_bin_testfile.bin", "wb"); // "wb" 表示以二进制写入方式打开文件

    if (file == NULL) {
        perror("无法打开二进制文件");
        return 1;
    }

    // 将结构体数组写入文件
    fwrite(people, sizeof(struct Person), 3, file);

    // 关闭文件
    fclose(file);

    printf("数据已写入二进制文件。\n");

    // 修改第一个结构体的数据
    strcpy(people[0].name, "Alice Updated");
    people[0].age = 26;
    people[0].height = 161.0;

    // 打开文件以追加方式写入数据
    file = fopen("people.bin", "ab"); // "ab" 表示以二进制追加方式打开文件

    if (file == NULL) {
        perror("无法打开二进制文件");
        return 1;
    }

    // 将修改后的结构体写入文件的指定位置(这里写入第一个结构体的位置)
    fseek(file, sizeof(struct Person) * 0, SEEK_SET);
    fwrite(&people[0], sizeof(struct Person), 1, file);

    // 关闭文件
    fclose(file);

    printf("第一个结构体已修改并重新写入二进制文件。\n");

    return 0;
}

3.2.2读操作

从二进制文件读入结构体数组,数组长度未知。

相关函数代码与说明:在数组长度未知时,可以申请动态空间存储。本例中假设开始数组个数为10,在检测到多于十个时,将数组长度扩充至2倍,更新结构体数组指针,直至读取完毕(检查fread返回值实现)。读取后打印二进制文本,结果正确。最后要记得关闭文件和释放动态内存

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

typedef struct Person
{
    char name[50];
    int age;
    float height;
} PERSON;

int main()
{
    FILE *file = fopen("struct_bin_testfile.bin", "rb"); // "rb" 表示以二进制读取方式打开文件

    if (file == NULL)
    {
        perror("无法打开二进制文件");
        return 1;
    }
    size_t size = 10;
    PERSON *person = (PERSON *)malloc(sizeof(PERSON) * size);
    // 动态申请内存来存储结构体数据
    if (person == NULL)
    {
        perror("无法分配内存");
        return 1;
    }
    size_t number = 0; // 数量
    while (fread(&person[number], sizeof(PERSON), 1, file) == 1) // 使用 fread 从文件中读取数据并将其存储在动态分配的内存中
    {
        number++;
        // 检查数组是否需要扩展
        if (number >= size)
        {
            size = 2 * size;
            PERSON *temp = (PERSON *)realloc(person, size * sizeof(PERSON));
            if (temp == NULL)
            {
                perror("内存分配失败");
                fclose(file);
                free(person);
                exit(EXIT_FAILURE);
            }
            person = temp;
        }
    }
    fclose(file);

    for (size_t i = 0; i < number; i++)
    {
        printf("name: %s ,age: %d, height:%.2f \n", person[i].name, person[i].age, person[i].height);
    }

    free(person);

    return 0;
}

4章 UNIX IO 

4.1 UNIX IO的优缺点

    • 优点
          Unix I/O 是最通用、开销最低的I/O方式
          所有其他 I/O都是使用Unix I/O 函数来实现的
          Unix I/O 提供访问文件元数据的函数
          Unix I/O 函数是异步信号安全的,可以在信号处理程序中安全地使用
      缺点
          处理不足值时容易出错
          有效地读取文本行需要某种形式的缓冲, 容易出错
          这两个问题都是由标准I/O和RIO包来解决
      

对比:标准IO

优点:
    通过减少读和写系统调用的次数,有效增加内存
    自动处理不足值
缺点:
    没有提供访问文件元数据的函数
    标准 I/O 函数不是异步信号安全的, 不适合用于信号处理
    标准 I/O 不适合网络套接字的输入输出操作
    对流的限制和对套接字的限制有时候会互相冲突,而又很少有文档描述这些现象

4.2 使用UNIX IO 完成实验

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "test.h"
int main(int argc, char *argv[]) {
    if (argc != 4) {
        printf("input wrong!");
        return 1;
    }//there are numbers of input on screen in argc

    int operation = atoi(argv[1]);//sring to number
    const char *inputFileName = argv[2];
    const char *outputFileName = argv[3];

    if (operation == 1) {
        textToScreenAndBinary(inputFileName, outputFileName);
    } else if (operation == 2) {
        binaryToScreenAndText(inputFileName, outputFileName);
    } else {
        printf("wrong operation! input '1' for text to  binary or '2' for binary to text.\n");
        return 1;
    }

    return 0;
}

main函数主要完成:读取命令行参数,检验合法性,并调用对应的函数

其中,atoi函数可以将命令行的字符串数字转为整型变量

// defination of struct
typedef struct myrecord 
{
    unsigned long id;
    char name[32];
    float score[4];
}record;
//input:2 file pointer
//output:null
//fuction:make text print to screen and change into bin
void textToScreenAndBinary(const char *inputFileName, const char *outputFileName)
{
    int inputFile = open(inputFileName, O_RDONLY);//0_RDONLY means read only
    if (inputFile == -1)
    {
        perror("Error opening input text file");
        exit(1);
    }
    int outputFile = open(outputFileName,O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);//open bin file
    if(outputFile == -1)
    {
      perror("Error opening output bin file\n");
      exit(1);
    }
    // 计算行数
    off_t len = lseek(inputFile,0,SEEK_END);//get length of txt
    char* buf = malloc (len+1);
    lseek(inputFile,0,SEEK_SET);//reset seek in 0
    size_t st=read(inputFile,(void *)buf,len);//read txt in buf
    if(st == -1)
    {
	perror("read fail!\n");
	exit(1);
    }
    int num=0;//get the number of'\n'
    for(int i=0;i<len;i++)
    {
        if(buf[i]=='\n') num++;
    }
record *stu = (record*)malloc(sizeof(record)*(num+1));//malloc space for struct
    char temp[128];int j=0,k=0;
    for(int i=0;i<len&&(k<(num-1));i++)
    {
        if(buf[i]=='\n')//test '/n'
        {
            memcpy(temp,buf+j,i-j+1);//copy one line
            sscanf(temp, "%lu %31s %f %f %f %f", &stu[k].id, stu[k].name, &stu[k].score[0], &stu[k].score[1], &stu[k].score[2], &stu[k].score[3]);//transport num from temp to struct
            printf(" %lu  %s  %.1f %.1f %.1f %.1f\n", stu[k].id, stu[k].name, stu[k].score[0], stu[k].score[1], stu[k].score[2], stu[k].score[3]);//print 
            j=i+1;
            k++;
        }
    }
  if(write(outputFile,stu,sizeof(record)*(num-1))<0)//write
    {
        perror("write fail!\n");
        exit(1);
    }
    close(outputFile);
    close(inputFile);
    free(buf);
    free(stu);//close file and free memery 
}



//input:2 file pointers
//output:null
//function:bin file print to screen and change to struct txt
void binaryToScreenAndText(const char *inputFileName, const char *outputFileName) {
    int inputFile = open(inputFileName, O_RDONLY);//read only
    if (inputFile == -1) {
        perror("Error opening input binary file");
        exit(1);
    }
    int outputFile = open(outputFileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
    if (outputFile == -1) 
    {
        perror("Error opening output text file");
        close(inputFile);
        exit(1);
    }

    struct myrecord record;

    while (1) {
        ssize_t bytesRead = read(inputFile, &record, sizeof(struct myrecord));//bytesread means the return number of read function
        if (bytesRead == 0) {
            break; // 文件读取结束
        } else if (bytesRead == -1) //read wrong
        {
            perror("Error reading input binary file");
            close(inputFile);
            close(outputFile);
            exit(1);
        }

        printf("%lu, %s, %.2f, %.2f, %.2f, %.2f\n", record.id, record.name, record.score[0], record.score[1], record.score[2], record.score[3]);

        char line[128];
        snprintf(line, sizeof(line), "%lu %s %.2f %.2f %.2f %.2f\n", record.id, record.name, record.score[0], record.score[1], record.score[2], record.score[3]);//sizeof(line) limit the length of write,avioding overflow

        if (write(outputFile, line, strlen(line)) == -1)//write wrong
        {
            perror("Error writing output text file");
            close(inputFile);
            close(outputFile);
            exit(1);
        }
    }

    close(inputFile);
    close(outputFile);
}

open()是一个常用的C语言标准库函数,用于打开文件并返回一个文件描述符。 

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

其返回值是一个指示文件的整型变量,负数表示打开失败。
参数说明:
pathname表示文件路径。
flags标志位,表示一系列对文件操作的权限,如O_RDONLY表示只读,O_WRONLY表示只写, O_CREAT表示没有该文件时创建, O_TRUNC表示如果文件已经存在,那么在打开文件时将截断(清空)文件内容,即将文件的大小截断为零字节, S_IRUSR表示文件的所有者有读取权限,S_IWUSR表示用户具有对文件或目录的写权限。

Linux 文件IO学习之open函数深入了解_linux open函数_catfish coffee的博客-CSDN博客

off_t len = lseek(inputFile,0,SEEK_END)

这段代码用来获取文件的大小。off_t是一个用于文件大小偏移的类型,它是一个有符号整数类型。

lseek函数原型如下

off_t lseek(int fildes, off_t offset, int whence);

fildes指示文件,offset表示偏移开头的字符数,置为0则是从文件起始读取。whence表示读到哪,SEEK_END表示读到文件结尾。返回读取的字符数。

注意到这行代码

lseek(inputFile,0,SEEK_SET);//reset seek in 0

为什么要求文件描述符回到文件开头呢?这和read函数的定义有关。

ssize_t read(int fd, void *buf, size_t count);

参数说明:

fd:一个打开的文件描述符。
buf:指向一个缓冲区的指针,用于存储读取到的数据。
count:要读取的字节数。
返回值是实际读取到的字节数,如果文件已经到达结尾,则返回0,如果出现错误,则返回-1。

memcpy()是一个C语言标准库函数,用于从源内存区域复制n个字节到目标内存区域。

void *memcpy(void *dest, const void *src, size_t n);

memcpy()函数会返回一个指向目标内存区域的指针。

参数说明:

dest:目标内存区域的指针。

src:源内存区域的指针。

n:要复制的字节数。

write()是一个Unix系统调用,用于向打开的文件描述符写入数据。

ssize_t write(int fd, const void *buf, size_t count);

参数说明:

fd:一个打开的文件描述符。
buf:指向一个缓冲区的指针,其中包含了要写入的数据。
count:要写入的字节数。
返回值是实际写入的字节数,如果出现错误,则返回-1。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值