嵌入式爱好者

嵌入式爱好者 门户 知识库 查看内容

linux下的文件IO操作例程

2024-3-31 12:13| 发布者: Espoir| 查看: 38| 评论: 0

类目:  >  知识库     文档编号: 1359

文件IO操作

1. 文件io通用函数

1. 实例

一个通用的 IO 模型通常包括打开文件、读写文件、关闭文件这些基本操作, 主要涉及到 4 个函数: open()、 read()、 write()以及 close()。

首先来看一个简单的应用例子,源码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

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

      if(argc != 3)
      {
              printf("Usage: %s <target file> <String>\n", argv[1]);
      }

      fd = open(argv[1], O_RDWR | O_CREAT, 0644);
      if(fd < 0)
      {
              printf("open %s failed!\n", argv[1]);
      }

      write(fd, argv[2], strlen(argv[2]));
      write(fd, "\r\n", 2);

      close(fd);
}

编译:

gcc 00_demo.c -o 00_demo

执行:

$./00_demo test.txt helloworld
$ cat test.txt
helloworld

2. 文件描述符

调用 open 函数会有一个int 类型的返回值,在 open函数执行成功的情况下,会返回一个非负整数, 该返回值就是一个文件描述符(file descriptor) ,如果返回值是负数,说明打开文件失败。

3. open/close/read/write函数

首先介绍一下man命令,它可以查看命令或者函数的用法及详细介绍,共包含9种类型如下:

1 Executable programs or shell commands // 命令
2 System calls (functions provided by the kernel) // 系统调用,比如 man 2 open
3 Library calls (functions within program libraries) // 函数库调用
4 Special files (usually found in /dev) // 特殊文件, 比如 man 4 tty
5 File formats and conventions eg /etc/passwd // 文件格式和约定, 比如 man 5 passwd
6 Games // 游戏
7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) /
/杂项
8 System administration commands (usually only for root) // 系统管理命令
9 Kernel routines [Non standard] // 内核例程

以open为例,可以查看open的原型和头文件

OPEN(2)                    Linux Programmer's Manual                   OPEN(2)

NAME
      open, openat, creat - open and possibly create a file

SYNOPSIS
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>

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

其他函数的用法也可以使用man查看。

2. 应用操作excel实例

1. 新建文件

新建一个excel表格,并保存为csv格式,为避免由于编码格式导致的问题,文件内容全部使用ascii字符,如下:

使用notepad++查看文件内容如下:

,Chinese,Math,English,Sum,level
Tom,90,80,88,,
Bob,76,89,90,,
Lucy,84,88,74,,

可以看出,表格内容由逗号分隔,上传至Ubuntu,使用hexdump查看,文件内容如下:

2. 应用处理

接下来写一个应用读取源文件数据,处理后写入新的文件。要求如下:

  • 计算出每个人的总分

  • 总分270分以上为A+,总分240-270为A,总分240以下为B

  • 将计算后的数据写入新的表格

1.实现打开和关闭

我们只需要调用open即可实现对源文件的打开和对目标文件的创建。

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char **argv)
{
      int fd_data, fd_result;

      if(argc != 3)
      {
              printf("Usage: %s <data.csv> <result.csv>\n", argv[0]);
              return -1;
      }

              fd_data = open(argv[1], O_RDONLY);
      if(fd_data < 0)
      {
              printf("open %s failed!\n", argv[1]);
              perror("open");
              return -1;
      }
      else
      {
              printf("data file fd = %d\n", fd_data);
      }

      fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);
      if(fd_result < 0)
      {
              printf("create %s failed!\n", argv[2]);
              perror("create");
              return -1;
      }
      else
      {
              printf("result file fd = %d\n", fd_result);
      }

      close(fd_data);
      close(fd_result);
}

其中有几个点需要提一下:

  • 源文件以只读方式打开,故open的第二个参数为O_RDONLY

  • 目标文件需要可读可写,如果不存在需要创建

  • 当目标文件存在时,由于有O_TRUNC参数,open函数会舍弃原有内容

2. 实现按行读取

read的返回值分为三种类型:

1、如果读取成功,则返回实际读到的字节数。这里又有两种情况:一是如果在读完count要求字节之前已经到达文件的末尾,那么实际返回的字节数将小于count值,但是仍然大于0;二是在读完count要求字节之前,仍然没有到达文件的末尾,这是实际返回的字节数等于要求的count值。

2、如果读取时已经到达文件的末尾,则返回0。

3、如果出错,则返回-1。

判断是否读完一行可以通过读换行符确定,即'\r''\n'

主函数内容如下:

int main(int argc, char **argv)
{
int fd_data, fd_result;
int i, len;
unsigned char data_buf[1000];
unsigned char c;

if(argc != 3)
{
printf("Usage: %s <data.csv> <result.csv>\n", argv[0]);
return -1;
}

fd_data = open(argv[1], O_RDONLY);
if(fd_data < 0)
{
printf("open %s failed!\n", argv[1]);
perror("open");
return -1;
}
else
{
printf("data file fd = %d\n", fd_data);
}

fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);
      if(fd_result < 0)
      {
              printf("create %s failed!\n", argv[2]);
              perror("create");
              return -1;
      }
      else
      {
              printf("result file fd = %d\n", fd_result);
      }

while(1)
{
/*read a line*/
len = read_line(fd_data, data_buf);
if(len == -1)
{
break;
}
if(len != 0)
{
printf("%s\r\n", data_buf);
}
}
close(fd_data);
close(fd_result);
}

read_line函数内容如下:

/* return value: n表示读到了一行数据的数据个数
* -1表示读到文件尾部或出错
*/
static int read_line(int fd, unsigned char *buf)
{
unsigned char Char;
int len;
int i = 0;
int err = 0;
while(1)
{
len = read(fd, &Char, 1);
if(len <= 0)
{
err = -1;
break;
}
else
{
if(Char != '\r' && Char != '\n')
{
buf[i] = Char;
i++;
}
else
{
err = 0;
break;
}
}
}

buf[i] = '\0';
if(err && i == 0)
return -1;
return i;
}

注意,执行需要两个参数;

taylor@ubuntu:~/tmp$ ./demo2 excel.csv result.csv 
data file fd = 3
result file fd = 4
,Chinese,Math,English,Sum,level
Tom,90,94,92,,
Bob,88,89,81,,
Lucy,69,77,74,,

3. 实现处理数据

其中,主函数只需要在读取到一行时对这一行数据进行处理。

int main(int argc, char **argv)
{
int fd_data, fd_result;
int i, len;
unsigned char data_buf[1000];
unsigned char result_buf[1000];
unsigned char c;

if(argc != 3)
{
printf("Usage: %s <data.csv> <result.csv>\n", argv[0]);
return -1;
}

fd_data = open(argv[1], O_RDONLY);
if(fd_data < 0)
{
printf("open %s failed!\n", argv[1]);
perror("open");
return -1;
}
else
{
printf("data file fd = %d\n", fd_data);
}

fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);
      if(fd_result < 0)
      {
              printf("create %s failed!\n", argv[2]);
              perror("create");
              return -1;
      }
      else
      {
              printf("result file fd = %d\n", fd_result);
      }

while(1)
{
/*read a line*/
len = read_line(fd_data, data_buf);
if(len == -1)
{
break;
}
if(len != 0)
{
// printf("%s\r\n", data_buf);
process_data(data_buf, result_buf);
}
}
close(fd_data);
close(fd_result);
}

对于首行和后面的数据,需要用不同的处理方式,从上述文件可以看出,首行的第一个字符是','对应的ascii码为0x2c,因此可以通过判断该行的第一个字符来确定是否为首行。

如果是首行,不需要进行处理,直接拷贝到目标文件;

如果不是首行,则需要进行数据分割和处理;

static void process_data(unsigned char *data_buf, unsigned char *result_buf)
{
unsigned char name[100];
int scores[3];
int sum;
int i;
unsigned char *levels[] = {"A+", "A", "B"};
int level;

if(data_buf[0] == ',')
{
strcpy(result_buf, data_buf);
}
else
{
sscanf(data_buf, "%[^,],%d,%d,%d", name, &scores[0], &scores[1], &scores[2]);
#if 0
printf("%s\n", name);
for(i = 0; i < sizeof(scores) / sizeof(scores[0]); i++)
printf("%d\n", scores[i]);
#endif
sum = scores[0] + scores[1] + scores[2];
if(sum >= 270)
level = 0;
else if(sum >= 270)
level = 1;
else
level = 2;
sprintf(result_buf, "%s,%d,%d,%d,%d,%s", name, scores[0], scores[1], scores[2], sum, levels[level]);
}
printf("result: %s\n", result_buf);
}

编译执行:

taylor@ubuntu:~/tmp$ ./demo3 excel.csv result.csv 
data file fd = 3
result file fd = 4
result: ,Chinese,Math,English,Sum,level
result: Tom,90,94,92,276,A+
result: Bob,88,89,81,258,B
result: Lucy,69,77,74,220,B

4. 写入目标文件

直接在主函数当中调用write写入目标文件即可,因代码简单,不再单独介绍,后面附上完整源码。

write(fd_result, result_buf, strlen(result_buf));
write(fd_result, "\r\n", 2);

编译执行后,目标文件内容如下:

taylor@ubuntu:~/tmp$ cat result.csv 
,Chinese,Math,English,Sum,level
Tom,90,94,92,276,A+
Bob,88,89,81,258,B
Lucy,69,77,74,220,B

使用excel打开:

完整例程源码如下:

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

static int read_line(int fd, unsigned char *buf)
{
unsigned char Char;
int len;
int i = 0;
int err = 0;
while(1)
{
len = read(fd, &Char, 1);
if(len <= 0)
{
err = -1;
break;
}
else
{
if(Char != '\r' && Char != '\n')
{
buf[i] = Char;
i++;
}
else
{
err = 0;
break;
}
}
}

buf[i] = '\0';
if(err && i == 0)
return -1;
return i;
}

static void process_data(unsigned char *data_buf, unsigned char *result_buf)
{
unsigned char name[100];
int scores[3];
int sum;
int i;
unsigned char *levels[] = {"A+", "A", "B"};
int level;

if(data_buf[0] == ',')
{
strcpy(result_buf, data_buf);
}
else
{
sscanf(data_buf, "%[^,],%d,%d,%d", name, &scores[0], &scores[1], &scores[2]);
#if 0
printf("%s\n", name);
for(i = 0; i < sizeof(scores) / sizeof(scores[0]); i++)
printf("%d\n", scores[i]);
#endif
sum = scores[0] + scores[1] + scores[2];
if(sum >= 270)
level = 0;
else if(sum >= 270)
level = 1;
else
level = 2;
sprintf(result_buf, "%s,%d,%d,%d,%d,%s", name, scores[0], scores[1], scores[2], sum, levels[level]);
}
// printf("result: %s\n", result_buf);
}

int main(int argc, char **argv)
{
int fd_data, fd_result;
int i, len;
unsigned char data_buf[1000];
unsigned char result_buf[1000];
unsigned char c;

if(argc != 3)
{
printf("Usage: %s <data.csv> <result.csv>\n", argv[0]);
return -1;
}

fd_data = open(argv[1], O_RDONLY);
if(fd_data < 0)
{
printf("open %s failed!\n", argv[1]);
perror("open");
return -1;
}
else
{
printf("data file fd = %d\n", fd_data);
}

fd_result = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);
      if(fd_result < 0)
      {
              printf("create %s failed!\n", argv[2]);
              perror("create");
              return -1;
      }
      else
      {
              printf("result file fd = %d\n", fd_result);
      }

while(1)
{
/*read a line*/
len = read_line(fd_data, data_buf);
if(len == -1)
{
break;
}
if(len != 0)
{
// printf("%s\r\n", data_buf);
process_data(data_buf, result_buf);
write(fd_result, result_buf, strlen(result_buf));
write(fd_result, "\r\n", 2);
}
}
close(fd_data);
close(fd_result);
}


已解决

未解决

只是看看

最新评论

QQ|小黑屋| 飞凌嵌入式 ( 冀ICP备12004394号-1 )

GMT+8, 2025-6-23 04:22

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

返回顶部